Python general importing guide (for your own code)
I'm sure there should be a duplicate for this by now, but I can't find it, so I'm writing a full essay.
To solve the problem properly, you must take care of two things:
Make sure that sys.path
- the path that Python searches for modules - includes the path to the project root.
Make sure that the import
statements in the code are written to work with that path.
The search path
For the first part, you must understand how sys.path
works. It is a list of folders where Python will look, that is set up automatically at startup (even if you don't import sys
- just like sys.argv
is).
Normally, it will be a list which contains, in order:
A path to the entry point for execution (the details of this will depend on how Python is started; typically this is ''
when running a .py
file directly from the same directory, a path the another directory if you do e.g. python somewhere/else/file.py
, and an explicit path when using the -m
switch)
Paths to system libraries
Paths to virtual environment libraries, if a virtual environment is active
Paths to things that were explicitly installed by the user
You can modify this list, with the expected impact on future import
statements; but you ordinarily should not.
To ensure your project root is on the path, normally you should just install the project - ideally into a virtual environment. Please see the Python packaging guide for details. Failing that, make sure to start the project from just outside the folder containing your "top-level" code. In OP's case, that means C:\code
. This will ensure that C:\code
(or something equivalent) is on sys.path
, which we can then rely upon for the second step.
The imports
We can fundamentally do this in two ways: By absolute imports specifying the path from the root, or by relative imports specifying the path from the current source file. Read more on Stack Overflow about relative imports here and here.
Absolute imports
In either case, we want to treat the root folder for our project (here, C:\code\voiceTerm
) as a package. For absolute imports, this means we will always mention the root folder name in our import path.
Thus:
In C:\code\voiceTerm\master.py
: from voiceTerm.voice_terminal_module.voice_terminal import VoiceTerminal
In C:\code\voiceTerm\voice_terminal_module\voice_terminal.py
: from voiceTerm.voice_terminal_module.chatbot_module.chatbot_module import Chatbot
(You don't really want to have _module
in your folder or file names. It doesn't really add information, makes this considerably harder to type, and is actually a bit misleading.)
We can also import
entire modules: import voiceTerm.master
, import voiceTerm.voice_terminal_module.voice_terminal
; import voiceTerm.voice_terminal_module.chatbot_module.chatbot_module
. Additionally, by naming a file __init__.py
, we become able to import the folder as a package: import voiceTerm
; import voiceTerm.voice_terminal_module
; import voiceTerm.voice_terminal_module.chatbot_module
. We can also import a module from one of those packages: from voiceTerm import master
; from voiceTerm.voice_terminal_module import voice_terminal
; from voiceTerm.voice_terminal_module.chatbot_module import chatbot_module
.
Relative imports
With relative imports, we must use the from
syntax, and we can only import things from within our own package hierarchy. However, we have the advantage that we don't have to specify full paths, and we can rename packages without having to edit the code. My personal recommendation is to use relative imports where possible; this also makes a strong visual distinction with imports from system libraries or other third-party packages.
For a relative import, first we specify the package or sub-package that we're importing from, using a relative import path. By starting with a single .
, we start from the current directory, looking for another module or package within the same folder.
Thus:
In C:\code\voiceTerm\master.py
: from .voice_terminal_module.voice_terminal import VoiceTerminal
to import the class; from .voice_terminal_module import voice_terminal
to import the module.
In C:\code\voiceTerm\voice_terminal_module\voice_terminal.py
: from .chatbot_module.chatbot_module import Chatbot
to import the class; from .chatbot_module import chatbot_module
to import the module.
Additional .
s navigate up the package hierarchy (but we cannot go beyond the root this way). For example, from ... import master
to import the top-level master.py
from the lower-down chatbot_module.py
. (Of course, this wouldn't actually work in this case, because it would be a circular import.) To import another source file (as a module) from the same directory, simply from . import other_file
. You get the idea.