3

I have a directory structure that looks like this:

scripts/
    __init__.py
    filepaths.py
    Run.py
    domains/
        __init__.py
        topspin.py
        tiles.py
        hanoi.py
        grid.py

I would like to say:

from scripts import *

and get the stuff that is in filepaths.py but also get the things that are in hanoi.py

The outer __init__.py contains:

__all__ = ['filepaths','Run','domains','hanoi']

I can't figure out how to get the inner files to be included in that list. Putting hanoi by itself gets this error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'hanoi'

Putting domains.hanoi gets this error message:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'domains.hanoi'

The last reasonable guess I could come up with is putting scripts.domains.hanoi which gets this error message:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'scripts.domains.hanoi'

How do you get the all list to include things that are in subdirectories?

karthikr
  • 97,368
  • 26
  • 197
  • 188
zelinka
  • 3,271
  • 6
  • 29
  • 42
  • I guess, “don't use * imports” is not what you want to hear, but still… – kirelagin Jun 06 '13 at 21:11
  • You can't do _exactly_ what you want, and that's at least partly because (as @kirelagin says) you shouldn't want to do it. If you can explain what you really care about here, maybe we can explain a better way to accomplish it than making `from pkg import *` work recursively without modifying the packages (which is what you're asking for). – abarnert Jun 06 '13 at 21:13
  • I would like to use one import statement that will allow me to say hanoi.foo() and tiles.foo(). The way things are structured now I have to say something like scripts.domains.hanoi.foo() which is way too long, or move everything into one directory, which would get crowded. – zelinka Jun 06 '13 at 21:18

2 Answers2

2

In scripts/__init__.py, before the __all__ add the following

from domains import topspin, tiles, hanoi, grid

This will add those modules to the namespace, and you will be able to import them with

from scripts import *

Note

As a soapbox, it is preferred to do things like

from scripts import topspin, tiles, hanoi, grid, filepaths, Run

over

from scripts import *

because 6 months from now, you might look at hanoi on the 400th line of code and wonder where it came from if you use the * import style. By explicitly showing what is imported from scripts it serves as a reminder where things come from. I'm sure that anyone trying to read your code in the future will thank you.

SethMMorton
  • 45,752
  • 12
  • 65
  • 86
  • from domains import topspin, tiles, hanoi, grid __all__ = ['filepaths','Run','topspin', 'tiles', 'hanoi', 'grid'] The list needed commas, if you fix that I'll accept this answer. – zelinka Jun 06 '13 at 21:30
  • Thanks. It was a copy paste and I forgot to add the commas. – SethMMorton Jun 06 '13 at 21:31
  • If you use python interactively import * is your friend. I agree if you're building a program it can cause problems, but like I said, if you're doing something small interactively you definitely come to appreciate the *. – zelinka Jun 12 '13 at 22:32
  • True. I wasn't thinking in terms of interactive use, but you are absolutely correct. – SethMMorton Jun 12 '13 at 22:37
1

Import them first, in the __init__ files.

In scripts/__init__.py, import at least domains, and in scripts/domains/__init__.py import hanoi, etc. Or import domains.hanoi directly in scripts/__init__.py.

Without importing these, the scripts/__init__.py module has no reference to the nestend packages.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343