0

Assuming the following sample project structure:

src/
  animals/
    __init__.py
    cat.py
    dog.py
  zoo.py

I want to achieve the following two behaviors:

  1. animals package dynamically imports all of its modules. This is required for the code that uses this package (say from zoo.py). This can be done in a fashion described here. For example like this:

    # animals/__init__.py
    from pathlib import Path
    from importlib import import_module
    
    for f in Path(__file__).parent.glob("*.py"):
        if f.name == '__init__.py':
            continue
        import_module(f".{f.parts[-1][-3]}", __name__)
    
  2. Each of the modules in animals should be separately runnable from CLI, for example like this:

    python3 -m src.animals.dog  # Runs some dog specific stuff, e.g. tests
    

So far, I fail to combine these two requirements together. The problem arises from the fact that this command line first loads the animals package which in turn imports dog among the other sub-modules. But later dog is being imported for a second time as __main__. This leads to a duplicate import (dog code being processed twice). I also get the following warning:

RuntimeWarning: 'src.animals.dog' found in sys.modules after import of package 'src.animals', but prior to execution of 'src.animals.dog'; this may result in unpredictable behavior.

One possible way I thought of solving it is somehow detecting which module is being invoked from the command line and skip its loading in __init__. But how do I find this info? Tried parsing sys.modules['__main__'] but it seems mostly uninitialized.

Note: In the real project I have one more hierarchy level under animals, and I load all the sub packages, but that shouldn't matter for the sake of this example.

vvv444
  • 2,764
  • 1
  • 14
  • 25

0 Answers0