How to import relative module from __main__ in python - python

I have two file
foo.py
main.py
while executing python main.py, I want main.py to import foo.py.
I tried
from . import foo
But python complains
Attempted relative import beyond top-level package
I also tried
from foo import func_name
It works, but that means I can only directly import what get exposed. I want to use it like foo.func_name
Is it possible to import the whole module in a relative way (regardless what the current working directory is)?

The script directory is already a part of the import path. Simply use
import foo

Related

import error attempting to import from the directory above

Not a python developer and I am clearly missing something fundamental here. Using Python 3.10.7 and i am getting an error:
from ..class_one import ClassOne
ImportError: attempted relative import beyond top-level package
when attempting to execute python run_me.py script in the example below
I have the following structure with following import statements
\Project
\data_processor
data_process.py
from ..class_one import ClassOne <--getting an error here
run_me.py
from data_processor.data_process import DataProcess
class_one.py
interesting that when i type a line from ..class_one import ClassOne in data_process.py my IDE thinks its completely legit and intellisence works, suggesting that i import ClassOne.
Most of the solutions imply Python earlier than v3.3 (changed the way packages are handled), which isn't the case here.
Python does not allow relative imports beyond the top-level package. This is why you are seeing the ImportError: attempted relative import beyond top-level package error...
Try to use absolute import, like this:
from Project.class_one import ClassOne
You can also move the class_one module to a package within the current project, you can create a new package and move the class_one module to it. Then, you can use a relative import to import the ClassOne module:
\Project
\data_processor
data_process.py
from my_package.class_one import ClassOne
run_me.py
from data_processor.data_process import DataProcess
\my_package
class_one.py
Finally, it's not recommended (complexity, cause confusion and difficulty to read the code) but I think you can try to use a 'sys.path' to add the parent directory to the Python path. I think it will allow you to use a relative import:
import sys
sys.path.insert(0, '..')
from class_one import ClassOne
Why you get that error?
Remember relative imports are resolved using __package__ variable(I'm talking about ..class_one). Add a simple print statement in your data_process.py to see the value of this variable:
print(__package__)
You're in Project folder and you run python run_me.py, so this variable must be: 'data_processor'. So you can't go beyond "one" level up. (It follows the dots as we see next).
When you can go one level up?
In run_me.py change your import statement from:
from data_processor.data_process import DataProcess
to
from Project.data_processor.data_process import DataProcess
Before running your script, we need to tell Python where to find Project folder. It doesn't know right now! We are in Project directory and there is no Project directory in where we are. So just add it to the sys.path in run_me.py:
import sys
sys.path.insert(0, PATH TO PARENT OF Project DIRECTORY)
Now run your command -> python run_me.py. Every thing works fine.
Did you notice the value of __package__? It's now 'Project.data_processor'. We went one level down, so we can go one level up .( As I said, it follows the dots.)
That was the reason. But what you can do now?
I think the most simple solution is to just stick with absolute imports. If you know in which directory you are and check the records in sys.path(Add to the paths if necessary), you won't get into problems.
You can manually hack __package__ which I do not recommend. To do so, add:
__package__ = "Project.data_processor"
at the top in your data_process.py file. Then add this to the run_me.py
import sys
sys.path.insert(0, PATH TO PARENT OF Project DIRECTORY)
This way you don't need to change your original import statement. That from data_processor.data_process import DataProcess just works.
For this option, you don't need to hack __package__ nor adding any path to the sys.path. Just change your import statement from:
from data_processor.data_process import DataProcess
to
from Project.data_processor.data_process import DataProcess
But for executing your command, you should go to the parent directory and run your script like:
python -m Project.run_me

I need help setting up my relative imports in python

I have spent so many hours trying out different answers on stack overflow that i no longer know what exactly is the proper way to use relative imports. Keep in mind this import should work on localhost and on a server
My project structure
init.py
Attempts to import Authenticate class in main.py result into ImportError: attempted relative import with no known parent package
Kindly give an explanation or links with working examples of importing in the same directory.
You are trying to import a Jupyter Notebook, not a class. This is why you get the ImportError.
Have a look at this: ipynb import another ipynb file
If you do not want to import from a Jupyter Notebook but from a module in a specified path you can try this:
import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()
You can also use relative import:
from foo import bar
Another option is to add a path to sys.path (over using import) to simplify things when importing more than one module from a single package:
import sys
# my_package dir contains mod_one.py, mod_two.py and mod_three.py
sys.path.append('/foo/bar/my_package')
from mod_one import foo
from mod_two import bar
from mod_three import foobar

How to Correctly Import Python Modules and Avoid Import Errors

I have a custom python module I'm working on and am confused how I should import modules into other modules. I want to use bits and pieces of some modules within others and keep getting an error: ImportError: cannot import name NameOfModule
I'm assuming there's some sort of circular reference that's causing the issue but I'm not sure if I need to add something to __init__.py, or if there's a specific way of importing the modules into each other, or if I should change my folder structure?
If I want to be able to use some function from mod1.py within mod2.py how should I go about setting up the import statements?
My current folder structure is:
FolderName
-__init__.py
-mod1.py
-mod2.py
-mod3.py
-mod4.py
Sample code:
__init__.py is empty
mod1.py: from . import mod2
mod2.py: from . import mod1
You should be using relative imports for files within the current module, like so:
from . import mod2
Or:
from .mod2 import foo
And unless you have a VERY good reason, you should be using Python 3.

dot_module and dot_dot_module when import module

I see many people use the following import methods in their projects:
from .module1 import a,b
from ..module2 import *
The module1 and module2 are a .py file but not a folder for package. What's the differences to the import module? Does it mean to import the module in current and ../ folder? But when I try to import another file in same folder, it said:
import .other
>>> SyntaxError: Invalid syntax
from .other import *
>>> ValueError: Attempted relative import in non-package
I'm curious on it. Thanks~
What you see is relative imports. They allow you to import modules by specifying their relative paths, without hard-coding the name of the package in which the modules are defined.
Does it mean to import the module in current and ../ folder?
Yes.
See PEP 328 for more details. Note it says:
Relative imports must always use from <> import; import <> is always
absolute.
which is why you get the SyntaxError when trying import .foo.
The ValueError is probably because you are running the importing file as a script (and it used to confuse me a lot). You need to run it as a package (using the -m switch) for relative imports to work. That is, suppose foo.py relative-imports other modules, you can't run it by
$ python foo.py # non-package error
Instead you do
$ python -m foo
See the related question: How to do relative imports in Python.

trying to import a *.pyc as a module

I have a python script that is trying to import another script somewhere in the file-system (path is only known at runtime).
To my understanding I need to use the imp module and this might work, but when loading the module I get an error that modules used by the imported module are not found.
Heres the code:
importer.py:
import imp
imp.load_compiled("my_module","full_path_to_my_module\\my_module.pyc")
my_module.py:
import sys
import another_module
When I run importer.py I get htis error message:
ImportError: No module named another_module
Whats going wrong here ?
I suspect that when 'importer.py' is loading 'my_module.pyc' hes also trying to load 'another_module' (thats good) but is looking in the wrong place (eg not 'full_path_to_my_module')
EDIT:
I tried adding 'full_path_to_my_module' to the system path:
import imp
import sys
sys.path.append(full_path_to_my_module)
imp.load_compiled("my_module",full_path_to_my_module+my_module)
But I still get the same error
Maybe I do something thats not necessary - Here's my goal:
I want to be able to use all functionality of 'my_module.pyc' inside 'importer.py'. But the location of 'my_module.pyc' is given as a parameter to 'importer.py'.
imp.load_compiled returns the compiled module object, it is different to the import statement which also binds the module to a name
import imp
my_module = imp.load_compiled("my_module", "full_path_to_my_module/my_module.pyc")
Then you can do something like:
my_module.yayfunctions('a')
Complete example session:
$ cat /tmp/my_module.py
def yayfunctions(a):
print a
$ python -m compileall /tmp/my_module.py
$ ls /tmp/my_module.py*
my_module.py my_module.pyc
$ python
>>> import imp
>>> my_module = imp.load_compiled("my_module", "/tmp/my_module.pyc")
>>> my_module.yayfunctions('a')
a
Edit regarding comment (ImportError: No module named another_module), I assume the error is caused by the code in my_module.pyc, and the another_module.py lives in the same directory
In that case, as others have suggested, it's simpler to just add the directory containing my_module to sys.path and use the regular import mechanism, specifically __import__
Here's a function which should do what you want:
import os
def load_path(filepath):
"""Given a path like /path/to/my_module.pyc (or .py) imports the
module and returns it
"""
path, fname = os.path.split(filepath)
modulename, _ = os.path.splitext(fname)
if path not in sys.path:
sys.path.insert(0, path)
return __import__(modulename)
if __name__ == '__main__':
# Example usage
my_module = load_path('/tmp/my_module.py')
my_module.yayfunctions('test')
It is since at the scope of import another_module your "full_path_to_my_module" isn't known.
Have you tried to add the path to known paths instead, i.e.:
import sys
sys.path.append("full_path_to_my_module")
You don't actually need to use the imp module to load pyc modules.
An easy way to try it out is to make two python modules, one importing from the other and run it. Delete then the imported .py file so you only get the .pyc file left: when running the script the import will work just fine.
But, for importing py files from random directories, you may want to add that directory to the python path first before importing it.
For instance:
import sys
sys.path.insert(0, "/home/user/myrandomdirectory")
Loading pyc files works the exact same way as loading a py file except it doesn't do a compile step. Thus just using import mymodule will work as long as the version number of the pyc is the same as the python you're running. Otherwise you'll get a magic number error.
If you module isn't in your path you'll need to add that to sys -- or if its a subdirectory, add a __init__.py file to that directory..

Categories