Solution:
unfortunately, this module requires to be within the package, and it also requires to be runnable as a script, occasionally. Any idea how I could achieve that?
It's quite usual to have a layout like this
main.py
mypackage/
__init__.py
mymodule.py
myothermodule.py
.with a mymodule.py
like this
#!/usr/bin/env python3
# Exported function
def as_int(a):
return int(a)
# Test function for module
def _test():
assert as_int('1') == 1
if __name__ == '__main__':
_test()
..a myothermodule.py
like this…
#!/usr/bin/env python3
from .mymodule import as_int
# Exported function
def add(a, b):
return as_int(a) + as_int(b)
# Test function for module
def _test():
assert add('1', '1') == 2
if __name__ == '__main__':
_test()
..and a main.py
like this…
#!/usr/bin/env python3
from mypackage.myothermodule import add
def main():
print(add('1', '1'))
if __name__ == '__main__':
main()
...which performs fine at the time you run main.py
or mypackage/mymodule.py
, however fails with mypackage/myothermodule.py
, due to the relative import…
from .mymodule import as_int
The way you're inferred to run it is…
python3 -m mypackage.myothermodule
however it's somewhat verbose, and doesn't mix well with a shebang line like #!/usr/bin/env python3
.
The easiest solve for this instance, pretending the name mymodule
is globally unique, would be to avoid employing relative imports, and just use…
from mymodule import as_int
Though, in case it's not unique, or your package structure is more complex, you'll require to add the directory bearing your package directory in PYTHONPATH
, and do it like this…
from mypackage.mymodule import as_int
...or in case you want it to perform "out of the box", you can frob the PYTHONPATH
in code first with this…
import sys
import os
PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))
from mypackage.mymodule import as_int
I'm -1 on this and on any other raised twiddlings of the __main__
machinery. The only employ instance appears to be running scripts that occur to be living within a module's directory, which I've always view as an antipattern. To make me change my mind you'd have to convince me that it isn't.
Whether running scripts within a package is an antipattern or not is subjective, however personally I trace it truly helpful in a package I have which comprise few custom wxPython widgets, so I can run the script for any of the source files to display a wx.Frame
bearing just that widget for testing purposes.