Is there a way to solve import issues with __init__.py? - python

I have a package with this structure
framework/
__init__.py
file0.py
file1.py
file2.py
file3.py
I want to able to import it as import framework, but I'm not able to do it that way, only from framework import * works, and that too without autocomplete. file0.py and file1.py are classes, and the others have only functions.
Autocomplete works, however, when I manually do this on the file I'm working on in an external directory
from framework import file0
from file0 import *
# and so on for the others
This is my __init.py__
from framework.file0 import file0
from framework.file1 import file1
from framework.file2 import *
from framework.file3 import *
I've tried putting
from framework import file0
from file0 import *
# and so on for the others
on __init.py__ but it doesn't solve the issue, autocomplete still doesn't work unless I put them in the actual file I'm working on in another directory. I want it to able to work on import framework
Is there a way?
Thanks in advance. I'm new to this, so any advice is appreciated.

What you want for your __init__.py is from .file0 import file0, or whatever content from file0.py you want to import.
See Package relative imports in Python docs.
However, I think it's ill adviced to import everything in a package to __init__.py. If you do that, it will be loaded into python every time you try to import anything from that package. Say you want to do from framework.file0 import SomeClass into some other package, and that class is all you need from framework. If you import everything in __init__py, you will be loading all that every time you touch that package, since __init__.py is always loaded when accessing the package.
If you want a way to import everything from the package, maybe you should put that in another file, say all.py, and then do from framework import all as framework?

Conventionally, __init__.py is to be left blank.
Then in the script file where you need to import the complete package (with all the files), put this at the top and you should be good to go.
import framework
And if you want to import only one module for some reason, say framework.file0, you can use
import framework.file0
As far as autocompletion is concerned, this approach worked for me, in JupyterLab Notebook as well as the console.

Related

How to make relative import work with dot inside a python package?

I have a folder named as "model_dir" contains multiple *.py files.
model_dir:
"model.py"
"utils.py"
inside model.py I can import like this: from utils import test
I want to copy the whole folder inside a package. Currently to make the import works inside the package I have two options:
1- adding folder path to sys.path
2- add dot for imports, like this: from .utils import test
Is there any way to make imports work without changing the code or sys path?
Have you tried including a blank __init__.py file in the model_dir folder? That should let python files import sibling files- I'm a novice dev myself and often run into pitfalls with imports inside packages, and I've found this link
to be pretty helpful figuring out what I've done wrong

How do I import a file that is in another directory?

-Booking
-components
-db.py
-scripts
-insert_data.py
How do I import db.py in insert_data.py?
(I'm using python 3)
from components import db
Should work as long as components has a (potentially empty) __init__.py in it
Put __init__.py inside components folder
Access it from scripts folder using from ..components import db
There are several options, and it helps to know how Python's modules and packages work (which is not always completely straightforward and intuitive):
What's the difference between a Python module and a Python package?
What is __init__.py for?
Importing files from different folder
Relative imports for the billionth time
How to import a module given the full path?
https://docs.python.org/3/reference/import.html (even the official documentation can be helpful at times :)
One way is to explicitly modify the module search path in the beginning of your script:
import sys, os
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'components'))
import db
A less hacky way uses relative import, as described in Importing from a relative path in Python and Execution of Python code with -m option or not.

Custom python package includes self as member

I have a simple python package that I am able to use and import, but that is behaving unexpectedly. The package structure is
package_name
__init__.py
modfile1.py
modfile2.py
in __init__.py I have
import package_name.modfile1
import package_name.modfile2
If I open a python interpreter and
import package_name
I then see the following autocomplete choices (via jedi)
package_name.modfile1 package_name.modfile2 package_name.package_name
If I use package_name.package_name this can continue recursively. Why is the package listed as a member of itself?
This is normal.
package_name.modfile1 would even exist if __init__.py were empty. It's just a module name, that you could import (with import package_name.modfile1)
same for package_name.modfile2
in __init__.py you import package_name.modfile1
So if you imported package_name, then the tab completion will offer you the symbols from __init__.py within package_name
Thus you get package_name.package_name.modfile1 and package_name.package_name.modfile2
Just comment the two imports from __init__.py and these symbols will disappear.
You could change the lines
import package_name.modfile1
import package_name.modfile2
to
import package_name.modfile1 as modfile1
import package_name.modfile2 as modfile2
To have a more consistent naming.
If you keep the __init__.py file empty
You have to use either
import package_name.modfile1
or
from package_name import modfile1
If you have it populated with my last suggestion you can just use.
import package_name
and then directly access package_name.modfile1
Please note, that adding imports to the __init__.py file has one small side effect.
whenever you package_name modified1 and modified2 will always be imported into RAM. Even if you imported package_name.modfile1 then package_name.modfile2 would also be loaded into RAM.
Therefore I personally keep the init files almost always empty and import explicitly what I want.
exceptions being, where I know, that modfile1 and modfile2 will always be used together.
Just do whatever fits best your purpose.

Yet another Python Relative import mishap

#Background and Problem#
I'm trying to build a web-scraper to back up my social media accounts (summer project, I know it's useless).
I'm trying to create a nice class structure, so I've come up with the following structure (I accept critique, I'm pretty new to programming):
\social-media-backup
\Files
__init__.py
File.py
Image.py
Video.py
\SocialMedia
SocialMediaFeed.py
SocialMediaPost.py
\Instagram
__init__.py
\MediaTypes
__init__.py
GraphImage.py
GraphVideo.py
\SearchTypes
__init__.py
InstagramUser.py
\Twitter
\VSCO
(Twitter and VSCO are, for now, empty. Anything without extension and starting with , is a folder. Every file has a class with the same name as the file inside)
#Questions#
Where can I learn Python's packaging system definitively? Any book or web-site recommendation?
How would I import Image into GraphImage? How would I import File into SocialMediaPost?
What do I need to write in __init__.py so as to import SOME_PACKAGE and have it import every module? (e.g.: import Files and have Files.Image and File.Video accessible).
(I know there are a lot of questions. They're written in order of importance)
#To accomplish importing File into SocialMediaPost I've tried:#
from Files.File import File
from ...Files.File import File
import File
from File import File
And almost any combination you can imagine.
I always get an Unable to import, No module named '__main__.Files' or Attempted relative import beyond top-level package.
#Expected behavior#
I'm used to Java's way of doing this, and I cannot figure out how to do this in Python. It seems so messed up. I really miss just adding a package and a folder tree from where the compiler would run.
knocks desk THERE MUST BE A BETTER WAY
##THANKS!!##
Lots of stuff is written about this... however most guides focus on how you do it, not what to do.
How I do it (for small to medium-sized projects):
Do not mess with sys.path.
Have one "project root" directory with your modules / packages underneath (as you already do).
Use absolute imports always, except for "sister" modules.
Always run as module, i.e. using python -m foo.bar
Concrete example using your structure. Assuming that your entry point might be in \SocialMedia\SocialMediaFeed.py, use import statements:
from . import SocialMediaPost (sister module)
import Instagram (child module)
from Files import Image (other module)
and run using: python -m SocialMedia.SocialMediaFeed
By running as module, you always have the project root (social-media-backup) added as "search path". This way absolute imports refering to its subfolders always work. By the way, you can print out the module search path using import sys; print(sys.path).
Some of this might seem overcomplicated, but I found that following the above points pays out greatly as soon as you try to package up stuff for installation (keyword setup.py).
Edit: to answer 3rd question: Have __init__.py contain:
from . import File
from . import Image
from . import Video
I would second the comments by Damian and user2357112 - try to avoid name collisions between folder, file and class/function when creating modules.
You probably won't be able to import anything outside of the current working directory without adding it to your PYTHONPATH. Adding a folder to your PYTHONPATH environment variable means that python will always check that folder when importing modules, so you'll be able to import it from anywhere.
There is a good thread on this already that will put you in the right direction:
Permanently add a directory to PYTHONPATH?
(It's a lot to cover in one post)

How can I import a package from within the package?

I'm writing a little package and I'm trying to include a demo script within it as an example. However, I can't seem to import the package cleanly from within as though I was outside of it.
With a directory structure like:
trainer/
__init__.py
helper.py
trainer.py
[...more files...]
demo.py
In demo.py I can't do from .. import trainer as it complains "Attempted relative import in non-package", despite the __init__.py. If I move the demo up a directory and import trainer it works fine, but I was trying to keep it together with the package.
The hack-looking import __init__ as trainer works, but eeeew.
Importing the various bits from all over the module directly also works, but makes for a messy example. Am I wholly misguided in my attempt or is there a better solution?
If you're trying to run demo.py as python demo.py, the problem that you're having is likely the same as here.
What's happening is that Python's relative import mechanism works by using the __name__ of the current module. When you execute a module directly, the __name__ gets set "__main__" regardless what the actual module name is. Thus, relative (in-package) imports don't work.
To remedy this, you can do the following:
Execute demo.py as a module within a package, like so: python -m trainer.demo. This should fix the error, but you'll still be importing the trainer.py module instead of the package.
Now add from __future__ import absolute_import to demo.py, which will cause your imports to be absolute-only by default, meaning that relative imports have to explicit (as in, from . import (...)). This is force import trainer to import the entire top-level package, instead of the module.
The way you organize the files, demo.py becomes part of the package, which might or might not be what you want. You can organize your files a little differently, moving demo.py outside of the trainer directory:
TopDir/
demo.py
trainer/
__init__.py
helper.py
trainer.py
[... more files ...]
Then, demo.py can do something like:
from trainer import trainer, helper

Categories