directory structure
test/
__init__.py
line.py
test.py
test.py
from . import line
output:
Traceback (most recent call last):
File "test.py", line 1, in <module>
from . import line
ImportError: cannot import name 'line'
I know I can just import line. but it may import standard library in python3.
why did this error happen? does python3 support this syntax?
ps: I'm not in interactive console and test directory has already been a package
I'm not sure if you can import module with the same name as library utilities directly. However, you could consider putting your modules inside a package, so your directory structure would look like:
.
├── main.py
├── package
│ ├── __init__.py
│ ├── line.py
│ ├── test.py
Where __init__.py might have some setup commands (you can omit this file if you have none) and in main.py you can do the following:
from package import line
...
Within the directory package if you'd like to say, import line.py in test.py you can use the syntax:
from . import line
Note relative imports (using the from . notation) will only work inside the script and not in the interactive console. Running the test.py ( if it's using relative imports) directly will also not work, although importing it from main.py will work.
Related
I am writing a python 3.10 package with the following architecture:
pyce
├── docs
├── README.md
├── requirements.txt
├── setup.py
└── src
└── pyce
├── __init__.py
├── plot
│ ├── __init__.py
│ └── colormaps_lc.py
└── tools
├── __init__.py
└── lcmapping.py
All __init__.py files are empty. I have written the associated setup.py file:
from setuptools import find_packages, setup
setup(
name="pyce",
version="1.0",
packages=find_packages(where="src/"),
package_dir={"": "src"},
)
The problem I have is:
import pyce.tools as pytools
pytools.lcmapping
returns
AttributeError Traceback (most recent call last)
Cell In[1], line 2
1 import pyce.tools as pytools
----> 2 pytools.lcmapping
AttributeError: module 'pyce.tools' has no attribute 'lcmapping'
Similar issue if I do:
import pyce.tools as pytools
from pytools import lcmapping
returns
ModuleNotFoundError Traceback (most recent call last)
Cell In[2], line 2
1 import pyce.tools as pytools
----> 2 from pytools import lcmapping
ModuleNotFoundError: No module named 'pytools'
This is typically the issue mentioned here :
#the-submodules-are-added-to-the-package-namespace-trap
Also similar to this Stack 74487179
First solution
I tried from pyce.tools import lcmapping or import pyce.tools.lcmapping as lcmap and this works fine!
However I would like not to have to import every single module at the beginning of a script but rather do import pyce.tools as pytools and then do pytools.lcmapping along my scripts (with in mind the fact that I will have many modules in the sub-package).
Second solution
In each __init__.py files of my packages/sub-packages, import my sub-package/modules (respectively).
Detailed here: #packages, and it works!
Expected solution
I do not remember having this issue with python 3.7, the sub-packages/sub-modules were automatically found even with empty __init__.py files.
Would anyone know if I made a mistake in my setup.py file and/or project architecture? Or does this issues has something related to python 3.10 ?
Many thanks
I am struggling with importing local source files that reside in the same directory as main.py in Python 3.9. I had it working before but
couldn't tell why it was working. After a while it stopped working.
I created a minimal example to reproduce the problem with the structure shown below.
I have read some available answers that suggest using from . import car in main.py which resulted in the
following Error:
(venv) [.../pyimport_example/productname] python3 ./main.py
Traceback (most recent call last):
File "/Users/myUser/pyimport_example/productname/./main.py", line 1, in <module>
from . import car
ImportError: attempted relative import with no known parent package
Got the same error when using from .car import Car
I have also tried to run main.py as a module as suggested in "Relative imports in Python 3:
(venv) [.../pyimport_example/productname] python3 -m main.py
Traceback (most recent call last):
File "/usr/local/Cellar/python#3.9/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py", line 188, in _run_module_as_main
mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
File "/usr/local/Cellar/python#3.9/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py", line 111, in _get_module_details
__import__(pkg_name)
File "/Users/myUser/pyimport_example/productname/main.py", line 2, in <module>
from .car import Car
ImportError: attempted relative import with no known parent package
The answer to "Relative imports in Python 3 seems to focus on the case where one want to run a python file as a
script inside a package, which is not the problem I am having.
My sample project
pyimport_example
├── README.md
├── productname
│ ├── __init__.py
│ ├── car.py
│ └── main.py
└── venv
├── bin
├── include
├── lib
└── pyvenv.cfg
content of main.py
from .car import Car
def main():
print("Maria ist cool.")
mycar = Car("Ford", "Mustang", "1966")
mycar.print_car()
if __name__ == '__main__':
main()
contents of car.py
class Car:
def __init__(self, make, model, year_manufacture):
self.make = make
self.model = model
self.year_manufacture = year_manufacture
def print_model(self):
print("{0} {1} {2}".format(self.year_manufacture, self.make, self.model))
Is there a fix without modifying the system path?
You have to modify your __init__.py-File.
In the folder productname you wanna specify what imports you can run from a module on the same level:
from .car import *
Now you should be able to import your file into your main.py with:
from car import Car
Question
When I try to activate main.py on linux bash with the command as follows,
python3 main.py
The error message looking as below keeps appearing, and I cannot figure out why!!
File "main.py", line 1, in <module>
import folder_beta.util_one
File "folder_beta/util_one.py", line 1, in <module>
ModuleNotFoundError: No module named 'util_two'
Questions in more detail
The folder tree looks like as below:
folder_alpha
├── main.py
└── folder_beta
├── __init__.py (empty)
├── util_one.py
└── util_two.py
main.py
import folder_beta.util_one
import folder_beta.util_two
....
util_one.py
import util_two
...
When I executed the 'util_one.py' alone, it works perfectly fine but when I executed the main.py, the error keeps appearing.
Can anyone tell me how to fix this problem, please?
That is an implicit relative import, it would have worked in Python 2 but it's no longer allowed in Python 3. From PEP 8:
Implicit relative imports should never be used and have been removed in Python 3.
In util_one.py module, change it to:
from folder_beta import util_two
I have a Python project that uses the MicroKernel pattern where I want each of the modules to be completely independent. I import each of the modules into the kernel and that works fine. However, when I am in a module I want the root of the module to be the module dir. This is the part that is not working.
Project structure;
.
├── requirements.txt
├── ...
├── kernel
│ ├── config.py
│ ├── main.py
│ ├── src
│ │ ├── __init__.py
│ │ ├── ...
│ └── test
│ ├── __init__.py
│ ├── ...
├── modules
│ └── img_select
│ ├── __init__.py
│ ├── config.py
│ ├── main.py
│ └── test
│ ├── __init__.py
│ └── test_main.py
If I import from main import somefunction in modules/img_select/test/test_main.py I get the following error:
ImportError: cannot import name 'somefunction' from 'main' (./kernel/main.py)
So it clearly does not see the modules/img_select as the root of the module, which leads to the following question:
How can I set the root for imports in a module?
Some additional info, I did add the paths with sys.path in the config files;
kernel/config.py;
import os
import sys
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
MODULES_DIR = os.path.join(ROOT_DIR, '../modules')
sys.path.insert(0, os.path.abspath(MODULES_DIR))
modules/img_select/config.py;
import os
import sys
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.abspath(ROOT_DIR))
And my python version is 3.7.3
I do realise that there are a lot of excellent resources out there, but I have tried most approaches and can't seem to get it to work.
I'm not sure what main you are trying to import from. I think python is confused from the pathing as well. How does test_main.py choose which main to run? Typically when you have a package (directory with __init__.py) you import from the package and not individual modules.
# test_main.py
# If img_select is in the path and has __init__.py
from img_select.main import somefunction
If img_select does not have __init__.py and you have img_select in the path then you can import from main.
# test_main.py
# If img_select is in the path without __init__.py
from main import somefunction
In your case I do not know how you are trying to indicate which main.py to import from. How are you importing and calling the proper config.py?
You might be able to get away with changing the current directory with os.chdir. I think your main problem is that img_select is a package with __init__.py. Python doesn't like to use from main import ... when main is in a package. Python is expecting from img_select.main import ....
Working Directory
If you are in the directory modules/img_select/test/ and call python test_main.py then this directory is known as your working directory. Your working directory is wherever you call python. If you are in the top level directory (where requirements.txt lives) and call python modules/img_select/test/test_main.py then the top level directory is the working directory. Python uses this working directory as path.
If kernel has an __init__.py then python will find kernel from the top level directory. If kernel is not a package then you need add the kernel directory to the path in order for python to see kernel/main.py. One way is to modify sys.path or PYTHONPATH like you suggested. However, if your working directory is modules/img_select/test/ then you have to go up several directories to find the correct path.
# test_main.py
import sys
TEST_DIR = os.path.dirname(__file__) # modules/img_select/test/
IMG_DIR = os.path.dirname(TEST_DIR)
MOD_DIR = os.path.dirname(IMG_DIR)
KERNEL_DIR = os.path.join(os.path.dirname(MOD_DIR), 'kernel')
sys.path.append(KERNEL_DIR)
from main import somefunction
If your top level directory (where requirements.txt lives) is your working directory then you still need to add kernel to the path.
# modules/img_select/test/test_main.py
import sys
sys.path.append('kernel')
As you can see this can change depending on your working directory, and you would have to modify every running file manually. You can get around this with abspath like you are doing. However, every file needs the path modified. I do not recommend manually changing the path.
Libraries
Python pathing can be a pain. I suggest making a library.
You just make a setup.py file to install the kernel or other packages as a library. The setup.py file should be at the same level as requirements.txt
# setup.py
"""
setup.py - Setup file to distribute the library
See Also:
* https://github.com/pypa/sampleproject
* https://packaging.python.org/en/latest/distributing.html
* https://pythonhosted.org/an_example_pypi_project/setuptools.html
"""
from setuptools import setup, Extension, find_packages
setup(name='kernel',
version='0.0.1',
# Specify packages (directories with __init__.py) to install.
# You could use find_packages(exclude=['modules']) as well
packages=['kernel'], # kernel needs to have __init__.py
include_package_data=True,
)
The kernel directory needs an __init__.py. Install the library as editable if you are still working on it. Call pip install -e . in the top level directory that has the setup.py file.
After you install the library python will have copied or linked the kernel directory into its site-packages path. Now your test_main.py file just needs to import kernel correctly
# test_main.py
from kernel.main import somefunction
somefunction()
Customizing init.py
Since kernel now has an __init__.py you can control the functions available from importing kernel
# __init__.py
# The "." indicates a relative import
from .main import somefunction
from .config import ...
try:
from .src.mymodule import myfunc
except (ImportError, Exception):
def myfunc(*args, **kwargs):
raise EnvironmentError('Function not available. Missing dependency "X".')
After changing the __init__.py you can import from kernel instead of kernel.main
# test_main.py
from kernel import somefunction
somefunction()
If you delete the NumPy (any library) from the site manager and save that folder in another location then use:
import sys
sys.path.append("/home/shubhangi/numpy") # path of numpy dir (which is removed from site manager and paste into another directory)
from numpy import __init__ as np
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
print(arr)
print(type(arr))
I have the following file structure:
bot
├── LICENSE.md
├── README.md
├── bot.py # <-- file that is executed from command line
├── plugins
│ ├── __init__.py
│ ├── debug.py
│ └── parsemessages.py
├── helpers
│ ├── __init__.py
│ ├── parse.py
│ └── greetings.py
└── commands
├── __init__.py
└── search.py
bot.py, when executed from the command line, will load in everything in the plugins directory.
I want plugins/parsemessages.py to import parse from the helpers directory, so I do that:
# parsemessages.py
from ..helpers import parse
parse.execute("string to be parsed")
I run python3 bot.py from the command line.
I get the following error:
File "/home/bot/plugins/parsemessages.py", line 2, in <module>
from ..helpers import parse
ValueError: attempted relative import beyond top-level package
So I change two dots to one:
# parsemessages.py
from .helpers import parse
parse.execute("string to be parsed")
...but I get another error:
File "/home/bot/plugins/parsemessages.py", line 2, in <module>
from .helpers import parse
ImportError: No module named 'plugins.helpers'
How can I get this import to work?
It's worth noting that I'm not attempting to make a package here, this is just a normal script. That being said, I'm not willing to mess around with sys.path - I want this to be clean to use.
Additionally, I want parse to be imported as parse - so for the example above, I should be typing parse.execute() and not execute().
I found this post and this post, but they start with a file that's quite deep in the file structure (mine is right at the top). I also found this post, but it seems to be talking about a package rather than just a regular .py.
What's the solution here?
You could remove the dots, and it should work:
# parsemessages.py
from helpers import parse
parse.execute("string to be parsed")
That's probably your best solution if you really don't want to make it a package. You could also nest the entire project one directory deeper, and call it like python3 foo/bot.py.
Explanation:
When you're not working with an actual installed package and just importing stuff relative to your current working directory, everything in that directory is considered a top-level package. In your case, bot, plugins, helpers, and commands are all top-level packages/modules. Your current working directory itself is not a package.
So when you do ...
from ..helpers import parse
... helpers is considered a top-level package, because it's in your current working directory, and you're trying to import from one level higher than that (from your current working directory itself, which is not a package).
When you do ...
from .helpers import parse
... you're importing relative to plugins. So .helpers resolves to plugins.helpers.
When you do ...
from helpers import parse
... it finds helpers as a top-level package because it's in your current working directory.
If you want to execute your code from the root, my best answer to this is adding to the Path your root folder with os.getcwd().
Be sure your sibling folder has a init.py file.
import os
os.sys.path.insert(0, os.getcwd())
from sibling import module