Python not able to reference module in parent - python

I am trying to set up a library in python. I have created a setup.py file and in a folder under that I have a library folder, and then I tried to create an sample and test folder (for sample code and tests that I would include)
Folders:
- setup.py
- cvImageUtils # this is the library
- __init__.py # this includs ColorUtils
- ColorUtils.py # this includes a class called ColorUtils
- examples
- color.py # this is shown below
init.py in ColorUtils folder
from . import ColorUtils
ColorUtils.py
class ColorUtils:
def __...
Color.py
from cvImageUtils import ColorUtils
m1 = cv2.imread(os.path.join(image_folder, "bb.jpeg"), 1) # 1 = load color
cv2.imshow('grayscale', ColorUtils.convert_rbg_to_grayscale(m1))
At first, it said, unable to find the module, so I added to the top of the file the following based on another SO solution:
import sys
sys.path.append('../')
Now that seems broken to me already, but it did get me past the no module found, but now it says ColorUtils has no method convert_rbg_to_grayscale. So Then I had to change it to ColorUtils.ColorUtils.convert_rbg_to_grayscale
cv2.imshow('grayscale', ColorUtils.ColorUtils.convert_rbg_to_grayscale(m1))
How can I setup the folder so that it allows me to include the library without sys, and call it without declaring ColorUtils twice.

change your __init__.py:
from cvImageUtils.ColorUtils import ColorUtils
I don't think you'll need to import sys anymore, and you don't have import ColorUtils twice. but just like you have to instantiate an object, you should create a ColorUtils object.
my personal preference would be not creating a Class for Utils.
you might have done this already, but if you want to use a method straight from a class like you did in python, you might want to declare it static.
class ColorUtils:
#staticmethod
def util_method():
pass
then you can just do:
ColorUtils.util_method()
Update:
you can read more about relative/absolute import from here as well.
to fix your actual problem though, you can do:
color.py
remove your import sys and sys call from color.py
change: import cvImageUtils.ColorUtils as ct
to: from cvImageUtils.ColorUtils import *
remove all your ct reference instead just use the actual functions.
cvImageUtils/__init__.py
change: from . import ColorUtils
to __all__=['ColorUtils']
I was able to run color.py to get all the images printed out on screen.
a image.png was also generated locally as well.

Every directory that you want to expose in module search(we usually hide test.py) in python need a init.py file. That should be rule of thumb, by using sys module you can add the module to your "module search path".
After having init.py in your directories, you need to import packages/modules/funcitons you want to use:-
import cvImageUtils.ColorUtils.convert_rbg_to_grayscale
You can execute following code in python to see, what have included in your sys path(used by python to search for modules/packages)
import sys
sys.path
Look into below links for more detailed explations
https://www.programiz.com/python-programming/package
https://www.programiz.com/python-programming/modules#search

Related

ImportError attempted relative import with no known parent

Based on some answers I try to be more specific.
I want to import the print and the models AND code in my main.py
I know the question gets asked a lot, but still I could not figure out whats wrong with my code!
I have a project directory like this
-project
--__init__py
--main.py
--print.py
--requests
--__init__.py
--models.py
--code.py
i want to import from print.py and * from requests
Therefore I tried to add these lines in main.py
from . import print
#or
import print
#for requests I tried
import os.path
import sys
sys.path.append('./requests')
from requests import *
all of those lines cause the same ImportError attempted relative import with no known parent ,
using Python 39
anyone an idea where the problem is?
I am very confused that this seems not to work, was it possible in older versions?
You should definitely not be doing anything with sys.path. If you are using a correct Python package structure, the import system should handle everything like this.
From the directory structure you described, project would be the name of your package. So when using your package in some external code you would do
import package
or to use a submodule/subpackage
import project.print
import project.requests
and so on.
For modules inside the package you can use relative imports. When you write
i want to import from print.py and * from requests Therefore I tried
it's not clear from where you want to import them, because this is important for relative imports.
For example, in project/main.py to import the print module you could use:
from . import print
But if it's from project/requests/code.py you would use
from .. import print
As an aside, "print" is probably not a good name for a module, since if you import the print module it will shadow the print() built-in function.
Your main file should be outside the 'project'-directory to use that as a package.
Then, from your main file, you can import using from project.print import ....
Within the project-package, relative imports are possible.

Override importlib to dynamically rename imported modules in python

I've got one source code which is compiled into two QGis plugins, on this model:
SourceCode -> build.py -> * MyPlugin.zip
* MyPluginExtended.zip
Since the cleanest way to import modules in QGis is to import them from the plugins directory (i.e. the parent directory), all the import statements in the MyPlugin code look like:
import MyPlugin.foo
import MyPlugin.foo.bar
from MyPlugin import foo`
But the problem is, the same import statements will be duplicated from the source code in the MyPluginExtended code, causing ModuleNotFound errors.
The QGis system prevents me to put my final code in a subdirectory that I would have then added to the sys.path, like this:
[Plugins directory] / MyPluginExtended / MyPlugin / [my files]
So the only solutions I could think of were:
1. Override the import system to dynamically replacing MyPlugin in every search path by MyPluginExtended
I tried to setup a custom importer, like proposed in the importlib documentation, doing something like this in my __init__ file, but none of my attempts worked:
try:
import MyPluginExtended
# this is the extended plugin, imports need to be overriden
class MyPathFinder():
# when imports contains 'MyPlugin', change the search path from `path/to/MyPlugin` to `path/to/MyPluginextended`
sys.meta_path.append(MyPathFinder)
except ImportError:
# this is the basic plugin, nothing to do
pass
2. Manually create aliases in sys.modules, like this:
import MyPlugin
sys.modules['MyPluginExtended'] = MyPlugin
But I would then have to do it for every submodule, and I don't knwo how to discover them programatically, something like:
for module_fullname, module in available_submodules():
module_fullname = module_fullname.replace('MyPlugin/', 'MyPluginExtended/')
sys.modules[module_fullname] = module

Cannot import function from another file

I have a file called hotel_helper.py from which I want to import a function called demo1, but I am unable to import it.
My hotel_helper.py file:
def demo1():
print('\n\n trying to import this function ')
My other file:
from hotel.helpers.hotel_helper import demo1
demo1()
but I get:
ImportError: cannot import name 'demo1' from 'hotel.helpers.hotel_helper'
When I import using from hotel.helpers.hotel_helper import * instead of from hotel.helpers.hotel_helper import demo1 it works and the function gets called. I tried importing the whole file with from hotel.helpers import hotel_helper and then call the function with hotel_helper.demo1() and it works fine. I don't understand what's wrong in first method. I want to directly import function rather using * or importing the whole file.
If you filename is hotel_helper.py you have to options how to import demo1:
You can import the whole module hotel_helper as and then call your func:
import hotel_helper as hh
hh.demo1()
You can import only function demo1 from module as:
from hote_helpers import demo1
demo1()
From your fileName import your function
from hotel.helpers import demo1
demo1()
You can import a py file with the following statement:
# Other import
import os
import sys
if './hotel' not in sys.path:
sys.path.insert(0, './hotel')
from hotel import *
NOTE:
For IDE like PyCharm, you can specify the import path using the Project Structure setting tab (CTRL+ALT+S)
Helpful stack overflow questions [maybe off topic]:
What is the right way to create project structure in pycharm?
Manage import with PyCharm documentation:
https://www.jetbrains.com/help/pycharm/configuring-project-structure.html
This is probably a duplicate of: https://stackoverflow.com/posts/57944151/edit
I created two files (defdemo.py and rundefdemo.py) from your posted 2 files and substituted 'defdemo' for 'hotel.helpers.hotel_helper' in the code. My 2 files are in my script directory for Python 3.7 on windows 10 and my script directory is in the python path file python37._pth. It worked.
defdemo.py
def demo1():
print('\n\n trying to import this function ')
rundefdemo.py
from defdemo import demo1
demo1()
output
trying to import this function
I was able to solve the issue, it was related to some imports I was making in my file, when I removed all the import statement in my hotel_helper.py ,the code started working as expected , Still I don't understand reason why the issue was occurring. anyway it works.
This ImportError can also arise when the function being imported is already defined somewhere else in the main script (i.e. calling script) or notebook, or when it is defined in a separate dependency (i.e. another module). This happens most often during development, when the developer forgets to comment out or delete the function definition in the body of a main file or nb after moving it to a module.
Make sure there are no other versions of the function in your development environment and dependencies.

python importing file on virtual environment

I am writing a web app using python3, venv and c9.io PAAS. I have the following structure of my code:
batch_runner.py
logic/
__init__.py
parsers/
__init__.py
time_parser.py
abstract_parser.py
here batch_runner imports abstract_parser, which, in it turn, import from time_parser. everything was installed and runs with venv activated.
To be specific, batch_runner.py contains:
from logic.parsers import abstract
from sys import argv
url = argv[1]
a = abstract(url)
logic/__init__.py is empty. logic/parsers/__init__.py contains:
from abstract_parser import abstract
from time_parser import _timeInfo
If I go to logic and run python abstract_parser.py directly, everything works as expected. However, if I go one level up, and run python batch_runner.py, it is able to import abstract_parser, but it can't find time_parser which is called from abstract_parser, throwing ImportError: No module named 'abstract'
Change this:
from abstract_parser import abstract
To
from logic.parsers.abstract_parser import abstract
Do read about importing from the python documentation on modules.
In this case, one possible solution is to use relative imports inside your package:
That is, in logic/parsers/__init__.py, use:
from .abstract_parser import abstract
from .time_parser import _timeInfo
and in abstract_parser.py:
from .time_parser import _timeInfo
This should let parsers/__init__.py find the abstract_parser module and the time_parser module.
The python import system has a surprising number of traps that you can fall into. This blog post by Nick Coghlan describes many of them, and I personally consider it a must-read if you're planning to develop a package.

How do I import from a file in the current directory in Python 3?

In python 2 I can create a module like this:
parent
->module
->__init__.py (init calls 'from file import ClassName')
file.py
->class ClassName(obj)
And this works. In python 3 I can do the same thing from the command interpreter and it works (edit: This worked because I was in the same directory running the interpreter). However if I create __ init __.py and do the same thing like this:
"""__init__.py"""
from file import ClassName
"""file.py"""
class ClassName(object): ...etc etc
I get ImportError: cannot import name 'ClassName', it doesn't see 'file' at all. It will do this as soon as I import the module even though I can import everything by referencing it directly (which I don't want to do as it's completely inconsistent with the rest of our codebase). What gives?
In python 3 all imports are absolute unless a relative path is given to perform the import from. You will either need to use an absolute or relative import.
Absolute import:
from parent.file import ClassName
Relative import:
from . file import ClassName
# look for the module file in same directory as the current module
Try import it this way:
from .file import ClassName
See here more info on "Guido's decision" on imports in python 3 and complete example on how to import in python 3.

Categories

Resources