简体   繁体   中英

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?

Your setup call looks like this:

setup(
  name="smux.py",
  version='0.1.1',
  scripts=['smux.py'],
  author="Henry Qin",
  author_email="root@hq6.me",
  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 .

The other answer is the more kosher and modern one, and I would use that and name the script smux if I did not have legacy scripts depending on the name smux.py . Unfortunately, others have wrapped smux.py and it would be unkind to break their scripts.

Here is what I did to avoid the circular dependency problem that arises from having a legacy script name that ends in .py and conflicts with the module naming.

I ended up modifying the setup call to have both of the following.

  py_modules=['smux'],
  scripts=['smux.py']

My experiments demonstrate that this has the desired effect of making the module importable while preserving a working script under the name smux.py .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM