Importing From Another Script in Python - python

My directory is as such:
isds:
__init__.py
jobs:
__init__.py
adhoc:
__init__.py
test.py
test2.py
My two files look like this.
test.py:
import sys
x = 10
test2.py:
import sys
from isds.jobs.adhoc.test import *
print(x)
When I run "python3 test2.py" from the same directory as test2.py, I get this error: ModuleNotFoundError: No module named 'isds.jobs.adhoc.test'
Why is this happening? I have the init.py files and I think I have the absolute import statement correct... but maybe not?
Thanks!

Since you are importing the module from same directory you can simply import using.
from test import *

in order to import as a package then you need to run the file as a package, so you would navigate to the folder containing isds` and run:
python -m isds.jobs.adhoc.test2
This runs the file as a module instead of a script, and since it gets indexed at the same level that it uses its own imports then the import mechanic you are using works as intended.
If you want to support either running as a script or running as a module you would need something like this:
try:
from isds.jobs.adhoc.test import *
except ModuleNotFoundError:
from test import *
But this can lead to other issues like if a different module not found error occurs and then import test ends up importing something else entirely you can get confusing and misleading error messages, so I'd generally recommend just running all your stuff with the -m flag if you are writing packages.
Also note this method works without any __init__.py files in python 3.7,4. the requirement to add empty init files was removed a while ago I believe.

Related

Getting a ModuleNotFoundError when trying to import from a particular module

The directory I have looks like this:
repository
/src
/main.py
/a.py
/b.py
/c.py
I run my program via python ./main.py and within main.py there's an important statement from a import some_func. I'm getting a ModuleNotFoundError: No module named 'a' every time I run the program.
I've tried running the Python shell and running the commands import b or import c and those work without any errors. There's nothing particularly special about a either, it just contains a few functions.
What's the problem and how can I fix this issue?
repository/
__init__.py
/src
__init__.py
main.py
a.py
b.py
c.py
In the __init__.py in repository, add the following line:
from . import repository
In the __init__.py in src, add the following line:
from . import main
from . import a
from . import b
from . import c
Now from src.a import your_func is going to work on main.py
Maybe you could try using a relative import, which allows you to import modules from other directories relative to the location of the current file.
Note that you will need to add a dot (.) before the module name when using a relative import, this indicates that the module is in the same directory as the current file:
from . import a
Or try running it from a different directory and appending the /src path like this:
import sys
sys.path.append('/src')
You could also try using the PYTHONPATH (environment variable) to add a directory to the search path:
Open your terminal and navigate to the directory containing the main.py file (/src).
Set the PYTHONPATH environment variable to include the current directory, by running the following command
export PYTHONPATH=$PYTHONPATH:$(pwd)
At last you could try to use the -m flag inside your command, so that Python knows to look for the a module inside the /src directory:
python -m src.main
I've had similar problems in the past. Imports in Python depend on a lot of things like how you run your program, as a script or as a module and what is your current working directory.
Thus I've created a new import library: ultraimport It gives the programmer more control over imports and lets you do file system based, relative imports.
Your main.py could look like this:
import ultraimport
a = ultraimport('__dir__/a.py')
This will always work, no matter how you run your code, no matter what is your sys.path and also no init files are necessary.

Python: Pygame TypeError when attempting to pass self as an object to a separate constructor [duplicate]

Within the top level of my git repository, I have the following file structure:
miscellaneous Dockerfiles, readme, etc
Code/
training.py
data/
generate.py
tasksets.py
Sometimes I want to import the generate module from within the tasksets module when I run the tasksets module as a script, so tasksets includes the following import:
import generate
Other times I want to import the tasksets module from within the training module, so training contains the following import:
import tasksets
However, this setup is giving me problems. tasksets can import generate fine when I run tasksets as a script, but throws an error if I import tasksets inside training when I run training as a script (I think because training can't find generate as a script within the default path). I've tried looking at all sorts of other StackOverflow questions and answers, using __init__.py files, relative imports, etc. Currently, my workaround is to use the following lines inside tasksets:
if __name__ == "__main__": import generate
else: from data import generate
But this doesn't feel right (and my IDE don't like it neither). Please can someone explain how to use the right assortment of __init__.py files and import statements such that I can import generate when running tasksets as a script, and also import tasksets when running training as a script?
You better use a classical Python module / package architecture.
projectname/
__init__.py
__main__.py
data/
__init__.py
generate.py
tasksets.py
To use your app, go into projectname/../ directory (one level upper projectname/) and run python -m projectname. This will execute projectname/__main__.py.
In __main__.py you will write something like:
from projectname.data import generate
from projectname.data import tasksets
if __name__ == '__main__':
generate.foo()
tasksets.bar()
You will use absolute import path (starting by your module name and a dot, projectname.)
You will import your submodules out of the if __name__ == '__main__'
__main__.py will be the only entry-point of your app/script.
In any other file, you will use the same syntax and paths to import other modules:
data/generate.py:
from projectname.data import tasksets
def foo():
print('SPAM!')
tasksets.bar()
Something I don't really enjoy, but I'm not sure any PEP deny it,
In your projectname/__init__.py file you can write:
from projectname.data import generate
from projectname.data import tasksets
So your two submodules will be imported into your main scope __init__.py, so you are able to import the submodules from this scope, like
data/generate.py:
from projectname import generate
But again, I don't really enjoy this way of doing (because Explicit is better than implicit.)
Last but not least,
You can also use python projectname/__main__.py command, but I still recommend python -m projectname
You can create a setup.py file using setuptools to "install" your app on your system and simply run projectname command to run it.

weird python3 import issue, No module named <module>

I write some python files like this:
main.py
view/ __init__.py #empity file
MainWindow.py
ListEditor.py
And in each file I wrote those imports:
<main.py>
from view.MainWindow import MainWindow
...
-
<MainWindow.py>
from view.ListEditor import ListEditor
and ListEditor.py don't import any files.
Each MainWindow.py or ListEditor.py defines a class that named same as the file name.
when I run the program from main.py, it works. But when I run from MainWindow.py I got ImportError: No module named 'view'
If I write
from ListEditor import ListEditor
in MainWindow.py, python MainWindow.py will be OK. but python main.py will get error:
ImportError: No module named 'ListEditor'
So, is there a way to make both python main.py and python MainWindow.py get right at the same time?
I'm using python3.4
P.S.
I think I have figured out the problem here. The import command searches a module in sys.path. The sys.path is a group of predefined paths plus the running script path. When I run the code from MainWindow.py, the code import ListEditor just works, but when I run from main.py, the current path is set to the parent path. So I need import view.ListEditor.
Well, there are couple ways to deal with it. #Vincent Beltman's answer is one of it. Or just put these code in the __init__.py file:
import os, sys
path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(path)
Finally, I'm new to python. And I think the import command is quite strange. I thought it should search the files relative to the path of the source file that containing the command, not just relative to the starter file. A starter file may varying and cause troubles like this one.
Try this:
try:
from view.ListEditor import ListEditor # If this one fails
except:
try:
from ListEditor import ListEditor # It will try this one

Python importing works from one folder but not another

I have a project directory that is set up in the following way:
>root
> modules
__init__.py
module1.py
> moduleClass
__init__.py
moduleClass1.py
moduleClass2.py
> scripts
runTests.py
> tests
__init__.py
test1.py
test2.py
run.sh
In runTests.py I have the following import statements:
import modules.module1
import modules.moduleClass.moduleClass2
import tests.test1
import tests.test2
The first two import statements work fine, but the second two give me the errors ImportError: No module named test1 and ImportError: No module named test2. I can't see what is different between the tests and modules directories.
I'd be happy to provide more information as needed.
When you run a script, Python adds the script's containing directory (here, scripts/) to sys.path. If your modules don't appear in sys.path any other way, that means Python may not be able to find them at all.
The usual solution is to put your scripts somewhere in your module hierarchy and "run" them with python -m path.to.module. But in this case, you could just use an existing test runner: Python comes with python -m unittest discover, or you might appreciate something fancier like py.test (pip install --user pytest).
The problem turned out to be that python didn't like the folder name tests. Changing the name to unit_tests solved the problem.

How to fix "Attempted relative import in non-package" even with __init__.py

I'm trying to follow PEP 328, with the following directory structure:
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
In core_test.py I have the following import statement
from ..components.core import GameLoopEvents
However, when I run, I get the following error:
tests$ python core_test.py
Traceback (most recent call last):
File "core_test.py", line 3, in <module>
from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package
Searching around I found "relative path not working even with __init__.py" and "Import a module from a relative path" but they didn't help.
Is there anything I'm missing here?
To elaborate on Ignacio Vazquez-Abrams's answer:
The Python import mechanism works relative to the __name__ of the current file. When you execute a file directly, it doesn't have its usual name, but has "__main__" as its name instead. So relative imports don't work.
You can, as Igancio suggested, execute it using the -m option. If you have a part of your package that is meant to be run as a script, you can also use the __package__ attribute to tell that file what name it's supposed to have in the package hierarchy.
See http://www.python.org/dev/peps/pep-0366/ for details.
Yes. You're not using it as a package.
python -m pkg.tests.core_test
It depends on how you want to launch your script.
If you want to launch your UnitTest from the command line in a classic way, that is:
python tests/core_test.py
Then, since in this case 'components' and 'tests' are siblings folders, you can import the relative module either using the insert or the append method of the sys.path module.
Something like:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents
Otherwise, you can launch your script with the '-m' argument (note that in this case, we are talking about a package, and thus you must not give the '.py' extension), that is:
python -m pkg.tests.core_test
In such a case, you can simply use the relative import as you were doing:
from ..components.core import GameLoopEvents
You can finally mix the two approaches, so that your script will work no matter how it is called.
For example:
if __name__ == '__main__':
if __package__ is None:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents
else:
from ..components.core import GameLoopEvents
You can use import components.core directly if you append the current directory to sys.path:
if __name__ == '__main__' and __package__ is None:
from os import sys, path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
In core_test.py, do the following:
import sys
sys.path.append('../components')
from core import GameLoopEvents
Issue is with your testing method,
you tried python core_test.py
then you will get this error
ValueError: Attempted relative import in non-package
Reason: you are testing your packaging from non-package source.
so test your module from package source.
if this is your project structure,
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
cd pkg
python -m tests.core_test # dont use .py
or from outside pkg/
python -m pkg.tests.core_test
single . if you want to import from folder in same directory .
for each step back add one more.
hi/
hello.py
how.py
in how.py
from .hi import hello
incase if you want to import how from hello.py
from .. import how
If your use case is for running tests, and it seams that it is, then you can do the following. Instead of running your test script as python core_test.py use a testing framework such as pytest. Then on the command line you can enter
$$ py.test
That will run the tests in your directory. This gets around the issue of __name__ being __main__ that was pointed out by #BrenBarn. Next, put an empty __init__.py file into your test directory, this will make the test directory part of your package. Then you will be able to do
from ..components.core import GameLoopEvents
However, if you run your test script as a main program then things will fail once again. So just use the test runner. Maybe this also works with other test runners such as nosetests but i haven't checked it. Hope this helps.
My quick-fix is to add the directory to the path:
import sys
sys.path.insert(0, '../components/')
As Paolo said, we have 2 invocation methods:
1) python -m tests.core_test
2) python tests/core_test.py
One difference between them is sys.path[0] string. Since the interpret will search sys.path when doing import, we can do with tests/core_test.py:
if __name__ == '__main__':
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from components import core
<other stuff>
And more after this, we can run core_test.py with other methods:
cd tests
python core_test.py
python -m core_test
...
Note, py36 tested only.
As you have already marked everything as a module, there's no need to use the relative reference if you launch as python module.
Instead of
from ..components.core import GameLoopEvents
simply
from pkg.components.core import GameLoopEvents
When you run from the parent of pkg, use the following
python -m pkg.tests.core_test
Old thread. I found out that adding an __all__= ['submodule', ...] to the
__init__.py file and then using the from <CURRENT_MODULE> import * in the target works fine.
You can use from pkg.components.core import GameLoopEvents, for example I use pycharm, the below is my project structure image, I just import from the root package, then it works:
This approach worked for me and is less cluttered than some solutions:
try:
from ..components.core import GameLoopEvents
except ValueError:
from components.core import GameLoopEvents
The parent directory is in my PYTHONPATH, and there are __init__.py files in the parent directory and this directory.
The above always worked in python 2, but python 3 sometimes hit an ImportError or ModuleNotFoundError (the latter is new in python 3.6 and a subclass of ImportError), so the following tweak works for me in both python 2 and 3:
try:
from ..components.core import GameLoopEvents
except ( ValueError, ImportError):
from components.core import GameLoopEvents
Try this
import components
from components import *
If someone is looking for a workaround, I stumbled upon one. Here's a bit of context. I wanted to test out one of the methods I've in a file. When I run it from within
if __name__ == "__main__":
it always complained of the relative imports. I tried to apply the above solutions, but failed to work, since there were many nested files, each with multiple imports.
Here's what I did. I just created a launcher, an external program that would import necessary methods and call them. Though, not a great solution, it works.
Here's one way which will piss off everyone but work pretty well. In tests run:
ln -s ../components components
Then just import components like you normally would.
For me only this worked: I had to explicitly set the value of package to the parent directory, and add the parent directory to sys.path
from os import path
import sys
if __package__ is None:
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
__package__= "myparent"
from .subdir import something # the . can now be resolved
I can now directly run my script with python myscript.py.
python <main module>.py does not work with relative import
The problem is relative import does not work when you run a __main__ module from the command line
python <main_module>.py
It is clearly stated in PEP 338.
The release of 2.5b1 showed a surprising (although obvious in retrospect) interaction between this PEP and PEP 328 - explicit relative imports don't work from a main module. This is due to the fact that relative imports rely on __name__ to determine the current module's position in the package hierarchy. In a main module, the value of __name__ is always '__main__', so explicit relative imports will always fail (as they only work for a module inside a package).
Cause
Python Bug Tracker Issue1510172: Absolute/relative import not working?
The issue isn't actually unique to the -m switch. The problem is that relative imports are based on __name__, and in the main module, __name__ always has the value __main__. Hence, relative imports currently can't work properly from the main module of an application, because the main module doesn't know where it really fits in the Python module namespace (this is at least fixable in theory for the main modules executed through the -m switch, but directly executed files and the interactive interpreter are completely out of luck).
To understand further, see Relative imports in Python 3 for the detailed explanation and how to get it over.
I've had similar issues and as a software engineer, I think some of the suggested solutions here are not ideal. If you want relative imports, you should not have try/except and then sometimes do an absolute import. Also, to run a program, you should not have to change sys.path.
Furthermore, the program should always work, independent of your current working directory and independent of how you start it.
Thus, I've created a new, experimental import library: ultraimport
It allows file system based imports, no matter how you run your code.
From the original question, you would change your core_test.py to something like
import ultraimport
GameLoopEvents = ultraimport('__dir__/../components/core.py', 'GameLoopEvents')
print(GameLoopEvents)
and it would always find it, no matter how you run your tests.
$ python -m tests.core_test
<class 'core.GameLoopEvents'>
python ./tests/core_test.py
<class 'core.GameLoopEvents'>
I've also put this example into the examples folder in the git repo.
As the library is experimental, I am interested in feedback. It works for me but it not widely tested, yet.
If your project structure would look like this:
project
|
| --- module1
| |
| file1.py
|
|-----module2
| |
| file2.py
and you are going import file1.py from within file2.py,
you can do this in file2.py:
import sys
sys.path.append('.')
import file2
I still don't know why and how, but it worked for me.
This is very confusing and if you are using IDE like Pycharm, it's little more confusing.
What worked for me:
Make Pycharm project settings (if you are running python from a VE or from Python directory)
There is nothing wrong with the way you defined. Sometime it works with:
from folder1.file1 import class
if it does not work, use:
import folder1.file1
Your environment variable should be correctly mentioned in system or provide it in your command line argument.
Because your code contains if __name__ == "__main__", which doesn't be imported as a package, you'd better use sys.path.append() to solve the problem.

Categories

Resources