Newbie package question

I’m trying to create my very first python package. However, I’m not sure what I’m doing wrong.

I created a subfolder “pack” containing 3 files:
__init__.py:
(empty file)

printer.py:

def say_hello():
   print( 'hello world' )

main.py:

import printer

def run():
   printer.say_hello()

Then in the root folder, I have a file test.py that tries to use the package:

from pack import main
main.run()

When I run test.py, I get an error:

ModuleNotFoundError: No module named 'printer'

I think that in main.py the import should be something like:

from . import printer  # relative import

or

from pack import printer  # absolute import
1 Like

Neither of these solutions work, however.

If I use:

from . import printer

Then when I run main.py, it fails with:

ImportError: cannot import name ‘printer’ from ‘main’ (main.py)

And if I use “from pack import printer” I get:

ModuleNotFoundError: No module named ‘pack’

So I’m not sure how to set things up so that I can achieve two things:
(1) run the package from within itself
(2) run the package while importing it

This seems odd because I need the package to be able to run itself (to do self testing, etc.) but I still want to be able to import it into a larger project.

I am a newbie also and I have the same issue. The only way I can get this to work is to have test.py read something like the below. I have no sense as to whether this is good practice or not though - I’m having a really hard time understanding how to organize modules into packages.

def run():
    printer.say_hello()

if __name__ == '__main__':
    import printer
else:
    from . import printer

The simplest way to organise your package is like this:

mypackage/
+--  __init__.py
+--  __main__.py
+--  submodule.py
+--  subpackage/
     +-- __init__.py
     +-- anothermodule.py

Of course you can have more than one sub-module or sub-package.

Technically it is not absolutely necessary to have an __init__.py
file in the package, but the rules for skipping it are very complicated
and most people (including me!) don’t understand it. So save yourself a
lot of pain and always include __init__.py, even if it is an empty
file.

The __main__.py file is used when you run the package as if it were a
script:

# Don't do this!
python3 mypackage.__init__.py

# Do this instead:
python3 -m mypackage

# or if you have to specify the full path:
python3 path/to/mypackage/__main__.py

That will automatically treat the package as a script and run the code
in the __main__.py file. That keeps it nicely independent from the
code that gets run when you import the package:

import mypackage  # uses mypackage/__init__.py

Of course you can import code inside __main__.py like this:

from . import stuff

Try reorganising your package to put the script-like code in a seperate
__main__.py file and see if that helps.

1 Like

Thank you! I’m not sure I fully get it but it seems to work so far.

@ellliottp