pythonpipsetup.pytwine

How to package my python project to be runnable from command line?


I've coded my python project and have succeeded in publishing it to test pypi. However, now I can't figure out how to correctly configure it as a console script. Upon running my_project on the command line, I get the following stack trace:

Traceback (most recent call last):
  File "/home/thatcoolcoder/.local/bin/my_project", line 5, in <module>
    from my_project.__main__ import main
ModuleNotFoundError: No module named 'my_project'

Clearly, it's created a script to run but the script is then failing to import my actual code.

Folder structure:

pyproject.toml
setup.cfg
my_project
├── __init__.py (empty)
├── __main__.py

Relevant sections of setup.cfg:

[metadata]
name = my-project
version = 1.0.5

...

[options]
package_dir =
    = my_project
packages = find:

...

[options.packages.find]
where = my_project

[options.entry_points]
console_scripts =
    my_project = my_project.__main__:main

pyproject.toml (probably not relevant)

[build-system]
requires = [
    "setuptools>=42",
    "wheel"
]

__main__.py:

from my_project import foo

def main():
    foo.bar()

if __name__ == '__main__':
    main()

To build and upload, I'm running the following: (python is python 3.10)

python -m build
python -m twine upload --repository testpypi dist/*

Then to install and run:

pip install -i https://test.pypi.org/pypi/ --extra-index-url https://pypi.org/simple my-project --upgrade

my_project

How can I make this console script work?

Also, this current method of setting console_scripts only allows it to be run as my_project; is it possible to also make it work by python -m my_project? Or perhaps this will work once my main issue is fixed.


Solution

  • I finally got back to this problem today and it appears that I was using an incorrect source layout, which caused the pip module installation to not work. I switched to a directory structure like this one:

    ├── src
    │   └── mypackage
    │       ├── __init__.py
    │       └── mod1.py
    ├── setup.py
    └── setup.cfg
    

    and modified the relevant parts of my setup.cfg:

    [options]
    package_dir=
        =src
    packages=find:
    
    [options.packages.find]
    where=src
    

    Then I can run it like python -m mypackage. This also made the console scripts work. It works on Linux but I presume it also works on other systems.