2

I am currently doing a personal coding project and I am trying to build a module, but I don't know why my structure doesn't work the way it's supposed to:

\mainModule
    __init__.py
    main.py
    \subModule_1
        __init__.py
        someCode_1.py
        someCode_2.py
    \subModule_2
        __init__.py
        otherCode.py

I want to be able to run the following code from main.py:

>>> from subModule_1 import someCode_1
>>> someCode_1.function()
"Hey, this works!"
>>> var = someCode_2.someClass("blahblahblah")
>>> var.classMethod1()
>>> "blah blah blah"
>>> from subModule2 import otherCode
>>> otherCode("runCode","#ff281ba0")

However, when I try to import someCode_1, for example, it returns an AttributeError, and I'm not really sure why. Is it to do with the __init__.py file?

REVISIONS

  • Minimal, Complete and verifiable (I hope...)

    \mainDir
        __init__.py # blank file
        main.py
        \subDir
            __init__.py # blank file
            codeFile.py
    

    Using this...

    #main.py file
    import subDir
    subDir.codeFile.function()
    

    And this...

    #codeFile.py file
    def function():
        return "something"
    

    ...it returns the same problem mentioned above**.

** The exact error is:

Traceback (most recent call last):
  File "C:\...\mainDir\main.py", line 2, in <module>
    subDir.codeFile.function()
AttributeError: module 'subDir' has no attribute 'codeFile'

Credits to @jonrsharpe: Thanks for showing me how to use Stack Overflow correctly.

6
  • 2
    Please provide a minimal reproducible example. Also you seem to be saying you want to run an interactive session "from main.py", which doesn't entirely make sense. Commented Jan 15, 2017 at 20:53
  • 1
    Might be caused by some module level code in someCode_1 which is executed upon import. WHat is the exact error message? Commented Jan 15, 2017 at 21:05
  • @jonrsharpe Sorry, I meant compiling and running main.py using the interpreter (sorry, rookie mistake) Commented Jan 15, 2017 at 21:15
  • @schwobaseggl Traceback (most recent call last): File "C:\...\main.py", line 10, in <module> subDir.codeFile.function() AttributeError: module 'subDir' has no attribute 'codeFile' Commented Jan 15, 2017 at 21:15
  • Make sure your current working directory is neither mainDir nor subDir when you perform the test. Commented Jan 15, 2017 at 21:18

2 Answers 2

1

You have two options to make this work.

Either this:

from subdir import codeFile
codeFile.function()

Or:

import subdir.codeFile
subdir.codeFile.function()
Sign up to request clarification or add additional context in comments.

Comments

1

When you import subDir, it does three things:

  1. executes the code in mainDir/subDir/__init__.py (i.e. in this case does nothing, because this file is empty)
  2. imports the resulting module under the name subDir locally, which will in turn make it an attribute of the mainDir module;
  3. registers the new import globally in the sys.modules dictionary (because the import is being performed from a parent module mainDir, the name is completed to 'mainDir.subDir' for the purposes of this registration);

What it does not do, because it hasn't been told to, is import subDir.codeFile. Therefore, the code in codeFile.py has not been run and the name codeFile has not yet been imported into the namespace of mainDir.subDir. Hence the AttributeError when trying to access it. If you were to add the following line to mainDir/subDir/__init__.py then it would work:

import codeFile

Specifically, this will:

  1. run the code in codeFile.py
  2. add the resulting module as an attribute of the mainDir.subDir module
  3. store a reference to it as yet another entry in sys.modules, this time under the name mainDir.subDir.codeFile.

You could also achieve the same effect from higher up the module hierarchy, by saying import subDir, subDir.codeFile instead of just import subDir in your mainDir.main source file.

NB: When you test this from the command line or IDE, make sure that your current working directory (queried by os.getcwd(), changed using os.chdir(wherever) ) is neither mainDir nor subDir. Work from somewhere else—e.g. the parent directory of mainDir. Working from inside a module will lead to unexpected results.

6 Comments

This makes so much sense - I'm amending this now to get it to work (I had no idea how the import keyword actually worked, but this clears up a lot of smoke for me)
Question - if I didn't want to have my current working directory to be main.py (which you accurately guessed it would be), "where" would I run the interpreter from? Does it even matter?
Unfortunately, I received an error from putting import codeFile into mainDir\subDir\__init__.py: ModuleNotFoundError: No module named 'codeFile'
Two things matter: (1) that you're not working inside a module; (2) that every module you want to find (in this case the directory mainDir) is either in your current working directory—right at your feet, so to speak—or inside one of the directories listed on your system path (sys.path). Otherwise mainDir will not be found when you try to import it. (But the mainDir directory itself should not be part of sys.path.)
Re your ModuleNotFoundError: another thing you have to work around is the fact that modules are cached. If you change module code, you have to reload it, (first reload the sub-sub-modules, then the sub-modules, then the module). That can get really tedious, so sometimes the easiest way is to re-start Python each time you try changing the architecture like this. Another problem is the difference between python 2.x and 3.x—my solution works in 2.x but am currently trying to figure out why it fails with ImportError: no module named 'subDir' in 3.x
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.