I wrote a Python 3 console-application which has the same structure as the example below. I want to know how I should be importing the modules in order to achieve the behavior specified in the desired functionality section.
/foo
|-/foo
| |-__init__.py
| |-/bar
| | |-__init__.py
| | |-eggs.py
| |-ham.py
| |-spam.py
|-setup.py
Where:
- The
spammodule has themainfunction - The
spammodule imports the Ham class in thehammodule - The
hammodule imports the Egg class in theeggsmodule - Both
__init__.pyfiles are empty - Basic
setup.pyfile that importssetuptools
Desired Functionality
I want to be able to upload the console app to PyPi. Then it can be downloaded as a package with
pip, and be executed in the terminal.~/>> fooI also want to be able to run it as a Python script.
~/foo>> python3 foo/spam.py
I found, what I think is a hacky, way to achieve this.
The (hacky) Solution
In order to get the installed package and Python script functionality, I added a try: ... except: ... which works but it doesn't seem the right way to do this.
try:
from module import Class # import will work for running as script
except:
# relative import will work for running as a package installed with pip
from .module import Class
If I only leave the relative import, and try to run the code as a Python script, I get:
Traceback (most recent call last):
File "foo/spam.py", line 6, in <module>
from .ham import Ham
ModuleNotFoundError: No module named '__main__.ham'; '__main__' is not a package
A similar situation occurs if I leave the regular import and run console application:
Traceback (most recent call last):
File ".../foo/spam.py", line 6, in <module>
from ham import Ham
ModuleNotFoundError: No module named 'ham'
The Files
__init__.py files are empty
spam.py
"""spam module"""
try:
from ham import Ham
except:
from .ham import Ham
def main():
pass
if __name__ == "__main__:
main()
ham.py
"""ham module"""
try:
from eggs import Egg
except:
from .eggs import Egg
class Ham:
pass
eggs.py
"""eggs module"""
class Egg:
pass
setup.py
from setuptools import setup, find_packages
setup(
name="foo",
version="1.0.0",
author="Pablo",
description="Example",
packages=find_packages(),
entry_points={
"console_scripts": ["foo=foo.spam:main"]
},
)