Bjorn121
Bjorn121

Reputation: 665

setuptools does not include any subpackages I specify

I'm trying to create an installer for a CLI tool I'm developing with Click. The problem is that for some reason submodules aren't included in the installer, which results in the following error:

from modules.commands import modules
ModuleNotFoundError: No module named 'modules'

This is my directory structure:

.
├── LICENSE
├── README.md
├── setup.py
├── src
│   ├── app_config
│   │   ├── __init__.py
│   │   └── configuration.py
│   └── commands
│       ├── __init__.py
│       ├── config
│       │   ├── __init__.py
│       │   └── commands.py
│       ├── modules
│       │   ├── __init__.py
│       │   └── commands.py
│       └── cli.py
└── tests

cli.py references commands created in config and modules. When I'm running cli.py directly, it works fine. However, no matter what pattern I try for setup.py to include packages, the submodules in commands are not included.

This is the code for setup.py:

setup(
    name='cli',
    version='0.1.0',
    packages=find_packages(include=['src', 'src.*']),
    install_requires=[
        'Click'
    ],
    entry_points={
        'console_scripts': [
            'cli = src.commands.cli:cli'
        ]
    }
)

I've checked the find_packages-implementation, but I can't see anything wrong with the way I've specified what is written above. I've also tried hardcoding all packages, but that didn't work either. I've also tried with src/*, as maybe it uses full filepaths, but that didn't work either.

Edit: More Troubleshooting

Thanks to this question, I tried running python -c "from setuptools import setup, find_packages; print(find_packages('src'))". According to the output, it finds all the submodules:

['app_config', 'commands', 'commands.config', 'commands.modules']

However, when I update my setup to include the same value, it fails.

setup.py:

setup(
    name='cli',
    version='0.1.0',
    packages=find_packages('src'),
    install_requires=[
        'Click'
    ],
    entry_points={
        'console_scripts': [
            'cli = src.commands.cli:cli'
        ]
    }
)

Output:


  error: subprocess-exited-with-error
  
  × python setup.py egg_info did not run successfully.
  │ exit code: 1
...
      error: package directory 'app_config' does not exist
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.

Upvotes: 2

Views: 3465

Answers (2)

Neon22
Neon22

Reputation: 630

I had exact same problem. Your question helped me find the answer from here:

I added graft src to my manifest.in I changed (in setup.cfg under [options]) packages = find: to packages = find_namespace:

Before I added graft I was super confused. Then it could find my subpackage under my main in src

Upvotes: 2

cizario
cizario

Reputation: 4269

you are probably missing MANIFEST.in file:

# https://packaging.python.org/guides/using-manifest-in/
graft src
global-exclude __pycache__
global-exclude *.py[cod]

and since you rely on setuptools as tool to build and distribute your package, it's recommended to adopt the last best practises, src layout (the case) and move the config to pyproject.toml and setup.cfg files:

pyproject.toml

[build-system]
# https://setuptools.readthedocs.io/en/latest/setuptools.html#setup-cfg-only-projects
requires = [
  "setuptools >= 40.9.0",
  "wheel"
]
build-backend = "setuptools.build_meta"

setup.py (optional)

from setuptools import setup

setup()

setup.cfg

# https://setuptools.readthedocs.io/en/latest/userguide/declarative_config.html
[metadata]
name = [..]
version = [..]
description = [..]
long_description = file: README.rst
long_description_content_type = text/x-rst
author = [..]
author_email = [..]
# maintainer =
# maintainer_email =
license = [..]
license_file = LICENSE
# license_files =
url = [..]
download_url = [..]
project_urls =
    Documentation = [..]
    Issue Tracker = [..]
    Source Code = [..]
keywords = [..]
sclassifiers =
    [..]
platforms = any

[options]
python_requires = >=3.6
install_requires =
    Click
packages = find_namespace:
package_dir =
    = src
include_package_data = True
zip_safe = False

[options.packages.find]
where = src

[options.entry_points]
console_scripts =
    cli = commands.cli:cli  # Update: change `src.commands.cli:cli` to
                            # `commands.cli:cli` as per the comment below

[options.extras_require]
    [..]

if you are on windows and you want to build and publish your package

pip install build wheel twine
py -m build -n  # don't forget '-n' flage to force using your project venv
pip install -e .  # for editable mode 

# then, if everything is ok then pulish it on pypi
py -m twine upload dist/*

Upvotes: 2

Related Questions