How to properly call functions defined in other directories in Python? - python

Sorry, this has been already answered for sure, but I cannot find the answer to my problem... I want to make two separate scripts callable. Let me explain in detail with an example.
I have a directory structure similar to this:
maindir
|- subdir
| |- script.py
| `- myfunc.py
`- main.py
with the following content:
In myfunc.py there is
def myverynicefunc():
print('Hello, I am your very nice func :)')
in script.py there is
import myfunc
def scriptfunc():
print('I am the script function :)')
myfunc.myverynicefunc()
and in main.py there is
from subdir.script import scriptfunc
scriptfunc()
If I go to the subdir directory and execute the script it works, I mean:
.../main_dir/subdir$ python3 script.py
Hello, I am your very nice func :)
However if I try to execute the main.py script it fails:
.../main_dir$ python3 main.py
Traceback (most recent call last):
File "main.py", line 1, in <module>
from subdir.script import scriptfunc
File "/home/alf/Escritorio/main_dir/subdir/script.py", line 1, in <module>
import myfunc
ModuleNotFoundError: No module named 'myfunc'
If I modify the content of script.py to
from . import myfunc
def scriptfunc():
print('I am the script function :)')
myfunc.myverynicefunc()
now the situation is the inverse, the main.py script works ok:
.../main_dir$ python3 main.py
Hello, I am your very nice func :)
I am the script function :)
but the script.py script fails:
.../main_dir/subdir$ python3 script.py
Traceback (most recent call last):
File "script.py", line 1, in <module>
from . import myfunc
ImportError: cannot import name 'myfunc'
Is there a way to make both calls to main.py and to script.py to work?

Try this in your script.py-
import sys
current_path = sys.path[0]
if current_path.split('/')[-1] != 'subdir':
sys.path.insert(0, current_path+'/subdir/')
import myfunc
By this, if the current directory for python is the parent directory of the file, that is the maindir, it would change the path to directory and then import it.
With this, it should work in both scenarios. Hope this helps. :)

with the second scenario, you can do
python3 -c "import subdir.script" in your main directory

Related

How do relative imports work?

I have a directory structure like this
project/
__init__.py
greetings.py
script.py
greetings.py
def hello():
print('Hello')
script.py
from . import greetings
greetings.hello()
When I execute python script.py following error occurs
Traceback (most recent call last):
File "script.py", line 1, in <module>
from . import greetings
ImportError: cannot import name 'greetings'
If I just use import greetings in script.py everything works.
But why does the relative import give error?
And why does it work when I use from . import models in views while working in django.
Please follow Module vs Package concept in python.
Here you created a package so you have to import package as:-
from project import greetings
Here relative import will work as
from .greetings import *
OR
import greetings
greetings should be on same folder

Splitting my code into multiple files in Python 3

I wish to split my code into multiple files in Python 3.
I have the following files:
/hello
__init__.py
first.py
second.py
Where the contents of the above files are:
first.py
from hello.second import say_hello
say_hello()
second.py
def say_hello():
print("Hello World!")
But when I run:
python3 first.py
while in the hello directory I get the following error:
Traceback (most recent call last):
File "first.py", line 1, in <module>
from hello.second import say_hello
ImportError: No module named 'hello'
Swap out
from hello.second import say_hello
for
from second import say_hello
Your default Python path will include your current directory, so importing straight from second will work. You don't even need the __init__.py file for this. You do, however, need the __init__.py file if you wish to import from outside of the package:
$ python3
>>> from hello.second import say_hello
>>> # Works ok!
You shouldn't run python3 in the hello directory.
You should run it outside the hello directory and run
python3
>>> import hello.first
By the way, __init__.py is no longer needed in Python 3. See PEP 420.
Packages are not meant to be imported from the current directory.
It is possible to make it work using if/else tests or try/except handlers, but it's more work than it is worth.
Just cd .. so you aren't in the package's directory and it will work fine.

Running python unittest in the console

I have the follwoing package structure
my-base-project
-> package1
__init__.py
MyScript.py
-> test
__init__.py
TestMyScript.py
I'd like to run the TestMyScript.py in the console. Therefore I cd in to my-base-project/test and execute python TestMyScript.py. However, I'm getting the error:
user#computer:~/my-base-project/test$ python TestMyScript.py
Traceback (most recent call last):
File "TestMyScript.py", line 4, in <module>
from package1 import MyScript
ImportError: No module named package1
How do I run these tests?
From this SO question, consider adding the directory you need to the PYTHONPATH:
import sys
sys.path.append('your certain directory')
Maybe you want to add the parent directory
sys.path.append('..')

Relative import inside flat package

I have a package of the following form:
$ ls folder
entry_point.py hello.py __init__.py utils.py
This is a package, and I can treat it as such:
$ python2.7
>>> import folder.utils
>>>
I want to use relative imports between these Python modules.
$ cat folder/entry_point.py
from hello import say_hello
if __name__ == "__main__":
say_hello()
$ cat folder/hello.py
from .utils import say
def say_hello():
say()
$ cat folder/utils.py
def say():
print "hello world"
I know I can't use relative imports at the entry point, where I call the interpreter. However, I still get ImportError from my imported files:
$ python2.7 folder/entry_point.py
Traceback (most recent call last):
File "folder/entry_point.py", line 1, in <module>
from hello import say_hello
File "/tmp/folder/hello.py", line 1, in <module>
from .utils import say
ValueError: Attempted relative import in non-package
This is rather counterintuitive, it is a package, it's just not treated as one due to entry_point.py having __name__ set to __main__ (in line with PEP 328).
I'm surprised that hello.py has a __name__ of hello rather than folder.hello. This stops me using relative imports in hello.py.
How do I use relative imports in this package? Am I forced to move hello.py and utils.py to a libs subpackage?
If you want folder to be a module inside a bigger project and you want to be able to run entry_point.py for using your folder module - move entry_point.py one level up:
from folder.hello import say_hello
if __name__ == "__main__":
say_hello()
Import paths - the right way?

Can anyone explain python's relative imports? [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

Categories