On my development (Win7) machine, my app runs fine. The folder structure looks like this (the script being run is run.py below):
package1/
__init__.py
run.py
..
Inside the app, there are some modules which do stuff like
import app from package1
Which works fine.
However, when I try deploying to a linux machine, and run that exact same file, I get an error:
ImportError: No module named package1
I looked into the sys.path of both machines when this script is being run. The first two lines of the windows machine are these:
C:\\Users\\USERNAME\\IdeaProjects\\PROJ_NAME\\package1
C:\\Users\\USERNAME\\IdeaProjects\\PROJ_NAME
Whereas the linux one only has this:
/home/username/webapps/PROJ_NAME/package1
I recognize the problem is that the second line is missing. But why is it missing? What am I missing? Did I build the folder structure wrong?
This is a crappy solution, and I don't like it, but it works.
I added this to run.py
# Fixing the python path
import sys
import os
file_location = os.path.dirname(os.path.abspath(__file__))
project_dir = os.path.abspath(os.path.join(file_location, os.pardir))
if not project_dir in sys.path:
sys.path.insert(0, project_dir)
Related
I am running a Flask server in Docker and cannot import create_app from app.py into my integration tests. I've tried a variety of naming approaches but Python is unable to find app.py.
The directory structure is as follows
/server
/test/integration/test.py
app.py
test.py has this import
from app import create_app
I tried relative imports as well but there was a "parent" error. I then played around with empty __init__.py files in an attempt to use relative imports. That didn't work. I am not sure why this is so involved to do really. What is the solution for this?
In test.py add:
# some_file.py
import sys
# caution: path[0] is reserved for script path (or '' in REPL)
sys.path.insert(1, '/path/to/app/folder')
import app
from app import create_app
This add the directory of the source file to the system so Python will know to go there when searching the things to import. This is true when both files are local on your computer. If there is a server you need to see how you modify the in-server Python environment to know the folder of the app.py file.
See: Importing files from different folder
You can try with relative imports
from ..app import create_app
My apps are organized like this:
apps/
code/
libglobal/
funglobal.py
tests/
project/
liblocal/
funlocal.py
main.py
In main.py I have:
import liblocal.funlocal
In funlocal.py I try to import funglobal.py with:
from ....code.libglobal import funglobal
When I run
python3 -B tests/project/main.py
I get an error:
from ....code.libglobal import funglobal
ValueError: attempted relative import beyond top-level package
I have read a lot of information about relative imports with python3 and still don't find how to solve this error without changing the apps organization radically. Any solution?
As the script being executed has its __name__ set as __main__ and defines itself to be on the top level of the package, it refuses to recognize scripts in sibling directories.
You can fix this with a sys.path hack:
import sys, os
sys.path.insert(0, os.path.abspath('../..'))
or an interseting alternative with setuptools is presented in this answer.
Have you a __init__.py script in each folder ?
If no, you should create an empty script named __init__.py in each folder.
My directory structure is:
project_folder/
..my_project/
....server/
......server.py
......api.py
When I'm in the project_folder and run python3 my_project/server/server.py, I get ModuleNotFoundError: No module named 'my_project' with the line of code:
from my_project.server.api import app as application
Weirdly, when I run my tests with Pytest everything passes. I've been trying to solve my problem without using this code snippet, which I always see recommended to solve these problems:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
Any tips?
The module you try to call is already in the same package, so just do
from api import app as application
Add an empty __init__.py file in my_project and server folders.
run this cd my_project/server/ and then python server.py
Or remove this line from server.py import my_project
And if you are trying to make a module add __init__.py to your server dir
I have the following directory structure:
application
tests
main.py
main.py
application/main.py contains some functions.
tests/main.py will contain my tests for these functions but I can't import the top level main.py. I get the following error:
ImportError: Import by filename is not supported.
I am attempting to import using the following syntax:
import main
What am I doing wrong?
If you'd like your script to be more portable, consider finding the parent directory automatically:
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# import ../db.py
import db
You must add the application dir to your path:
import sys
sys.path.append("/path/to/dir")
from app import object
Or from shell:
setenv PATH $PATH:"path/to/dir"
In case you use windows:
Adding variable to path in windows.
Or from the command line:
set PATH=%PATH%;C:\path\to\dir
Please mind the diff between PYTHONPATH, PATH, sys.path.
Late to the party - most other answers here are not correct unfortunately - apart LennartRegebro's (and BrenBarn's) which is incomplete. For the benefit of future readers - the OP should, first of all, add the __init__.py files as in
root
application
__init__.py
main.py
tests
__init__.py
main.py
then:
$ cd root
$ python -m application.tests.main
or
$ cd application
$ python -m tests.main
Running a script directly from inside its package is an antipattern - the correct way is running with the -m switch from the parent directory of the root package - this way all packages are detected and relative/absolute imports work as expected.
First of all you need to make your directories into packages, by adding __init__.py files:
application
tests
__init__.py
main.py
__init__.py
main.py
Then you should make sure that the directory above application is on sys.path. There are many ways to do that, like making the application infto a package and installing it, or just executing things in the right folder etc.
Then your imports will work.
You cannot import things from parent/sibling directories as such. You can only import things from directories on the system path, or the current directory, or subdirectories within a package. Since you have no __init__.py files, your files do not form a package, and you can only import them by placing them on the system path.
To import a file in a different subdirectory of the parent directory, try something like this:
sys.path.append(os.path.abspath('../other_sub_dir'))
import filename_without_py_extension
Edit: Missing closing bracket.
in python . exists for same directory, .. for parent directory
to import a file from parent directory you can use ..
from .. import filename (without .py extension)
In my home directory, I have a folder called local. In it, there are files called __init__.py and local_settings.py. My django app is in a completely different directory. When the app is NOT running in DEBUG mode, I want it to load the local_settings.py file. How can this be acheived? I read the below:
Import a module from a relative path
Importing files from different folder in Python
http://docs.python.org/tutorial/modules.html
Basically, those tutorials are allowing to import from another directory, but what about a completely different working tree? I don't want to keep doing .., .., .. etc. Is there a way to goto the home directory?
I tried the following code:
import os, sys
os.chdir(os.path.join(os.getenv("HOME"), 'local'))
from local_settings import *
But i keep seeing errors in my apache error.log for it...
os.chdir just affects the current working directory, which has nothing whatsoever to do with where Python imports modules from.
What you need to do is to add the the local directory to the Pythonpath. You can either do this from the shell by modifying PYTHONPATH, or from inside Python by modifying sys.path:
import sys
import os
sys.path.append(os.path.expanduser("~/local"))
import local_settings
In response to your concerns about source control, you can just set the source control to ignore that file, and/or have a symlink installed as part of your deploy script to link the file on the os into another. I do both , though not in django. but it's a trivial task.
your deploy layout could look like this:
/current ( symlink to /releases/v3 )
/settings/local_settings.py
/releases/v1
/releases/v2
/releases/v3
and a task runs as part of your deploy:
cd /current
ln -s /settings/local_settings.py local_settings.py
if you're deploying with fab or capistrano, it's a few lines of configuration. i'm sure you could do this with puppet/chef simply too.