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

user2357484
  • 101
  • 1
  • 4

2 Answers2

11

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)
jdg
  • 2,230
  • 2
  • 20
  • 18
  • 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 Feb 03 '22 at 04: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
romanows
  • 458
  • 4
  • 12
  • Despite Python >= 3.3 supporting [implicit namespace packages](https://stackoverflow.com/questions/37139786/is-init-py-not-required-for-packages-in-python-3-3) that don't require an `__init__.py`, I found that they are required in order for `pkgutil.walk_packages` to successfully recurse into subpackages – Addison Klinke Mar 22 '22 at 17:43