$ cat >> driver.py
import project.one
$ python driver.py
That worked because the containing folder for driver.py
was on the module search path (sys.path
), because of how we started Python - so the project
folder could be found directly within the CWD.
Here are the rules for how sys.path
gets initialized:
We can, of course, make this more robust by actually installing the package. That will make sure that the package appears on sys.path
regardless, and also opens up other, more explicit options for creating an entry point.
The corresponding Q&A on Stack Overflow is not terribly high quality (everything to do with import
is a huge mess full of redundancy and cargo-culting) but it does give the necessary information:
stackoverflow.com
Karl Knechtel:
There are many ways to do this, but in general you want a program to start with a single absolute import first.
For example, if I create a trivial test package:
After this quote, you begin immediately with DOS instructions inside the command prompt
. Why not with instructions within the Python shell editor
? Is Python not equipped with the ability to create Python packages? In my opinion it would make sense for there to be a Pythonic way of creating packages for relative imports without the need of deferring this action to DOS.
Karl Knechtel:
Once you have fixed this, the next problem is that your second relative import simply has the wrong “path”. It should be from ..package2.sub_pkg import sub_file
.
Yes, I fixed this. Thank you.
Update
. After making the update with respect to the sub_file
import reference in file_1
, I executed the following commands in the command prompt. After doing so, the following response was observed:
C:\User\mycomp\Desktop\pkg>python -m package1.file_1
I'm in package1, file_2
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "C:\Users\mycomp\Desktop\pkg\package\file_1.py", line 18, in <module>
from ..package2.sub_package import sub_file
ImportError: attempted relative import beyond top-level package
C:\User\mycomp\Desktop\pkg>
I’m not sure how to interpret this. There isn’t a “within Python” here, because Python isn’t the system that you use to create files, it’s the rules for interpreting what’s written in them. It’d be like asking about how to write books “within English” when someone showed how to use a word processor instead of a pen and paper.
But the point is that the package doesn’t really need any “setup”. I created some files and put them in folders to give a simpler example than your actual project. It’s not necessary to make any more files or do anything special with the folder structure. What is necessary is to make sure that either:
some absolute import happens first;
Python runs the code as a module (with a fully-qualified package name) using -c
.
This way, the package will be loaded first before any relative imports are attempted.
Keep in mind here that Python packages are modules - they’re represented within Python by the same type of object, and stored within sys.modules
in the same way.
Paul:
After this quote, you begin immediately with DOS instructions inside the command prompt
. Why not with instructions within the Python shell editor
?
Because then I would have to go back and forth between plain English explanations of steps to follow, and code blocks showing things to type. 
Sorry for the confusion.
Paul:
I executed the following commands in the command prompt. After doing so, the following response was observed
The command should be run from the Desktop folder, and it should use pkg
in the path:
C:\User\mycomp\Desktop\>python -m pkg.package1.file_1
This way, pkg
is the top-level package, which contains package1
and package2
sub-packages. Since file_1
and sub_file
now have a common “root” - in the package system, not just your file hierarchy on disk - they can use relative import.
If you don’t want the pkg
folder to represent a Python package, then it won’t be possible to use relative import between a module in package1
and another module package2
or vice-versa - as far as Python is concerned, they are not related to each other, and they could be relocated to any separate places. As I described, relative import only works within an already-loaded package; for something to be “an already-loaded package”, we must be willing to treat it as a package.
My misinterpretation is all. I create my folders/directories via Windows. This is not the only way of course. You can of course create them via DOS or Linux as you know. I was just a bit concerned why you were doing it differently and thinking there was a more sinister reason for doing so (there isn’t, just preference I suppose).
Well, I have found where I went wrong. The relative import syntax from my original post is not wrong at all. The issue was that I was attempting to run that module from its location that was the issue. From Learning Python, 5th E.:
In Python 3.X, the new relative search rule change means that a file can no longer
serve as both script and package module as easily as it could in 2.X.
In order to test/run the relative imports instructions, you must implicitly run them from a main module, …, the main of the package. So, I have added a root_main.py
module to the project. If I run the project from there, no exception errors are encountered. Here is my updated package:
From the figure, I was attempting to run the file_1.py
module in the package1 directory. This is what was causing the errors (as highlighted by the Learning Python reference). I went ahead and added a new module named root_file.py
. When I ran the script from there, all was well.
In other words, I was attempting to run the module as the package script. Of course, this module is a package module and not the script of the package, hence the exception errors.
In my new module root_file.py
, I have the following script:
from package1 import file_1
file_1.run_1('Hello from the pkg\root_file.')
The script in my file_1.py
file, I have:
from . import file_2
from .sub_package1 import sub_file_1
num1 = 11
string1 = "I'm in package1, file_1."
def run_1(message):
print(message)
run_1(string1)
Here is the YouTube video that I referenced. Note that it discusses both the absolute and the relative import methods. If you want to skip to the beginning of the relative imports discussion, jump to the ~5:35 minute mark.
The limitation of relative imports is that you can only import modules that are along the hierarchy (above and below) but not adjacent. For example, with relative import syntax, I wouldn’t be able to import modules from the package2 directory. For that, you have to use absolute path imports.
Well, thank you again for your time and attempting to resolve this issue. Much appreciated!
All is well now.