Importing your own Python modules - python

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.

Related

Import a library which is in a sibling of the current folder

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.

Python - fails importing package

I have trouble importing package.
My file structure is like this:
filelib/
__init__.py
converters/
__init__.py
cmp2locus.py
modelmaker/
__init__.py
command_file.py
In module command_file.py I have a class named CommandFile which i want to call in the cmp2locus.py module.
I have tried the following in cmp2locus.py module:
import filelib.modelmaker.command_file
import modelmaker.command_file
from filelib.modelmaker.command_file import CommandFile
All these options return ImportError: No modules named ...
Appreciate any hint on solving this. I do not understand why this import does not work.
To perform these imports you have 3 options, I'll list them in the order I'd prefer. (For all of these options I will be assuming python 3)
Relative imports
Your file structure looks like a proper package file structure so this should work however anyone else trying this option should note that it requires you to be in a package; this won't work for some random script.
You'll also need to run the script doing the importing from outside the package, for example by importing it and running it from there rather than just running the cmp2locus.py script directly
Then you'll need to change your imports to be relative by using ..
So:
import filelib.modelmaker.command_file
becomes
from ..modelmaker import command_file
The .. refers to the parent folder (like the hidden file in file systems).
Also note you have to use the from import syntax because names starting with .. aren't valid identifiers in python. However you can of course import it as whatever you'd like using from import as.
See also the PEP
Absolute imports
If you place your package in site-packages (the directories returned by site.getsitepackages()) you will be able to use the format of imports that you were trying to use in the question. Note that this requires any users of your package to install it there too so this isn't ideal (although they probably would, relying on it is bad).
Modifying the python path
As Meera answered you can also directly modify the python path by using sys.
I dislike this option personally as it feels very 'hacky' but I've been told it can be useful as it gives you precise control of what you can import.
To import from another folder, you have to append that path of the folder to sys.path:
import sys
sys.path.append('path/filelib/modelmaker')
import command_file

Python3 correct way to import relative or absolute?

I am writing a python module neuralnet. It was working all fine in Python2, but in Python3 imports are failing.
This is my code structure.
neuralnet/
__init__.py
train.py # A wrapper to train (does not define new things)
neuralnet.py # Defines the workhorse class neuralnet
layer/
__init__.py
inlayer.py # Defines input layer class
hiddenlayer.py
application/ # A seperate application (not part of the package)
classify.py # Imports the neuralnet class from neuralnet.py
train.py needs to import neuralnet.py's neuralnet class.
neuralnet.py needs to import layers/inlayer.py etc.
(I prefer relative imports.)
I have a different application (classify.py) which needs to import this module.
Where I do...
from neuralnet.neuralnet import neuralnet
I have tried a few ways to import.
Either I get an error (mostly arcane like parent is not imported)
While running train.py (which is a part of the neuralnet module)
from . import layer # In file neuralnet.py
SystemError: Parent module '' not loaded, cannot perform relative import
Or
while running classify.py (which is outside the module).
from layer.inlayers import input_layer # In file neuralnet.py
ImportError: No module named 'layer'
My imports worked perfectly well for years in Python2. I am wondering what Python3 expects of me? Should I move train.py to outside my module (technically it is not a part of the module)? Please suggest best practice.
In Python 3, implicit relative imports are forbidden, see https://www.python.org/dev/peps/pep-0328/ and https://docs.python.org/release/3.0.1/whatsnew/3.0.html#removed-syntax:
The only acceptable syntax for relative imports is from .[module]
import name. All import forms not starting with . are interpreted as
absolute imports. (PEP 0328)
from .stuff import Stuff is an explicit relative import, which you "should" make use of whenever possible, and must use in Python 3, whenever possible. Head over to https://stackoverflow.com/a/12173406/145400 for a deeper analysis on relative imports.
Relative import usage has changed from python2 to python3,
The only acceptable syntax for relative imports is from .[module] import name. All import forms not starting with . are interpreted as absolute imports. (PEP 0328)
Python’s -m switch allows running a module as a script. When you ran a module that was located inside a package, relative imports didn’t work correctly.
The fix for Python 2.6 adds a __package__ attribute to modules. When this attribute is present, relative imports will be relative to the value of this attribute instead of the __name__ attribute. (PEP 0366)
To your questions:
You get SystemError: Parent module '' not loaded, cannot perform relative import or
in Python3.5 and forward you would get ImportError: attempted relative import with no known parent package when
you run python neuralnet.py and try to import from . import layers as your __package__ would be None and PYTHONPATH will only have current file(and not its parent), hence it can't find layer.
You may either run the module like this:
python -m neuralnet.neuralnet
Here your __package__ will be neuralnet, hence you will be able to import the neuralnet module which is within it.
Or you may do this workaround:
Update the __init__.py in neuralnet package to:
import os
import sys
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
Then run your script neuralnet.py, the above lines will add neuralnet directory to the PYTHONPATH.
You get ImportError: No module named 'layer' when layer is not a module that is in your PYTHONPATH so either install it or add it to the PATH using
import sys
sys.path.append("/path/to/layer")
Background:
Part of a message from Guido(author of Python):
... in 2.4, we introduce the leading dot notation for relative import,
while still allowing relative import without a leading dot. In
2.5 we can start warning about relative import without a leading dot
(although that will undoubtedly get complaints from folks who have
code that needs to work with 2.3 still). In 3.0 we can retire ambiguous import.
The use case for multiple dots should be obvious: inside a highly
structured package, modules inside one subpackage must have a way to
do relative import from another subpackage of the same parent package.
There is the remaining issue of what exactly the syntax would be. I
propose to extend the from clause to allow one or more dots before the
dotted name, and to make the dotted name optional if at least one
leading dot is found. I propose not to change from-less import.
Examples:
from .foo import bar
from .foo.bar import xxx
from . import foobar as barfoo
from ..foo.bar import *
from ... import foobar, barfoo
Relavent PEP to read: PEP-328

Python: Importing a file from a parent folder

...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

Python: import the containing package

In a module residing inside a package, i have the need to use a function defined within the __init__.py of that package. how can i import the package within the module that resides within the package, so i can use that function?
Importing __init__ inside the module will not import the package, but instead a module named __init__, leading to two copies of things with different names...
Is there a pythonic way to do this?
Also, starting in Python 2.5, relative imports are possible. e.g.:
from . import foo
Quoting from http://docs.python.org/tutorial/modules.html#intra-package-references:
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 surrounding module for example, you might use:
from . import echo
from .. import formats
from ..filters import equalizer
This doesn't exactly answer your question, but I'm going to suggest that you move the function outside of the __init__.py file, and into another module inside that package. You can then easily import that function into your other module. If you want, you can have an import statement in the __init__.py file that will import that function (when the package is imported) as well.
If the package is named testmod and your init file is therefore testmod/__init__.py and your module within the package is submod.py then from within submod.py file, you should just be able to say import testmod and use whatever you want that's defined in testmod.
I'm not totally sure what the situation is, but this may solve your "different name" problem:
import __init__ as top
top.some_function()
Or maybe?:
from __init__ import some_function
some_function()
In Django, the file manage.py has from django.core.management import execute_manager, but execute_manager is not a module. It is a function within the __init__.py module of the management directory.

Categories

Resources