Python relative imports with sys.path - python

I have this weird Python import and I can't get it to work with any of the suggestions in other discussions.
I'm currently adding a small script to someone else's module, so I cannot change the file structure or any of the existing code, which makes things difficult.
Here is an example of the python script which contains a bunch of classes:
/path/to/root/directory/aaa/bbb/ccc/utils.py
The current developer imports this as follows:
from aaa.bbb.ccc import utils
utils.SomeClass.someMethod()
All directories in the tree have a __init__.py file
Now I want to call the module externally as follows:
import sys
sys.path.append('/path/to/root/directory')
from aaa.bbb.ccc import utils
utils.SomeClass.someMethod()
This does NOT work, and gives the the following error:
from aaa.bbb.ccc import utils
ImportError: No module named ccc
However, changing the import a little bit does work:
import sys
sys.path.append('/path/to/root/directory')
from aaa.bbb.ccc.utils import *
SomeClass.someMethod()
I do not understand why the 2nd one works and not the 1st. Again, I cannot change the existing code, so the following 2 statements must work with my sys.path.append and imports:
from aaa.bbb.ccc import utils
utils.SomeClass.someMethod()
I cannot remove the utils from utils.SomeClass
Does anyone know how I can achieve this?

This really isn't an answer, but there is no way I could fit this into a comment, let alone with any sane formatting. My apology, but it hopefully can still help us get somewhere.
I suspect there is still a bit of information missing somewhere in the question. I've setup the following tree under /tmp/so/xxx:
.
└── aaa
├── __init__.py
└── bbb
├── __init__.py
└── ccc
├── __init__.py
└── utils.py
__init__.py files are blank and utils.py says:
class SomeClass:
#staticmethod
def someMethod():
print("FOO")
Which if I read the description correctly should be enough to replicate the behavior. Now I try both snippets of yours:
import sys
sys.path.append("/tmp/so/xxx")
from aaa.bbb.ccc import utils
utils.SomeClass.someMethod()
And run:
$ python test1.py
FOO
And second one:
import sys
sys.path.append("/tmp/so/xxx")
from aaa.bbb.ccc.utils import *
SomeClass.someMethod()
Runs as well:
$ python test2.py
FOO
I've tried Python 3.6.5 and 2.7.15. Same result.
Based on your output, I presume you're running Python 2. The only way I could reproduce this problem (get the same error) was by removing __init__.py from ccc/, but the other syntax would not work either then.
Could you perhaps post your tree and content of __init__.py files? With the available data, I was unfortunately able to reproduce the problem.

Related

Relative path ImportError when trying to import a shared module from a subdirectory in a script

I am trying to import a util package one directory up from where my code is, but I get an ImportError which I don't understand.
I have a number of different variations on the import syntax in Python, none of which are working.
There are a number of similar questions on Stack Overflow, but none have helped me understand or fix this issue.
Of the top of my head, I have tried the following variations:
import util
import ..util
from .. import util
from ..util import parser
from AdventOfCode2022 import util
from ..AdventOfCode2022 import util
from ...AdventOfCode2022 import util
Most of these I guessed wouldn't work, but I tried them anyway to be sure.
Error message:
ImportError: attempted relative import with no known parent package
Directory structure:
.
├── day03
│ ├── input.txt
│ ├── part1.py
│ ├── part2.py
│ └── test_input.txt
└── util
├── __init__.py
└── parser.py
I just want to import my util package from any "day0*/" directory - not sure why Python makes it so hard!
Two options:
Add the full path to ./util/ to your PYTHONPATH environment variable.
For example on Bash, your ~/.bashrc might have export PYTHONPATH="${PYTHONPATH}:/Users/foobar/projects/advent-of-code/util/".
Add sys.path.append('/path/to/application/app/folder') before the import.
The other solutions don't work because:
day03 and the parent directory are not modules with their own __init__.py. Lines like from ..util import parser only work if everything involved is a module.
You are presumably running the code from within ./day03/.
View this as 'I have a bunch of independent Python projects (day01, day02 etc) that all want to share a common piece of code I have living in a different project (util) that lives somewhere else on my computer.'

Importing files from different folder in the same parent directory

I've got a folder that looks something like this. I'm trying to import a class from card.py from test_cards.py
└── 32-PROJECT-Texas-Hold-Em-Poker/
├── poker/
│ ├── card.py
│ └── __init__.py
└── tests/
└── test_cards.py
└── __init__.py
In test.py I've tried:
from poker import card
from .poker import card
from ..poker import card
from 32-PROJECT-Texas-Hold-Em-Poker.poker import card
import sys
sys.path.insert(1, '/path/to/Test_folder_1/Test_folder_2')
from Test_folder_2 import add_numbers
but it keeps coming up with either No module named poker or ImportError: attempted relative import with no known parent package. I've tried different variations along with varying where the init.py file is, and honestly I've tried a lot more than what I posted above. I've read up on relative and absolute imports. Short of adding this directory right into my path, I'm completely lost at what seems to be a simple task. I've spend a couple of days on this now and I just can't seem to get it to work. Also, what should I be studying to understand this stuff better rather than finding stuff online? I've just recently learnt about system paths and venvs.
I'm actually following along with The complete Python bootcamp for 2022 on Udemy
from test_cards.py, he is able to get a Card class from card.py just from typing
from poker.card import Card
Thank you
There are a few ways to do this. Here's one that's quite simple, suitable for test code but not recommended in a production app:
import sys
import os.path
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'poker'))
import card
sys.path = sys.path[:-1]
That should work no matter where you run your Python script from.
Here's some more information: https://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python

How to Import from parent directory Python

I am trying to import a file from the main directory using python. I tried several methods but no luck :(.
My file directory
|_ api
|__init__.py
|_api1.py
|_api2.py
|_api3.py
|_api4.py
|_api5.py
|_api6.py
|__init__.py
|_api.py
|_db_ops.py
Challenge
I am trying to import some methods of api.py into api1.py and api2.py.
The solutions I have found were:
1. Add __ini__.py file
I have added them as you can see but did not work.
2. import using `import api`
did not worked rather throws an error **ModuleNotFoundError**
3. import using 'from . import api'
throws an error "cannot import from unknown module"
4. even tried to create a parent folder **test** and then tried with import test.apicall but still did not worked!
Any help.
Thanks
first of all, the file name is __init__.py and not __ini__.py.
by default, you only can import directory from the same level or below where you are using the python command.
example:
myproject/
project/
__init__.py
foo.py
bar.py
if the terminal in myproject and i run python project/foo.py, foo can import bar.py , but if i am myproject/project and i run python foo.py, foo cannot import bar.py
to change the default you can use
import sys
sys.path.append('path of my dir')
It depends on what you want to do. If you want to run a script in a lower-level folder, Python will not let you do it. On the other hand, let's say for simplicity you have the folder structure
mypackage/
subpackage/
__init__.py
api1.py
__init__.py
api.py
If api.py looks like the following
def foo(a):
print(a)
then in api1.py you can have a relative import like
from ..api import foo as f
Then you can't, however, run api1.py as a script, but you can use f as a function to extend things in api1.py or write a script with the content
from mypackage.subpackage.api1 import f
so in that case, it will look like the function foo was in api1.py.
I'll note that this was heavily inspired by the Python-documentation on relative imports... (https://docs.python.org/3/reference/import.html)

relative paths for modules in python

I've attempted a few different techniques trying to do something that to me seems doable but I guess I am missing some gotchas about python (using 2.7 but would like this to work also for 3.* if possible).
I am not sure about terminology like package or module, but to me the following seems quite a "simple" doable scenario.
This is the directory structure:
.
├── job
│   └── the_script.py
└── modules
   ├── __init__.py
   └── print_module.py
The content of the_script.py:
# this does not work
import importlib
print_module = importlib.import_module('.print_module', '..modules')
# this also does not work
from ..modules import print_module
print_module.do_stuff()
The content of print_module:
def do_stuff():
print("This should be in stdout")
I would like to run all this "relative paths" stuff as:
/job$ python2 the_script.py
But the importlib.import_module gives various errors:
if I just use 1 input parameter ..modules.print_module, then I get: TypeError("relative imports require the 'package' argument")
if I use 2 input parameters (as in the example above), then I get: ValueError: Empty module name
On the other hand using the from ..modules syntax I get: ValueError: Attempted relative import in non-package.
I think the __init__.py empty file should be enough to qualify that code as "packages" (or modules? not sure about the terminology), but it seems there's something I am missing about how to manage relative paths.
I read that in the past people was hacking this using the path and other functions from import os and import sys, but according to the official docs (python 2.7 and 3.*) this should not be needed anymore.
What am I doing wrong and how could I achieve the result of printing the content modules/print_module.do_stuff calling it from a script in the "relative directory" job/?
If you follow the structure of this guide here: http://docs.python-guide.org/en/latest/writing/structure/#test-suite (highly recommend reading it all, it is very helpful) you will see this:
To give the individual tests import context, create a tests/context.py file:
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import sample
Then, within the individual test modules, import the module like so:
from .context import sample
This will always work as expected, regardless of installation method.
Translated in your case this means:
root_folder
├── job
│ ├── context.py <- create this file
│ └── the_script.py
└── modules
├── __init__.py
└── print_module.py
In the context.py file write the lines shown above, but import modules instead of import samples
Finally in your the_script.py: from .context import module and you will be set to go!
Good luck :)
I found a solution using sys and os.
The script the_script.py should be:
import sys
import os
lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../modules'))
sys.path.append(lib_path)
# commenting out the following shows the `modules` directory in the path
# print(sys.path)
import print_module
print_module.do_stuff()
Then I can run it via command line no matter where I am in the path e.g.:
/job$ python2 the_script.py
<...>/job$ python2 <...>/job/the_script.py
If you are not sure about terminology go to very nice tutorials:
http://docs.python-guide.org/en/latest/writing/structure/#modules
and
http://docs.python-guide.org/en/latest/writing/structure/#packages
But for your structure:
.
├── job
│ └── the_script.py
└── modules
├── __init__.py
└── print_module.py
just say in the the_script.py:
import sys
sys.append('..')
import modules.print_module
This will add parent directory to PYTHONPATH, and python will see directory 'parallel' to job directory and it will work.
I think that at the most basic level it is sufficent to know that:
package is any directory with __init__.py file
module is a file with .py, but when you are importing module you omit extension.

how to import py file from different upper folder?

All,
File structure:
\
util
utils.py
modules
__init__.py
modules1.py
submodule
__init__.py
submodule.py
I want to know how to import utils.py in those
__init__.py
for example, now I run the python interpreter in \ level, I run import modules, I suppose the code from ..util.utils import * may works, but it is not.
may I know where is the mistake?
and may I know if there's a way i can import utils.py in a universal format?
something like
import \util\utils.py
I know I may use path.append(), but any alternative?
Thanks
============
got the answer from this post:
Import a module from a relative path
If you are developping a python package (what you are obviously doing, as you have init.py), then the most simple way to import your module is just via the package.
For example, if your package is called mypackage, then:
import mypackage.utils

Categories

Resources