10

I have a package layout:

scenarios/
    __init__.py
    X/
        __init__.py
        Y/
            __init__.py
    Z/
        __init__.py 

I have executed

import scenarios
pkgutil.walk_packages(scenarios.__path__, scenarios.__name__ + '.')

But this generates a list only including the packages X and Z, Y is missing. What can I use to get all the sub directories?

Thanks

2 Answers 2

12

Here is a theory: The walk_packages function attempts to import each module listed. When it gets to the sub-package "Y" it attempts to import it, but there is an error. By default, this error is suppressed. A sideeffect is that the walk_packages function doesn't recurse into Y. You can test this theory using the "onerror" keyword argument. For example:

import sys, pkgutil
from traceback import print_tb

def onerror(name):
    print("Error importing module %s" % name)
    type, value, traceback = sys.exc_info()
    print_tb(traceback)

import scenarios
pkgutil.walk_packages(scenarios.__path__, scenarios.__name__ + '.', onerror=onerror)
1
  • Thanks, I didn't realise it was failing silently on import errors. My problem was that my package wasn't on my sys.path
    – Tom Close
    Commented Feb 3, 2022 at 4:45
0

This works in Python 3.6 at least, for what it's worth. Set up the test scenario:

mkdir -p scenarios/X/Y scenarios/Z
find scenarios -type d -exec touch {}/__init__.py \;

Now run a version of your example code:

import pkgutil
import scenarios
for module_info in pkgutil.walk_packages(scenarios.__path__, scenarios.__name__ + '.'):
    print(module_info.name)

Which prints:

scenarios.X
scenarios.X.Y
scenarios.Z
1
  • Despite Python >= 3.3 supporting implicit namespace packages that don't require an __init__.py, I found that they are required in order for pkgutil.walk_packages to successfully recurse into subpackages Commented Mar 22, 2022 at 17:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.