I know a similar question has been answered ad nauseam in these pages, but I've read all the answers and cannot find a solution that makes my nuanced application work. The long and short:
I would like to expose an external module (that only exists in a relative path, and I cannot update the PATH variable) to my working module. In each case, I recognize that I could import the module using a sys.path.append()/import. However, I would like to import the module in my __init__.py and expose it to the module there (so I only have to adjust the path once, theoretically). Everything I have read indicates that once I have exposed the module via the import in __init__.py, I should be able to access it via a call like my_module.imported_module. However, that does not seem to work. The basic idea is to share a set of functions across multiple modules that should also all be independent. Example below:
(base module):
__init__.py:
import sys
sys.path.append('../') # I know this is not ideal, but for simplicity
import core
myfile:
import base
print dir(core)
NameError: name 'core' is not defined
Alternatively:
myfile:
import base
print dir(base.core)
AttributeError: 'module' object has no attribute 'core'
And last:
myfile:
import base.core
print dir(base.core)
ImportError: No module named core
**last, last:
And last:
myfile:
import core
print dir(core)
ImportError: No module named core
Any ideas?
you don't really have a choice here, if it's a relative path in a directory outside of your main module, you're going to have to manipulate the path. You should change your sys.path manipulation to work with __file__ instead so you aren't bound to current working directly, i.e.:
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(__file__))
However, if the other package shares a package with your file you could use a relative import:
parent/
__init__.py
core.py
base/
__init__.py
myfile.py
You can also do this path manipulation in your .pythonrc or with your ipython settings.
Related
as the question, i have my directory map like this
the formatOutput contain some function for better print
now, i want use a function in module printChecked.py in package formatOutput from findInfoSystem.py
i have tried create __init__.py in all folder to treat python it is a package (the advice i get from previous answer other post) but it always failed.
case 1: from formatOutput.printChecked import print_checked_box
error is: ModuleNotFoundError: No module named 'formatOutput'
case 2: from dttn.formatOutput.printChecked import print_checked_box
error is ModuleNotFoundError: No module named 'dttn'
case 3: from ..formatOutput.printChecked import print_checked_box
error is ImportError: attempted relative import with no known parent package
i don't want to use the sys.path method because i think it is not the good way to solve problem.
Help me please !
There are two classes of solutions to this problem:
modify the python import path
use the various setup tools or manually install .egg-links or symbolic links
to "install" your development modules in the python/lib/site-packages
The first approach is simple, but the second involves delving deeper
into a number of related topics. You'd probably want a virtual environment,
and a setup.py, etc.
So for the quick and dirty, two ways to modify the python import path:
set the PYTHONPATH= environment variable to include the parent directory of your packages
in findInfoSystem before importing formatOutput.printChecked, add this:
import sys
sys.path.append("..")
i found something very weird. I'm not import direct in module file but import to init.py file of package and then import to module file from packages name and it work. it like that:
from __init__.py of systemInfo package:
import sys,os
from formatOutput import prettyAnnounce,prettyParseData
current_directory = os.getcwd()
# sys.path.insert(1, current_directory+"/formatOutput/")
# sys.path.insert(1,current_directory+"/")
then in findInfoSystem.py module, im imported again like this:
from systemInfo import current_directory, prettyAnnounce as prCh , prettyParseData as prPD
yeah, now it's work like a charm. :))) i even not sure how
How do I import a module and use it as if I installed it without actually installing it? More specifically, when I do imports on an installed module, all the imports are relative to the module. However when I just import it, all the imports are relative to the module it is called from.
As a specific example, in the below I would like run_import.py to print module not parent. But because it imports cfg from the parent not the module, it prints the wrong one. I would like to be able to run module1 on a standalone basis and have it isolated from any code that is calling it, much like you would in an installed package.
Directory structure is
module1/
__init__.py
cfg.py
tasks.py
run_module.py
utils.py
cfg.py
run_import.py
utils.py
Code
# cfg.py
level = 'parent'
# module1/cfg.py
level='module'
# module1/tasks.py
import cfg
def run_it():
print(cfg.level)
# module1/run_module.py
import tasks
tasks.run_it() # prints 'module'
# module1/utils.py
def util_fun():
print('util module')
# utils.py
def util_fun():
print('util parent')
# run_import.py
import module1.tasks as tasks
tasks.run_it() # prints 'parent', would like it to print 'module'
import utils
utils.util_fun() # prints util parent, should not print util module
This give me what I was looking for but has the unintended consequence that everything gets imported relative to that module
import sys
sys.path.insert(0, "module1")
tasks.run_it() # prints 'parent'
import utils
utils.util_fun() # prints util module, not util parent
Here are a couple of answers I have looked it, they didn't seem to solve it.
What's the purpose of the "__package__" attribute in Python? this sounds like what is needed but not sure how that can be set
Python3 importlib.util.spec_from_file_location with relative path? look potentially promising but i'm not sure how to use it, particularly not sure what the file path should be
How to use a packed python package without installing it
Import a module from a relative path
Can a python module be imported without installing
Import module using relative paths
When you execute run_import.py, the imports are searching in the root folder (module1/).
So you can try changing module1/tasks.py
from module1 import cfg
def run_it():
print(cfg.level)
Try this, adding the module to the path works if you would only like to change run_import.py
import sys
sys.path.insert(0, "module1")
from module1 import tasks
tasks.run_it()
With the folder structure
lib/
abcd/
__init.py__
lib.py
app.py
the code
from lib.abcd import lib
works. But with this file structure:
bin/
app.py
lib/
abcd/
__init.py__
lib.py
the code
from ..lib.abcd import lib
gives an import error.
How to do the import properly when the library is in a sibling of the current folder? (or subfolder of a sibling folder)
I know that there might some hack that involves adding lib/ to the PATH, but is there an elegant Pythonic solution?
If not, is there a real internal reason to prevent users to do this simple import in a simple way?
Methods to do this
Method #1: Using the sys module: You can easily accomplish what you are trying to do using the sys module. To import the lib package, you can use one of the two codes listed below:
import sys
sys.path.append('<PATH_TO_LIB_FOLDER>')
from lib.abcd import lib
or
import sys
sys.path.insert(0, '<PATH_TO_LIB_FOLDER>')
Method #2: Using the os module: Another method is to use the os module. Here is an example code that imports the lib module using the os module by invoking the os.path.join method:
import os
path = os.path.join("<PATH>/lib/abcd", "lib")
from lib.abcd import lib
Method #3: Add the module to your PYTHONPATH: This is not the best method in most cases, but if you don't want to keep using the sys or os module to import lib, this is ideal. All you have to do is type this in your bash terminal:
export PYTHONPATH=<PATH_TO_LIB> python lib.py
Then in your python shell you can import it like this:
from lib.abcd import lib
Method #4: Combine the sys and os module (recommended): This is the most efficient method and will save you a lot of time. This code combines the os and sys module like this:
import sys, os
sys.path.append(os.path.abspath(os.path.join('..', 'lib')))
Then you can import your module with ease like this:
from lib.abcd import lib
How all the codes work:
All the codes above are very simple. All the examples except for "Method #3", add your module to the PYTHONPATH temporarily. "Method #3" on the other hand, adds the module to your PYTHONPATH permanently.
Surface level look
Normally, you can't. When importing a file, Python only searches the current directory, the directory that the entry-point script is running from, and sys.path which includes locations such as the package installation directory (it's actually a little more complex than this, but this covers most cases).
The reason you don't see this problem for importing installed modules is because they are installed in a location that is already on your path, or the location is added to the path by the installing utility (pip for example).
You can add to the Python path at runtime:
import sys
sys.path.insert(0, '../lib')
import file
You can also use sys.path.append('../lib'), but then it will be searched for last in your path and may be overridden by previous path entries.
I have read through the import documentation extensively, and as far as I can tell, the answer to your question is no, there is no way to do this in a purely "Pythonic" way.
More in depth look:
Looking deeper into the import documentation explains this:
The import statement combines two operations; it searches for the named module, then it binds the results of that search to a name in the local scope. The search operation of the import statement is defined as a call to the __import__() function, with the appropriate arguments. The return value of __import__() is used to perform the name binding operation of the import statement.
Looking more closely at __import__:
__import__(name, globals=None, locals=None, fromlist=(), level=0)
Note: This is an advanced function that is not needed in everyday Python programming, unlike importlib.import_module().
This function is invoked by the import statement. It can be replaced (by importing the builtins module and assigning to builtins.__import__) in order to change semantics of the import statement, but doing so is strongly discouraged as it is usually simpler to use import hooks (see PEP 302) to attain the same goals and does not cause issues with code which assumes the default import implementation is in use. Direct use of __import__() is also discouraged in favor of importlib.import_module().
level specifies whether to use absolute or relative imports. 0 (the default) means only perform absolute imports. Positive values for level indicate the number of parent directories to search relative to the directory of the module calling __import__() (see PEP 328 for the details).
This makes me think that you can specify a level in some way that may make the import automatically look on the parent path. I'm guessing that when import is called from your app.py that is not in it's own directory, level is set to 0 and it searches the same level and deeper.
When you call import in app.py from a subfolder, level is still set to 0 and thus can't find the other directories above it. I am investigating a "Pythonic" way of setting this level to 1 when running your script which would appear to fix this problem.
I understand the four lines below:
import bpy
import numpy as np
from sys import argv
from os import *
But I've never seen the following lines:
from . uisun import *
from . hdr import sunposition
What about the dot? Does it refer to the position in the directory or something else?
The files uisun.py, sunposition.py, hdr.py are in the same directory within __init__.py which contains the code above.
By the way, this comes from a Blender addon.
ITs Intra-package References :
The submodules often need to refer to each other. For example, the surround module might use the echo module. In fact, such references are so common that the import statement first looks in the containing package before looking in the standard module search path. Thus, the surround module can simply use import echo or from echo import echofilter. If the imported module is not found in the current package (the package of which the current module is a submodule), the import statement looks for a top-level module with the given name.
When packages are structured into subpackages (as with the sound package in the example), you can use absolute imports to refer to submodules of siblings packages. For example, if the module sound.filters.vocoder needs to use the echo module in the sound.effects package, it can use from sound.effects import echo.
Starting with Python 2.5, in addition to the implicit relative imports described above, you can write explicit relative imports with the from module import name form of import statement. These explicit relative imports use leading dots to indicate the current and parent packages involved in the relative import. From the surround module for example, you might use:
from . import echo
from .. import formats
from ..filters import equalizer
This is just like playing around in a terminal. '.' means the current directory (where you are running your program from) and '..' means the parent directory. Read this for an example.
...Now I know this question has been asked many times & I have looked at these other threads. Nothing so far has worked, from using sys.path.append('.') to just import foo.
I have a python file that wishes to import a file (that is in its parent directory). Can you help me figure out how my child file can successfully import its a file in its parent directory. I am using python 2.7.
The structure is like so (each directory also has the __init__.py file in it):
StockTracker/
└─ Comp/
├─ a.py
└─ SubComp/
└─ b.py
Inside b.py, I would like to import a.py: So I have tried each of the following but I still get an error inside b.py saying "There is no such module a".
import a
import .a
import Comp.a
import StockTracker.Comp.a
import os
import sys
sys.path.append('.')
import a
sys.path.remove('.')
from .. import a
Should do it. This will only work on recent versions of Python--from 2.6, I believe [Edit: since 2.5].
Each level (Comp and Subcomp) must also be have an __init__.py file for this to work. You've said that they do.
When packages are structured into
subpackages (as with the sound package
in the example), you can use absolute
imports to refer to submodules of
siblings packages. For example, if the
module sound.filters.vocoder needs to
use the echo module in the
sound.effects package, it can use from
sound.effects import echo.
Starting with Python 2.5, in addition
to the implicit relative imports
described above, you can write
explicit relative imports with the
from module import name form of import
statement. These explicit relative
imports use leading dots to indicate
the current and parent packages
involved in the relative import. From
the surround module for example, you
might use:
from . import echo
from .. import formats
from ..filters import equalizer
Quote from here http://docs.python.org/tutorial/modules.html#intra-package-references
If the Comp directory is in your PYTHONPATH environment variable, plain old
import a
will work.
If you're using Linux or OS X, and launching your program from the bash shell, you can accomplish that by
export PYTHONPATH=$PYTHONPATH:/path/to/Comp
For Windows, take a look at these links:
http://docs.python.org/using/windows.html
http://www.itechtalk.com/thread3595.html
EDIT:
To modify the path programmatically, you were on the right track in your original question. You just need to add the parent directory instead of the current directory.
sys.path.append("..")
import a