I am trying to create an executable directory. It appears that the code in the init.py in one of my subpackages is executing before the main.py file in the root directory. Why is that?
Since you didn't describe any particular package structure in your question, all me to conjure up one for the sake of example. Let's say your package structure looks like the following:
package/
├── __init__.py
├── __main__.py
└── subpackage
├── __init__.py
└── submodule.py
and that package/__main__.py contains
print("before import in", __name__)
import package.subpackage.submodule
print("after import in", __name__)
while the files package/__init__.py, package/subpackage/__init__.py, and package/subpackage/submodule.py all contain
print(__name__)
(Note that __name__ is just a fancy global variable that holds the name of the current module).
If we try to run our package using the command
$ python3 -m package
we get the following output
package
before import in __main__
package.subpackage
package.subpackage.submodule
after import in __main__
This tells us that that package's top level __init__ module was the first to be loaded by the interpreter, followed by __main__. In the process of running __main__, we encounter an import statement, which causes the interpreter to briefly halt execution to load the desired module. When loading a module, Python check whether each intermediate package has already been loaded. Any packages that haven't been loaded yet will be loaded first, so importing package.subpackage.submodule results in package/subpackage/__init__.py being run, followed by package/subpackage/submodule.py. Only once all this is completed does control return back to __main__.
In your package, the __init__.py of your subpackage is not executing before __main__.py per se. Rather, you main module is (presumably) importing a module from the subpackage, which results in the subpackage's __init__ module being loaded, as demonstrated above.
Related
How could I run the entirety of test.py from main.py. Both main.py and test.py is allocated within the application folder. The test.py file is within the app folder. How would I be able to achieve this, the code I have below does not work?
Directories:
application folder
├── appFolder
│ └──test.py
└── main.py
Main.py:
from .appFolder import test
from subprocess import call
call(["Python3","test.py"])
You don't need to import anything, just reference the folder name in main.py. To make it more robust, you should probably use a relative file otherwise you might get some odd results depending on where main.py is called from.
import os.path
from subprocess import call
d = os.path.dirname(os.path.realpath(__file__)) # application folder
call(["python3", f"{d}/appFolder/test.py"])
See also: https://stackoverflow.com/a/9271479/1904146
This question already has answers here:
Attempted relative import with no known parent package [duplicate]
(4 answers)
Relative imports in Python 3
(31 answers)
Closed 1 year ago.
I have the following directory structure:
py_test
├── __init__.py
├── dir1
│ ├── __init__.py
│ └── script1.py
└── dir2
├── __init__.py
└── script2.py
In script2 I want to "import ..\script1".
What I tried in script2:
Does not work
from ..dir1 import script1
ImportError: attempted relative import with no known parent package`
Works
import sys, os
path2add = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'dir1')))
if (not (path2add in sys.path)) :
sys.path.append(path2add)
If I want to go with option 1, what is the simplest (i.e., with the least files) file/dir structure that makes it work?
I am aware of this, but I wonder if creating that directory structure can be avoided, and still use type-1 import.
I am currently using this workaround, which uses type-2 import.
Related:
How to import a Python class that is in a directory above?
Import a module from a directory (package) one level up
Getting "ImportError: attempted relative import with no known parent package" when running from Python Interpreter
Using importlib to dynamically import module(s) containing relative imports
How to import variables in a different python file
As mentioned in the comments, attempting to import modules a directory up will not work if script2.py is your entry point.
As mentioned in this link you included:
If the module's __name__ does not contain any package information (e.g., it is set to __main__), then relative imports are resolved as if the module were a top-level module, regardless of where the module is actually located on the file system.
The module's __name__ is set to __main__ if it is the entry point, or the one that you pass to the interpreter with something like python script2.py.
Any python module run as such no longer has the information needed to import files from higher directories.
Therefore you have two options:
Option 1: Keep using the workaround with sys.path.append
This will work how you want it to, but it is rather cumbersome.
Option 2: Make your entry point at the top level
Assuming your package has more than one script that needs to be run, you could create a new file that imports both script1 and script2 and then calls the functionality you want based on a command line argument. Then you will be able to keep your current directory structure and have your relative imports work just fine, without any kind of fiddling with sys.path.
Sorry if the title is not very clear but I failed to summarize well.
I'm experimenting with packages and I'm in this situation:
$:~/project$ tree
.
├── first_mod.py
└── first_package
├── __init__.py
└── sub_package
├── __init__.py
└── second_mod.py
In the first __init__.py inside first_package dir I specifies this content:
from first_package.sub_package.second_mod import function
(obviously in the module second_mod there is a function called function)
If I open an interpreter in the dir project and import first_package and then try to see what it contains using tab autocompletion, in addition to the function the sub_package is also listed.
>>> import first_package
>>> first_package. [tab]
first_package.function( first_package.sub_package
The question is: is it inevitable that sub_package is also shown as the content of first_package when I import only function in the __init__.py?
The behavior at hand can be explained with a short rundown of what happens when you import a module baz with a statement like import foo.bar.baz.
1: importing parent modules
Before baz can be imported, bar needs to be there. And before bar can be imported, foo needs to be there - there is no way for python to reach baz via a shortcut.
2: running __init__.py files
Every package that is imported along the up to baz has an __init__.py file, which is executed.
3: loading encountered modules into sys.modules
When a folder is imported as a package, all python files in it are imported as modules (excluding __init__.py files, which can be imagined to be stand-in for the package itself). They will be loaded into sys.modules and are accessible to the package objects (which in this case are foo, ``bar, and baz`).
And that's pretty much it, the gritty details can be looked up here.
In your example, two import statements got executed (one by you and one when first_package/__init__.py was run), but only the first one is necessary to explain what happened. When you imported first_package, the third step loads all modules that are part of the package. This includes sub_package, and there is no way around it using the standard import mechanisms.
Running
del first_pacakge.sub_package
will remove it from the object in case you only care about that, but it won't unload it and it will still be in sys.modules.
I have the following project structure:
x/
a.py
b.py
main.py
a.py:
from b import *
class A:
.....
main.py
from x.a import A
.....
I want to be able to run a.py independently as well as access its functionality through main.py
I'm able to run a.py but when I try to import it as shown in main.py, the module is unable to be found. I can fix this problem by adding the following line to a.py:
sys.path.append(os.path.join(os.path.dirname(__file__)))
but this feels hacky. Is there a better way to achieve the desired behavior?
You need to mark the directory "x" as a package to be able to load anything off it.
As stated in the official documentation of Python, you have to create an empty "__init__.py" file in the root of "x" to mark it off as a package.
Then your directory structure should look something like this:
.
└── x
├── __init__.py
├── a.py
└── b.py
└── main.py
You may want to edit "a.py" to load the modules relative to the package it is in using a period to represent the current package:
# x/a.py
from .b import *
class A:
# rest of your code
I have a module with multiple files structured like this:
/bettermod/
├── __init__.py
├── api.py
├── bettermod.py
├── errors.py
└── loggers.py
From bettermod.py, I'm trying to import two things:
a class called API from api.py
the whole errors.py file
For the first thing, it is quite easy, I just have to do this:
from .api import API
However, for importing the whole errors.py file, I'm encountering a problem; I'm trying to do like this:
from . import errors
which should work, according to this python documentation, but it's raising the following error:
File "/path/to/bettermod/bettermod.py", line 10, in <module>
from . import errors
ModuleNotFoundError: No module named 'bettermod'
Edit: when debugging, I found that __name__ was equal to bettermod.bettermod
From docs:
Note that relative imports are based on the name of the current module.
I cannot tell you what is wrong with certainty, but there is a smell: bettermod package has a bettermod module. You want to do from bettermod.bettermod import MyBetterClass? I doubt it. In Python files ARE namespaces, so choosing your file and directory names is also an API design. Just keep that in mind.
I suspect the problem is masked by the name collision. Try this. If you run python in bettermod directory and say import bettermod you are importing bettermod\bettermod.py. And . is relative to the bettermod.py module. Now try to run python in directory above bettermod package directory. It will work because now . resolves to bettermod package.
Try:
import mymodule
mymodule.__file__
This will tell what mymodule is. For packages, it will show path to __init__.py. This will help you to orient yourself. Also look up PYHTONPATH and how you can use it to make sure you are importing from the right path.