Using absolute import while in developing Python modules? - python

I know relative imports are not suggested, such as quoted from PEP8:
Relative imports for intra-package imports are highly discouraged.
Always use the absolute package path for all imports. Even now that
PEP 328 is fully implemented in Python 2.5, its style of explicit
relative imports is actively discouraged; absolute imports are more
portable and usually more readable.
What if I am developing a package (with several modules)? While in development, absolute import won't work w/o installing/deploying the package. Does that mean I have to periodically install/deploy the current WIP modules just for testing?
Here is an example provided by Cld. Given a Python project/package:
myproject/
package1/
__init__.py
somemodule.py
package2/
__init__.py
somemodule.py
somescript.py
main.py
In main.py, absolute-import works quite well:
import package1
import package2.somescript
import package2.somemodule
However, for modules, like somescript.py in package2, the following absolute-imports:
import package2.somemodule
import package1
It would raise ImportError:
Traceback (most recent call last):
File "package2/somescript.py", line 1, in <module>
import package2.somemodule
ImportError: No module named package2.somemodule

Depand where you 'main' file is.
if you have:
myproject/
package1/
__init__.py
somemodule.py
package2/
__init__.py
somemodule.py
somescript.py
main.py
somescript.py:
import package2.somemodule
import package1
main.py
import package1
import package2.somescript
import package2.somemodule
If you execute: python package2/somescript.py you get an error
Traceback (most recent call last):
File "package2/somescript.py", line 1, in <module>
import package2.somemodule
ImportError: No module named package2.somemodule
But if you execute python main.py, you get no problem.

One common practice is pip install -e /path_to_your_pkg/, which will create a symbolic link of your package in the Python site-packages directory (not copying it as in standard install), doing so will enable:
import your_pkg anywhere
you can keep developing/updating your package and the installed version is always the latest
One known issue is if you are following PEP 517 and replace setup.py with setup.cfg and pyproject.toml, the pip install -e does not work. You need a dump setup.py as follows to fix this compatibility issue (still an issue in Jan 2021):
import setuptools
setuptools.setup()

Related

Some questions about __init__.py

enviroment: python3.8
directory:
test\
module1\
__init__.py
mod1.py
module2\
mod2.py
main.py
1. I can import a directory without __init__.py , why?
I want to check how exactly init.py work, so I import the module1 and module2 in main.py
# test\main.py
from module1 import mod1
from module2 import mod2
In my expectation, line2 should occur error, because I didn't create __init__.py in module2
But both of them can be imported.
Now, I'm confused about how exactly __init__.py work
2. I can't import those package which is imported in __init__.py
I try to import mod1.py in main.py in this way:
# test\main.py
import module1
module.mod1.mod1_print() # mod1_print() is a function which is defined in mod1.py
So I import mod1.py in test\module1\__init__.py :
# test\module1\__init__.py
import mod1
But when I execute main.py I got this error:
D:\>"C:/Program Files/Python38/python.exe" d:/test/main.py
Traceback (most recent call last):
File "d:/test/main.py", line 2, in <module>
import module1
File "d:\test\module1\__init__.py", line 1, in <module>
import mod1
ModuleNotFoundError: No module named 'mod1'
My question is:
If I want to import mod_print() in this form: module.mod1.mod1_print() , what should I do?
Python 3.3+ has Implicit Namespace Packages that allow it to create packages without an __init__.py file.
Allowing implicit namespace packages means that the requirement to provide an init.py file can be dropped completely, and affected portions can be installed into a common directory or split across multiple directories as distributions see fit.
see https://stackoverflow.com/a/37140173/9822 - python >= 3.3 dropped the requirement for __init__.py.
You could try something like this in module1/__init__.py:
import module1.mod1

Import error with unit tests: "No module named ..." from local libary

I'm new to Python (JS developer) and am trying to run a testing suite. My project folder structure is as such:
project/
__init__.py
libs/
__init__.py
s3panda.py
tests
__init__.py
tests_s3panda.py
In terminal, I'm running python tests_s3panda.py.
I don't understand how it's unable to find a local module:
Traceback (most recent call last): File "tests_s3panda.py", line 7,
in
from libs.s3panda import S3Panda ImportError: No module named libs.s3panda
tests_s3panda.py snippet:
from __future__ import absolute_import
import unittest
import pandas as pd
from libs.s3panda import S3Panda
class TestS3Panda(unittest.TestCase):
...
Doing from ..libs.s3panda import S3Panda for relative path, I get:
ValueError: Attempted relative import in non-package
I believe the fact that there is no init.py in the top-level folder means that Python is not aware that libs and tests are both part of the same module called project.
Try adding an __init__.py to your project folder, then write the import statement as from project.libs.s3panda import S3Panda. In general, you want to specify absolute imports rather than relative imports (When to use absolute imports).

Why simple import of module in same directory is not allowed

I've created two modules in the same directory:
.
├── mod1.py
├── mod2.py
There is no __init__.py, I don't want to create this as a package, I'm just creating a simple script which I have modularized by breaking into different modules.
My intention is to run mod1.py using python mod1.py
~/junk/imports$ cat mod1.py
from . import mod2
print(mod2.some_expr)
$ cat mod2.py
some_expr = 'hello world!'
Although I know that directly using import mod1 will work, but I'm deliberately not using it so that my module name doesn't clash with built in modules (which I felt is a good practice)
I'm getting the following errors with python2 and python3
~/junk/imports$ python3 --version
Python 3.4.3
kartik#kartik-lappy:~/junk/imports$ python3 mod1.py
Traceback (most recent call last):
File "mod1.py", line 1, in <module>
from . import mod2
SystemError: Parent module '' not loaded, cannot perform relative import
~/junk/imports$ python2 --version
Python 2.7.11
~/junk/imports$ python2 mod1.py
Traceback (most recent call last):
File "mod1.py", line 1, in <module>
from . import mod2
ValueError: Attempted relative import in non-package
Most of the questions like this on StackOverflow deal with packages, but I'm not using packages. I just want to run it as a simple script.
My question is not about how to do it, but I want to know the reason behind the above not working.
You shouldn't use relative, but absolute import:
import mod2
print(mod2.some_expr)
The documentation is pretty good, and this SO answers gives an alternative using importlib.
If a handmade module clash with a builtin module, the proper way to go is probably to rename it, eventually through addition of a {pre,suf}fix.
Another is to use importlib.
The motivation underlying these limitation can be found in the PEP 328, and comes mainly from BDFL preferences, over all other solutions.

How to import package modules from in-package "main" module

My package structure is:
main.py
mapp/
__init__.py
core/
__init__.py
tobeimported.py
test/
__init__.py
(test modules)
utils/
__init__.py
blasttofasta.py
The file blasttofasta.py is executed as script.
blasttofasta.py looks like:
import mapp.core.tobeimported
def somefunc():
pass
if __name__ == '__main__':
pass
But Exception occurs:
Traceback (most recent call last):
File "utils/blasttofasta.py", line 5, in <module>
import mapp.core.tobeimported
ImportError: No module named mapp.core.analyzers
How to import tobeimported module? I run the blasttofasta.py from top directory (where main.py is)
EDIT: Maybe better question is: How to get mapp package to the sys.path? Because script file only see its own directory but not the package directory.
Thank you
If I want to including blasttofasta.py or run it as script simultaneously mos important is to have directory containing mapp package in sys.path.
This worked for me:
Before importing mapp (or other module from this package) I wrote into blasttofasta.py:
import os
os.sys.path.append(os.path.dirname(os.path.realpath(__file__))+ '/../../')
This append mapp package path and I can run it as script. On the other side is no problem with is included in another package.
Follow the absolute structure to import.
To import blasttofasta.py in tobeimport.py
ToBeimport contents
from myapp.utils import blasttofasta
Your structure is good.
Two things need to happen:
Your map directory needs a __init__.py file.
You can simply do this (naively):
$ touch /path/to/map/__init__.py
/path/to/map needs to be in sys.path
Please read: http://docs.python.org/2/tutorial/modules.html for more details.

Import from different directories in python

This is my folder structure:
src/
__init__py
Lowlevel/
__init__.py
ModuleToCheck.Py
Test/
__init__.py
ModuleToCheck_test.py
(__init__.py are empty files)
Now I want to import ModuleToCheck.py in ModuleToCheck_test.py
How am I able to do this without appending anything to sys.path?
Update:
from ..Lowlevel import ModuleToCheck leads to:
src$ python Test/ModuleToCheck_test.py
Traceback (most recent call last):
File "Test/ModuleToCheck_test.py", line 6, in <module>
from ..Lowlevel import ModuleToCheck
ValueError: Attempted relative import in non-package
The following is from http://docs.python.org/tutorial/modules.html#intra-package-references
Note that both explicit and implicit
relative imports are based on the name
of the current module. Since the name
of the main module is always
"__main__", modules intended for use
as the main module of a Python
application should always use absolute
imports.
You're running your module ModuleToCheck_test.py as the main module, hence the exception.
One solution is to create a test.py module in your src directory containing the following:
import Test.ModuleToCheck_test
You can then run that module using python test.py

Categories

Resources