Importing files from sibling directory - python

I need to run unit tests for my Flask app. In my test config file, I need to import the flask create_app function from a sibling directory to initialize the test app. I cannot figure it out without getting import errors.
I have tried putting __init__.py on virtually every folder without success. I have read that editing the sys path is not recommended so I would like a solution without.
Folder Structure
root/
----__init__.py
----server/
--------__init__.py
--------database.py
----tests/
--------__init__.py
--------config.py
config.py
from server import create_app
from server.database import db
Raises this error:
Traceback (most recent call last):
File "tests/config.py", line 2, in <module>
from server import create_app
ModuleNotFoundError: No module named 'server'
and:
from ..server import create_app
from ..server.database import db
Raises this error:
Traceback (most recent call last):
File "tests/config.py", line 2, in <module>
from ..server import create_app
ValueError: attempted relative import beyond top-level package
Can someone explain why it doesn't work and how python imports work in general? I have never been able to figure them out.

For an import statement to work correctly, names must be resolved in sys.path somehow. Creating a correct package structure and installing the package is usually the best way to get the names visible in sys.path.
Remove root/__init__.py and tests/__init__.py
Correct your import statements:
from ..server import create_app # no
from server import create_app # yes
Add root/setup.py with contents as described in setuptools basic guide.
Create/activate virtualenv (usually in root/.venv/ subdir, but doesn't really matter where)
From the project root, i.e. the directory containing setup.py, install your package:
pip install --editable .

Related

Cannot import modules from other folders

I am currently having an issue with importing files from other directories in my python project.
My current file structure is
Project
- Backend
- Config
+ __init__.py
+ databaseConfig.py
- DataAccess
+ __init__.py
+ sqlConns.py
- __init__.py
- api.py
- main.py
- setup.py
What I am trying to do is import /Config/databaseConfig.py file into /DataAccess/sqlConns.py file. I get the following error when trying to run the sqlConns.py file
PS C:\source\repos\aaStats\aaStats> py .\Backend\DataAccess\sqlConns.py
Traceback (most recent call last):
File "C:\source\repos\aaStats\aaStats\Backend\DataAccess\sqlConns.py", line 2, in <module>
import Config.databaseConfig
ModuleNotFoundError: No module named 'Config'
I have also tried using relative imports, but I am met with another error.
PS C:\source\repos\aaStats\aaStats> py .\Backend\DataAccess\sqlConns.py
Traceback (most recent call last):
File "C:\source\repos\aaStats\aaStats\Backend\DataAccess\sqlConns.py", line 2, in <module>
from ..Config import databaseConfig as dbcfg
ImportError: attempted relative import with no known parent package
Config/databaseConfig.py contains database configuration parameters that I want to reference is various places in my project. It isn't a huge deal if I had to move this single file in order to get it to be referenced properly, but I will want to use structures like this for files later on in my project.
Here are some details about my files:
/Config/__init__.py
from . import databaseConfig
/DataAccess/__init__.py
from . import sqlConns
Backend/__init__.py
from . import DataAccess
from . import Config
Backend/setup.py
from setuptools import setup, find_packages
setup(
name='aaStatsApi',
version='0.1.0',
packages= ['DataAccess','Config'],
install_requires=[
'fastapi==0.63.0',
'uvicorn==0.13.4',
'requests==2.25.1',
'pyodbc==4.0.30',
]
)
Check out this post.
The fact that you can't perform relative imports so easily is by design, for better or for worse. The ideal way is have your main script in the root (Backend) directory and do all your calls from there. The function that has __name__ == __main__ is your calling function. If you do not directly call Calls.py or Configs.py from a console, but are calling them from another main function within your root directory, you should be able to place the following into Conns.py:
# FILE: DataAcess\sqlConns.py
from Config.dataBaseConfig import * # or whatever you need to import
Again, the key is to ensure that your starting point in from your root project directory.
NOT RECOMMENDED:
For risk of getting downvoted, and I do not recommend this, but you could append the relative path to your calling class:
import sys, os
sys.path.append(os.path.abspath("../Config"))
from sqlConns import * # or whatever
sys.path.pop() # clear sys.path

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).

ImportError trying to import __init__.py from root of package

My project is structured as a package like so,
cred/
LICENSE
setup.py
cred/
__init__.py
runserver.py
resources/
__init__.py
event.py
In my cred/cred/__init__.py I have some code that creates various variables, used throughout the package (like app, api and db).
I can successfully import these by using from cred import app, api, db from inside the python files in the resources folder, but for some reason I get,
$ python cred/runserver.py
Traceback (most recent call last):
File "cred/runserver.py", line 1, in <module>
from cred import app, api, db, initDB
ImportError: No module named 'cred'
when doing from cred import app, api, db inside runserver.py.
I have no idea what to do to fix it, so any help would be appreciated :/...
Update
I have no idea what changed, but when I got back to working on the project, it ran as expected. I suspect some cache or something else in my environment was messing with it :/... Thanks to #rfkortekaas for giving his time to try and answer though!
You need to give the subfolder to the import as resources is not on the python path.
from cred.resources import app

gobject-introspection overrides cause import errors

I am using gobject-introspection in python2.7 on ubuntu raring and I run into an import error while building some packages. I have isolated a minimal set of steps to replicate it:
Make a local directory structure:
gi:
__init__.py
overrides:
__init__.py
Put the standard boilerplate
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
print __path__, __name__
in both __init__.py files.
From the directory containing your local copy of gi, run the following:
python -c "from gi import repository"
I get an error message that looks like:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/gi/repository/__init__.py", line 25, in <module>
from ..importer import DynamicImporter
File "/usr/lib/python2.7/dist-packages/gi/importer.py", line 28, in <module>
from .module import DynamicModule
File "/usr/lib/python2.7/dist-packages/gi/module.py", line 37, in <module>
from .overrides import registry
ImportError: cannot import name registry
Any explanation? I can't find any decent documentation of the intended behavior because gobject-introspection seems like a very poorly documented project. Help is greatly appreciated!
From the Python documentation:
The __init__.py files are required to make Python treat the
directories as containing packages; this is done to prevent
directories with a common name, such as string, from unintentionally
hiding valid modules that occur later on the module search path.
Simply by having those __init__.py files accessible from the running directory, you are telling the interpreter that that is an implementation of the gi module. Any usage of the main gi module will not go correctly.
Now, why does it print the error as coming from /usr/lib ? Because gi was found in local/gi, but gi.repository was found in /usr/lib/python2.7/dist-packages/gi/repository . It is running /usr/lib/python2.7/dist-packages/gi/repository/__init__.py. From there, it imports some other submodules correctly, but when it tries to import overrides it finds your local stub in gi/overrides. Your stub does not define registry, so you have the fail.
Try and put registry='dumb_string' in gi/overrides/__init__.py and see that the error is gone.

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