Search code examples
pythonsetuptoolssetup.pypypi

How do I force setup.py to include the `__init__.py` file and make my package importable?


I am trying to make my Python project importable by people who install it using pip. Although it contains a __init__.py and works as a package locally, it seems that I am misunderstanding how setuptools works.

I run the following three commands to upload the package.

python3 setup.py sdist bdist_wheel
python3 -m pip install  --upgrade twine
python3 -m twine upload dist/*

Then on a different machine, I run pip3 install smux.py. The result is that I can access smux.py as a command, but I get an import error when trying to import it.

python3
Python 3.8.5 (default, Jul 28 2020, 12:59:40) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import smux
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'smux'

After running the setup.py commands above, I examined smux.py.egg-info/SOURCES.txt in the current directory and find it contains the following:

README.md
setup.py
smux.py
smux.py.egg-info/PKG-INFO
smux.py.egg-info/SOURCES.txt
smux.py.egg-info/dependency_links.txt
smux.py.egg-info/top_level.txt

The file __init__.py is missing.

How do I either get that file into the package, or modify the setup call to make smux importable?


Solution

  • Your setup call looks like this:

    setup(
      name="smux.py",
      version='0.1.1',
      scripts=['smux.py'],
      author="Henry Qin",
      author_email="[email protected]",
      description="Simple tmux launcher that will take less than 2 minutes to learn and should work across all versions of tmux",
      long_description=long_description,
      platforms=["All platforms that tmux runs on."],
      license="MIT",
      url="https://github.com/hq6/smux"
    )
    

    With the scripts argument, you've told setuptools that smux.py is a script, not a module. Accordingly, it gets installed as a script, not a module.

    Your code does not need an __init__.py and should not have one. Having an __init__.py will not help. You need to tell setuptools to install your file as a module rather than a script, and register an entry point separately, with a console_scripts entry in the entry_points argument:

    setup(
        ...
        # no scripts= line
        py_modules=['smux'],
        entry_points={
            'console_scripts': ['smux=smux:main']
        }
    )
    

    Then when your code is installed, smux will be importable, and there will be a smux script available from the command line that calls smux.main.