I was working on a project with this type of folder tree:
-main.py
-Message_handlers
-__init__.py
-On_message.py
-Other_modules.py
-Exceptions_handler
-__init__.py
-Run_as_mainException.py
Message_handlers and Exceptions_handler are two packages, now my problem is that from inside the module On_message.py I can't import the class Run_as_mainException (inside of the module Run_as_mainException.py) using this code
# This is On_message.py
from ..Exceptions_handler.Run_as_mainException import Run_as_main_Exception
This line gives the error: ImportError: attempted relative import with no known parent package
p.s. Every file has a class inside with the same name of the file, example:
# This is Run_as_mainExample.py
class Run_as_mainExample:
def __init__(self):
# rest of the code
Can anyone help me please?
You have to assume that you're running everything from the level where main.py is located. This means, imagine that you execute python main.py, and you want to import Run_as_main_Exception from main.py, what should you do?
from Exceptions_handler.Run_as_mainException import Run_as_main_Exception
Try using that line in your On_message.py file, and you shouldn't have any problem when running your script from that exact location (remember, the same level where main.py is located)
Related
Here is my code:
from .Input import Choice27
import os
def New_File():
file_path = os.path.abspath(r"C:\Users\Me\Documents\Project\InputFolder\Test.txt")
Var1 = str(Choice27.Var[0])
Var2 = str(Choice27.Var[1])
with open(file_path, 'r') as file:
Output = file.read()
Replace = {'Find1':Var1,'Find2':Var2,}
for key, value in Replace.items():
Output = Output.replace(key, value)
It is giving me an error ImportError: attempted relative import with no known parent package.
My file structure for this test project is:
Project folder
Main.py
InputSubFolder
Input.py
Output.py
I know a beginner amount of python programming but I have never dealt with subfolders with my code. I use vscode for testing and auto-py-to-exe for compiling. I do not have any warnings before testing with vscode and receive no errors on compiling.
I have tried doing absolute pathing Ex. "from Input import Choice27", but I receive the same error.
I have also tried adding init.py to the subfolder even though I know it is not needed in my version of python.
On the Main.py, I can call import the modules with "import InputSubFolder.Input as IN, " which works just fine.
What kind of structuring or pathing do I need to do so that each file and subfolder can communicate if needed?
Inside your "Project folder/InputSubFolder", create a new file named __init__.py (two underscores before and after init keyword) and add following code:
from .Input import Choice27
Now inside Main.py, you can access Choice27 like this:
from InputSubFolder import Choice27
Adding __init__.py in a directory makes that directory a local Python package, containing all exportable classes, functions and variables which needs to be imported in some other Python file.
At the end, your project structure should be:
Project folder
Main.py
InputSubFolder
__init__.py
Input.py
Output.py
i'm struggling with something that feels like it should be simple.
my current dir looks like this:
root/
└─ __init__.py (tried with it and without)
└─ file_with_class.py
└─ tests_folder/
└─ __init__.py (tried with it and without)
└─ unittest_for_class.py
unittest_for_class.py needs to import the class from file_with_class to test it, i tried to import it in various ways i found online but i just keep getting errors like:
(class name is same as file name lets say its called file_with_class)
File "tests_folder/unittest_for_class.py", line 3, in <module>
from ..file_with_class import file_with_class
ValueError: Attempted relative import in non-package
File "tests_folder/unittest_for_class.py", line 3, in <module>
from file_with_class import file_with_class
ImportError: No module named file_with_class
and others..
what is the correct way to import a class from a .py file that is in the parent folder ?
As a short explanation
import * from ..parent works if your program started at the parent level.
You import submodules which can have cross relations to other submodules or files in the package -> They are only relative inside a package not the os structure.
Option 1
you actually enter via a script in your parent folder and import your mentioned file as a submodule. Nicest, cleanest and intended way, but then your file is no standalone.
Option 2 - Add the parent dictionary to your path
sys.path.append('/path/to/parent')
import parent
This is a little bit dirty as you now have an extra path for your imports but still one of most easiest ones without much trickery.
Further Options and theory
There are quite a few posts here covering this topic relative imports covers quite a few good definitions and concepts in the answers.
Option 3 - Deprecated and not future proof importlib.find_loader
import os
import importlib
current = os.getcwd() # for rollback
os.chdir("..") # change to arbitrary path
loader = importlib.find_loader("parent") # load filename
assert loader
parent = loader.load_module() # now this is your module
assert parent
os.chdir(current) # change back to working dictionary
(Half of an) Option 4
When working with an IDE this might work, Spyder allows the following code. Standard python console does NOT.
import os
current = os.getcwd()
os.chdir("..")
import parent
os.chdir(current)
Following up on #Daraan's answer:
You import submodules which can have cross relations to other submodules or files in the package -> They are only relative inside a package not the os structure.
I've written an experimental, new import library: ultraimport which allows to do just that, relative imports from anywhere in the file system. It will give you more control over your imports.
You could then write in your unittest_for_class.py:
import ultraimport
MyClass = ultraimport("__dir__/../file_with_class.py", "MyClass")
# or to import the whole module
file_with_class = ultraimport("__dir__/../file_with_class.py")
The advantage is that this will always work, independent of sys.path, no matter how you run your script and all the other things that were mentioned.
You can add the parent folder to the search path with sys.path.append() like so:
import sys
sys.path.append('/path/to/parentdir')
from file_with_class import file_with_class
...
See also the tutorial for how Python modules and packages are handled
Just keep from file_with_class import file_with_class. Then run python -m test_folder.unittest_for_class. This supports running the script as if it is a module.
I have 3 folders in my project: scripts , src, tests. In scripts, I have a script to populate my local db with test data (populate_db.py). In the tests folder, I have a file called generators.py, which I'm trying to import into populate_db.py , but I'm not having any luck. I have this:
code_path = Path("../")
sys.path.append(code_path / "tests")
from generators import UserFactory
but I get the error ModuleNotFoundError: No module named 'generators'. Strange thing, is I do
sys.path.append(code_path / "src")
from users.models import User
and that imports fine. Not sure what I've done differently/wrong. I also tried a relative import: from ..generators import UserFactory, but got attempted relative import with no known parent package. I do have __init__.py in the parent and tests directories (though there are no python files in the parent, only in the 3 children).
Try this:
from .tests.generators import UserFactory
I found that the correct way to add a path to sys.path when using the pathlib.Path is to convert it to a string:
sys.path.append(str(code_path / "tests"))
I'm a greenhorn, so go easy on me:
I've been trying to divide up a python project I was working on into smaller parts. To that end I created 4 Classes inside a single folder in VSCode, one being a main class that imports the other 3 and accesses their methods etc.
The structure is as following:
top_level_folder
|--lower_level_folder
|--class1.py
|--class2.py
|--class3.py
|--mainclass.py
Now my mainclass is supposed to import the other 3 classes, via
from top_level_folder.lower_level_folder import class1
etc.
However, doing it this way, I get a ModuleNotFound Error (no module named top_level_folder)
import class1
etc
results in a TypeError
and
import top_level_folder.lower_level_folder.class1 as x
doesn't work either
Is there something obvious I'm missing? Is it down to my VSC installation?
It depends. If you're running mainclass.py as your executable script, your import should look like this
mainclass.py
from class1 import MyClass
But if you're planning on importing the module from outside the folder, you'll either need an __init__.py file, or you would specify the folder name. I.e your file structure looks like this
top_level_folder
|--lower_level_folder
|--__init__.py
|--class1.py
|--class2.py
|--class3.py
|--mainclass.py
|--main.py
your would import like this
main.py
from mainclass import MyClass
mainclass.py
from lower_level_folder.class1 import MyClass2
__init__.py
from lower_level_folder.mainclass import MyClass
In python 2 I can create a module like this:
parent
->module
->__init__.py (init calls 'from file import ClassName')
file.py
->class ClassName(obj)
And this works. In python 3 I can do the same thing from the command interpreter and it works (edit: This worked because I was in the same directory running the interpreter). However if I create __ init __.py and do the same thing like this:
"""__init__.py"""
from file import ClassName
"""file.py"""
class ClassName(object): ...etc etc
I get ImportError: cannot import name 'ClassName', it doesn't see 'file' at all. It will do this as soon as I import the module even though I can import everything by referencing it directly (which I don't want to do as it's completely inconsistent with the rest of our codebase). What gives?
In python 3 all imports are absolute unless a relative path is given to perform the import from. You will either need to use an absolute or relative import.
Absolute import:
from parent.file import ClassName
Relative import:
from . file import ClassName
# look for the module file in same directory as the current module
Try import it this way:
from .file import ClassName
See here more info on "Guido's decision" on imports in python 3 and complete example on how to import in python 3.