1

My project have the following structure:

project/
  + setup.py
  + bobafett/
    + __init__.py
    + __main__.py
    + foo.py

With:

  • __init__.py: an empty file
  • foo.py: contains the definition of bar:
def bar():
    print("foo.bar()")
  • __main__.py import and use foo.bar:
import foo
foo.bar()

✓ Locally, all works well:

~/project $ python3 bobafett/__main__.py
foo.bar()

✗ Once bobafett is packaged, published and installed, foo is no longer found

~/project $ python3 setup.py bdist_wheel
~/project $ curl -T ... https://my-pypi.example.com/simple/bobafett/...
~/project $ cd /tmp
/tmp $ pip --index-url https://my-pypi.example.com/simple --user bobafett
/tmp $ python -m bobafett
...
  File "/home/ysc/.local/lib/python3.6/site-packages/bobafett/__main__.py", line 1, in <module>
    import foo
ModuleNotFoundError: No module named 'foo'

How is that? What can I write instead of import foo that both works locally and once deployed? Do I need to change my project structure?


setup.py:

from setuptools import setup

setup(
    name='bobafett',
    version='1.0.0',
    author='YSC',
    author_email='ysc@example.com',
    packages=['bobafett'],
    url='https:///my-pypi.example.com/simple/bobafett/',
    description='Prints "foo.bar()".',
)
YSC
  • 38,212
  • 9
  • 96
  • 149

1 Answers1

1

You can do the following:

  1. change import foo to from . import foo. It will fix running python -m bobafett but break python3 bobafett/__main__.py.
  2. run locally the same way as when packaged: python -m bobafett instead of python3 bobafett/__main__.py.
sanyassh
  • 8,100
  • 13
  • 36
  • 70
  • It works indeed :) If you happen to know why and explain it, I could accept your answer. If not, I'll wait a bit to allow others to answer. – YSC Oct 11 '19 at 14:03
  • 1
    @YSC I am not 100% sure, but combining these two answers: https://stackoverflow.com/a/4383597/9609843 and https://stackoverflow.com/a/11537218/9609843 gives the following: running `python3 bobafett/__main__.py` allows Python to find `foo` with `import foo` because it searches `the directory that the entry-point script is running from`. But when running from `/tmp` Python cant do it. Thus we change to `from . import foo`. After that `When you execute a file directly, it doesn't have its usual name, but has "__main__" as its name instead. So relative imports don't work.` So change to `python -m` – sanyassh Oct 11 '19 at 14:38