Python imports with __init__.py in a sibling directory - python

My directory structure looks like this:
- scripts
- script.py
- app
- foo
- connect.py
- bar
- __init__.py
- random.py
The __init__.py file in bar/ looks like
from bar.random import Random
__all__ = [ "Random" ]
and connect.py has an import
from bar import Random
I'm trying to execute script.py from the root directory via python scripts/script.py which is attempting to import from foo.py
from os import getcwd
from sys import path
path.append(getcwd())
from app.foo.connect import Connect
and getting:
Traceback (most recent call last):
File "scripts/script.py", line 19, in <module>
from app.foo.connect import Connect
File "/home/user/project/app/foo/connect.py", line 17, in <module>
from bar import Random
ModuleNotFoundError: No module named 'bar'
When running the app through its main, everything works. But when trying to execute a specific script attempting to import from a subdirectory in app/ I get the traceback.
What am I doing wrong?

The correct import of Random in connect.py is from app.bar.random import Random.
Also include __init__.py file in the app folder and connect folder.
You also do not need the __all__ statement in the one __init__.py file you have. All the __init__.py files can be left blank.

Related

Cannot import Python module in same package

I have a Python 3.9.2 project with the following directory structure:
lib/
├─ mod1.py
├─ mod2.py
├─ __init__.py
main.py
In /main.py, I have from lib import mod1. In /lib/mod1.py, I have import mod2. When I run /main.py, I receive the following error:
Traceback (most recent call last):
File "/main.py", line 1, in <module>
from lib import mod1
File "/lib/init.py", line 1, in <module>
import mod2
ModuleNotFoundError: No module named 'mod2'
Why is this happening? When I change the code in /lib/mod1.py to say from lib import mod2, the code works fine, but I don't understand why that fixes it. Shouldn't I be able to import /lib/mod2.py the way I originally tried, since both mod1.py and mod2.py are in the same directory?
In /lib/mod1.py, you probably want to do:
# relative import - entire module
from . import mod2
# relative import - specific piece
from .mod2 import foo
or
# absolute import - entire module
from lib import mod2
# absolute import - specific piece
from lib.mod2 import foo
The correct way to import things is really tricky in Python because it depends on where you run the script from.
If you run the code from the root directory, import mod2 causes problems, but
If you were to run /lib/mod1.py (say it were run-able) from inside lib, then import mod2 would be correct and the alternatives above would cause errors.

Python gives relative import error for package? [duplicate]

This question already has answers here:
Relative imports for the billionth time
(12 answers)
Closed 2 years ago.
I can't for the life of me get python's relative imports to work. I have created a simple example of where it does not function:
The directory structure is:
__init__.py
start.py
parent.py
sub/
__init__.py
relative.py
/start.py contains just: import sub.relative
/sub/relative.py contains just from .. import parent
All other files are blank.
When executing the following on the command line:
$ cd /
$ python start.py
I get:
Traceback (most recent call last):
File "start.py", line 1, in <module>
import sub.relative
File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
from .. import parent
ValueError: Attempted relative import beyond toplevel package
I am using Python 2.6. Why is this the case? How do I make this sandbox example work?
You are importing from package "sub". start.py is not itself in a package even if there is a __init__.py present.
You would need to start your program from one directory over parent.py:
./start.py
./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py
With start.py:
import pkg.sub.relative
Now pkg is the top level package and your relative import should work.
If you want to stick with your current layout you can just use import parent. Because you use start.py to launch your interpreter, the directory where start.py is located is in your python path. parent.py lives there as a separate module.
You can also safely delete the top level __init__.py, if you don't import anything into a script further up the directory tree.
If you are going to call relative.py directly and i.e. if you really want to import from a top level module you have to explicitly add it to the sys.path list.
Here is how it should work:
# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')
# Now you can do imports from one directory top cause it is in the sys.path
import parent
# And even like this:
from parent import Parent
If you think the above can cause some kind of inconsistency you can use this instead:
sys.path.append(sys.path[0] + "/..")
sys.path[0] refers to the path that the entry point was ran from.
Checking it out in python3:
python -V
Python 3.6.5
Example1:
.
├── parent.py
├── start.py
└── sub
└── relative.py
- start.py
import sub.relative
- parent.py
print('Hello from parent.py')
- sub/relative.py
from .. import parent
If we run it like this(just to make sure PYTHONPATH is empty):
PYTHONPATH='' python3 start.py
Output:
Traceback (most recent call last):
File "start.py", line 1, in <module>
import sub.relative
File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
from .. import parent
ValueError: attempted relative import beyond top-level package
If we change import in sub/relative.py
- sub/relative.py
import parent
If we run it like this:
PYTHONPATH='' python3 start.py
Output:
Hello from parent.py
Example2:
.
├── parent.py
└── sub
├── relative.py
└── start.py
- parent.py
print('Hello from parent.py')
- sub/relative.py
print('Hello from relative.py')
- sub/start.py
import relative
from .. import parent
Run it like:
PYTHONPATH='' python3 sub/start.py
Output:
Hello from relative.py
Traceback (most recent call last):
File "sub/start.py", line 2, in <module>
from .. import parent
ValueError: attempted relative import beyond top-level package
If we change import in sub/start.py:
- sub/start.py
import relative
import parent
Run it like:
PYTHONPATH='' python3 sub/start.py
Output:
Hello from relative.py
Traceback (most recent call last):
File "sub/start.py", line 3, in <module>
import parent
ModuleNotFoundError: No module named 'parent'
Run it like:
PYTHONPATH='.' python3 sub/start.py
Output:
Hello from relative.py
Hello from parent.py
Also it's better to use import from root folder, i.e.:
- sub/start.py
import sub.relative
import parent
Run it like:
PYTHONPATH='.' python3 sub/start.py
Output:
Hello from relative.py
Hello from parent.py

Import error with unit tests: "No module named ..." from local libary

I'm new to Python (JS developer) and am trying to run a testing suite. My project folder structure is as such:
project/
__init__.py
libs/
__init__.py
s3panda.py
tests
__init__.py
tests_s3panda.py
In terminal, I'm running python tests_s3panda.py.
I don't understand how it's unable to find a local module:
Traceback (most recent call last): File "tests_s3panda.py", line 7,
in
from libs.s3panda import S3Panda ImportError: No module named libs.s3panda
tests_s3panda.py snippet:
from __future__ import absolute_import
import unittest
import pandas as pd
from libs.s3panda import S3Panda
class TestS3Panda(unittest.TestCase):
...
Doing from ..libs.s3panda import S3Panda for relative path, I get:
ValueError: Attempted relative import in non-package
I believe the fact that there is no init.py in the top-level folder means that Python is not aware that libs and tests are both part of the same module called project.
Try adding an __init__.py to your project folder, then write the import statement as from project.libs.s3panda import S3Panda. In general, you want to specify absolute imports rather than relative imports (When to use absolute imports).

how to import file.py from main folder if you are working in a subfolder python3

I have a structure such has:
/mainfolder
file.py
//subfolder
test.py
I am trying to import file.py in test.py. for some reason I just can't.
I tried
from .file import *
returning :
Traceback (most recent call last):
ModuleNotFoundError: No module named '__main__.file'; '__main__' is not a package
also tried to add path to sys.path:
import sys
import os
sys.path.extend([os.getcwd()])
doesnt work either
Looks like you're running test.py with python test.py and as such the test module is being treated as a top level module.
You should first make your folders Python packages if they are not by adding __init__.py files:
/mainfolder
__init__.py
file.py
/subfolder
__init__.py
test.py
Then you can append the outer mainfolder to sys.path:
import sys
import os
sys.path.append(os.path.join(os.getcwd(), '..'))
After which from file import someobject without relative import works. Be wary of wild card imports.
See ModuleNotFoundError: What does it mean __main__ is not a package? and How to do relative imports in Python? for more on why your current approach does not work.
What IDE are you using? I am using Pycharm Community IDE with Python 3 and it works with from file import * or from file import some_function (I wanted to comment but I can't since I don't have 50 reputation yet)

When automatically importing modules from a subfolder, their imports fail

I've read through a couple of similar questions, notably this one about imp.load_module which seems to be close to what I want, but I can't understand why I'm still getting ImportErrors. Here is my folder hierarchy:
program\
__init__.py
main.py
thirdparty\
__init__.py
css\
__init__.py
css.py
utils\
__init__.py
http.py
In main.py I have the following code. This is intended to search the thirdparty\ directory and load each module it finds. Each module is in its own separate directory.
import os
import imp
for root, dirs, files in os.walk("thirdparty"):
for source in (s for s in files if s.endswith(".py")):
name = os.path.splitext(os.path.basename(source))[0]
m = imp.load_module(name, *imp.find_module(name, [root]))
The problem is that css.py happens to use its own subfolder that it loads stuff off of, utils. It has a line in it that says:
from utils import http
And that is where it fails. I get this error when I run main.py.
Traceback (most recent call last):
File "main.py", line 7, in <module>
m = imp.load_module(name, *imp.find_module(name, [root]))
File "thirdparty/css/css.py", line 1, in <module>
from utils import http
ImportError: No module named utils
I'm stumped. css.py is self contained in its own folder, and when I run css.py separately it imports utils just fine. What is causing this?
Maybe you can solve this by changing the import to:
from .utils import http
Or by adding the folder you import to the Python Path:
sys.path.append(os.path.join(root, source))
When you import modules in thirdparty, the place Python looks for modules is still the main directory. The initial import works, because you give the right path to imp.find_module, but after that Python has no idea where to look for the modules.

Categories

Resources