I am trying to import the class PBase which is in base.py(its in the same folder)
So I am doing the following
from base import PBase
but I am getting the following error
Traceback (most recent call last):
File "test_pricing.py", line 9, in <module>
from base import PBase
ImportError: cannot import name PBase
here is my base.py
import yaml
import unittest, time, re
class PBase(unittest.TestCase):
def enter_credentials(self, username, password):
self.driver.find_element_by_id("id_username").clear
self.driver.find_element_by_id("id_username").send_keys(username)
self.driver.find_element_by_id("id_password").clear
self.driver.find_element_by_id("id_password").send_keys(password)
self.driver.find_element_by_css_selector("input.btn.btn-success").click()
def get_credentials(self):
with open('credentials.yml', 'r') as f:
doc=yaml.load(f)
return doc
def is_user_logged_in(self):
f= "Account" in self.driver.find_element_by_css_selector(".navbar").text
return f
def log_in_user(self):
self.driver.get(self.login_url)
user_dict=self.get_credentials()
username=user_dict["user"]["username"]
password=user_dict["user"]["password"]
self.enter_credentials(username, password)
self.assertEqual(self.expected_logged_in_title, self.driver.title)
def wait_for_chat_window(self, timeout=5):
WebDriverWait(self.driver, timeout, poll_frequency=0.1).until(lambda b: b.find_element_by_id('habla_beta_container_do_not_rely_on_div_classes_or_names').is_displayed())
time.sleep(3)
def close_modal_window(self):
driver=self.driver
driver.find_element_by_xpath('//a[#class="close"]').click()
def tearDown(self):
if self.is_final_test==1:
self.driver.quit()
This might be an issue caused by importing in a circular way. For example one tries to import from Bar from bar.py that requires Foo from foo.py that requires Utils that is defined in bar.py:
foo.py:
from bar import Utils
class Foo:
def __init__(self):
print("hello, from Foo")
Utils.do_something()
and bar:
from foo import Foo
class Utils:
#staticmethod
def do_something():
print("done something")
class Bar(Foo):
def __init__(self):
print('Hi, from Bar')
This gives similar issues where one can import bar inside foo.py without any issue, but once one tries to make any reference to the class Utils inside foo.py one gets various errors, for example the previous code results in:
Traceback (most recent call last):
File "main.py", line 1, in <module>
from bar import Bar
File "bar.py", line 1, in <module>
from foo import Foo
File "foo.py", line 1, in <module>
from bar import Utils
ImportError: cannot import name 'Utils' from 'bar' (bar.py)
The issue is easily solved by placing Utils in its own file.
Related
I have the following project and module setup:
class2.py:
from mod1.class1 import Class1
class Class2(object):
def __init__(self, c1: Class1):
self.c1 = c1
class2.py:
from mod2.class2 import Class2
class Class1(object):
def __init__(self):
self.c2 = Class2(self)
main.py:
from mod1.class1 import Class1
from mod2.class2 import Class2
c1 = Class1()
c2 = Class2(c1)
The idea is that when a parent class initializing a child class, it introduces itself to the child class. This way the child class can call parent class methods.
This pattern works fine in strongly typed languages like C#.
When I run main.py, I get the following error:
Traceback (most recent call last):
File "C:\Projects.Personal\exp02\main.py", line 2, in <module>
from mod2.class2 import Class2
File "C:\Projects.Personal\exp02\mod2\class2.py", line 2, in <module>
from mod1.class1 import Class1
File "C:\Projects.Personal\exp02\mod1\class1.py", line 1, in <module>
from mod2.class2 import Class2
ImportError: cannot import name 'Class2' from partially initialized module 'mod2.class2' (most likely due to a circular import) (C:\Projects.Personal\exp02\mod2\class2.py)
Process finished with exit code 1
I just need to let Class2 know about the type of Class1.
Why am I getting such error?
What is the proper pattern to do this in Python?
Update #1
I understand that this is a circular import as it is specifically stated in the error message.
The idea explained in this article (https://stackabuse.com/python-circular-imports/) is not applicable here. Here I have Classes not module functions. I just need to annotate a variable. My code sample is very much simplified. The actual classes code is large. I don't want to combine them in one file.
IMO, This is a valid pattern and I can do it in Java or C#.
How can I implement the idea in Python?
Update #2: TYPE_CHECKING did not work
Per #RedKnite, I updated the class2.py to the following code:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from mod2.class2 import Class2
class Class1(object):
def __init__(self):
self.c2 = Class2(self)
I am getting the the following error:
Traceback (most recent call last):
File "C:\Projects.Personal\exp02\main.py", line 6, in <module>
c1 = Class1()
File "C:\Projects.Personal\exp02\mod1\class1.py", line 8, in __init__
self.c2 = Class2(self)
NameError: name 'Class2' is not defined. Did you mean: 'Class1'?
Use the TYPE_CHECKING flag from typing and make the class a string.
At runtime TYPE_CHECKING is False so the import will not execute, but a type checker should find this acceptable.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from mod1.class1 import Class1
class Class2(object):
def __init__(self, c1: "Class1"):
self.c1 = c1
You have a circular import. Your Class1 and Class2 files are attempting to import each other- i'd suggest using one file that imports both classes.
Let's take a folder structure like this:
project_root
│ start.py
└───Application
└───ViewModels
│ __init__.py
│ MagnifierWindowViewModel.py
│ MainViewModel.py
│ MainWindowViewModel.py
│ PlotterWindowViewModel.py
These are the contents of the files:
start.py
from Application.ViewModels import MainViewModel
if __name__ == "__main__":
mainViewModel = MainViewModel()
Application\ViewModels\__init__.py
from Application.ViewModels.PlotterWindowViewModel import *
from Application.ViewModels.MagnifierWindowViewModel import *
from Application.ViewModels.MainViewModel import *
from Application.ViewModels.MainWindowViewModel import *
Application\ViewModels\MagnifierWindowViewModel.py
class MagnifierWindowViewModel(object):
def __init__(self):
pass
Application\ViewModels\MainViewModel.py
from Application.ViewModels import MagnifierWindowViewModel, MainWindowViewModel, PlotterWindowViewModel
class MainViewModel(object):
def __init__(self):
self.mainWindowVM = MainWindowViewModel()
self.magnifierWindowVM = MagnifierWindowViewModel()
self.plotterWindowVM = PlotterWindowViewModel()
Application\ViewModels\MainWindowViewModel.py
class MainWindowViewModel(object):
def __init__(self):
pass
Application\ViewModels\PlotterWindowViewModel.py
class PlotterWindowViewModel(object):
def __init__(self):
pass
With this structure, I get this error:
Traceback (most recent call last):
File "project_root/start.py", line 4, in <module>
mainViewModel = MainViewModel()
File "project_root/Application/ViewModels/MainViewModel.py", line 5, in __init__
self.mainWindowVM = MainWindowViewModel()
TypeError: 'module' object is not callable
But if I put the last line in Application\ViewModels\__init__.py first, the application runs just fine. Why is that?
The reason I have this Application\ViewModels\__init__.py is so that I can write
from Application.ViewModels import MagnifierWindowViewModel
instead of
from Application.ViewModels.MagnifierWindowViewModel import MagnifierWindowViewModel
You've stuck every class in its own module named the exact same thing as the class. That's a really bad idea for the reasons you're seeing here: it is way too easy to get the class and the module mixed up.
When your MainViewModel.py performs its imports:
from Application.ViewModels import MagnifierWindowViewModel, MainWindowViewModel, PlotterWindowViewModel
what gets imported depends on how much of Application\ViewModels\__init__.py has executed. If this line has not executed:
from Application.ViewModels.MainWindowViewModel import *
then the import in MainViewModel.py imports the MainWindowViewModel module. If the import * has executed, then it shadows the MainWindowViewModel module with the MainWindowViewModel class defined inside the module, so the import in MainViewModel.py imports the MainWindowViewModel class.
I have a class JCheq, with a static var named 'logger'.
JCheq imports module printing_systems, but I need to use JCheq.logger from printing_systems.
My code does not compile after I put import JCheq in printing_systems.py.
jcheq.py
from printing_systems import printing_systems
from logger import logger
class JCheq:
logger = logger.Logger('logs/jcheq.log', loglevel=logger.Logger.INFO)
def __init__(self):
pass
...
printing_systems/printing_systems.py
from jcheq import JCheq
class WinLPR:
def __init__(self):
pass
#staticmethod
def send(spool, params):
temp_dir = tempfile.mkdtemp()
try:
JCheq.logger.log('Creando archivo temporal en dir: ' + temp_dir, logger.Logger.TRACE)
Error trace:
Traceback (most recent call last):
File "/home/jsivil/Desktop/Proyectos/UNPAZ/jcheq/jcheq/jcheq.py", line 12, in <module>
from printing_systems import printing_systems
File "/home/jsivil/Desktop/Proyectos/UNPAZ/jcheq/jcheq/printing_systems/printing_systems.py", line 7, in <module>
from jcheq import JCheq
File "/home/jsivil/Desktop/Proyectos/UNPAZ/jcheq/jcheq/jcheq.py", line 12, in <module>
from printing_systems import printing_systems
ImportError: cannot import name 'printing_systems'
Moving the import statement in the function is commonly used to solve circular imports. It is handy in cases when restructuring your application would be too costly (if useful at all).
Another solution would be to move JCheq.logger into its own module that both jcheq.py and printing_systems/printing_systems.py would import.
Or, you could make logger.Logger a factory function backed by some registry (or simply memoize it) so that it returns the same logger when the same arguments are given. This way, printing_system.py would simple import logger instead of importing jcheq.
How do I write a decorator in Python, which has some import from Foo import Foo, which is needed, when I want to use it for methods of a class, which also has this import?
Putting the import into both separate files will cause an error, telling me that Foo cannot be imported from Foo.
If it's not possible then this:
Is it a good idea, if the decorator is not going to be used anywhere else, to put the decorator into the same file as the class, so that I only have to write the import once and it can't conflict with any other import?
In my real example, I want to write a decorator, which simply changes a flag, which indicates whether a list has been changed or not. Every method in that class, which modifies the list would be decorated using that decorator.
EDIT#1:
After changing the structure of my code, I now have only two participating source code files. Those are the following:
# -*- coding: utf-8 -*-
from AppSettings import AppSettings
from FileManager import FileManager
from decorators.changesvocables import changesvocables
from exceptions.DuplicateVocableException import DuplicateVocableException
from exceptions.UnknownVocableException import UnknownVocableException
__author__ = 'xiaolong'
class VocableManager:
vocables = []
search_result = []
vocables_changed = False
test_counter = 0
test_call_counter = 0
def __init__(self):
pass
#classmethod
#changesvocables
def remove_vocable(cls, vocable):
VocableManager.test_call_counter += 1
if vocable in VocableManager.vocables:
VocableManager.test_counter += 1
VocableManager.vocables.remove(vocable)
# del vocable
else:
print(vocable)
raise UnknownVocableException('Vocable not found.')
# VocableManager.vocables_changed = True
#classmethod
#changesvocables
def remove_vocable_by_index(cls, index):
del VocableManager.vocables[index]
# VocableManager.vocables_changed = True
#classmethod
#changesvocables
def add_vocable(cls, vocable):
if vocable not in VocableManager.vocables:
VocableManager.vocables.append(vocable)
else:
raise DuplicateVocableException('The vocable already exists.')
# VocableManager.vocables_changed = True
After that the class still goes on, but there are no other methods with the changesvocables decoration. If wanted, I can add the whole class.
And the decorator:
# -*- coding: utf-8 -*-
from functools import wraps
from VocableManager import VocableManager as VocMan
__author__ = 'xiaolong'
def changesvocables(function):
#wraps(function)
def wrapper(*args, **kw):
result = function(*args, **kw)
VocMan.vocables_changed = True
return result
return wrapper
This causes the following error, when I am trying to run the application:
** (__main__.py:16991): WARNING **: Couldn't connect to accessibility bus: Failed to connect to socket /tmp/dbus-sQwlsgyRi2: Connection refused
Traceback (most recent call last):
File "/home/xiaolong/development/pycharm-workspace/gtkplus-tool/gtkplustool/__main__.py", line 1, in <module>
from Application import Application
File "/home/xiaolong/development/pycharm-workspace/gtkplus-tool/gtkplustool/Application.py", line 8, in <module>
from VocableManager import VocableManager
File "/home/xiaolong/development/pycharm-workspace/gtkplus-tool/gtkplustool/VocableManager.py", line 4, in <module>
from decorators.changesvocables import changesvocables
File "/home/xiaolong/development/pycharm-workspace/gtkplus-tool/gtkplustool/decorators/changesvocables.py", line 3, in <module>
from VocableManager import VocableManager as VocMan
ImportError: cannot import name 'VocableManager'
EDIT#3:
Here is a MCVE:
main.py:
# -*- coding: utf-8 -*-
from mcve.ListManager import ListManager
__author__ = 'xiaolong'
if __name__ == '__main__':
list_manager = ListManager()
list_manager.add_item('item1')
decorator:
# -*- coding: utf-8 -*-
from functools import wraps
from mcve.ListManager import ListManager as ListMan
__author__ = 'xiaolong'
def changesitems(function):
#wraps(function)
def wrapper(*args, **kw):
result = function(*args, **kw)
ListMan.vocables_changed = True
return result
return wrapper
ListManager:
# -*- coding: utf-8 -*-
from mcve.changesitems import changesitems
class ListManager:
list_of_items = []
def __init__(self):
pass
#changesitems
def add_item(self, item):
if item not in ListManager.list_of_items:
ListManager.add_item(item)
Same error as before:
Traceback (most recent call last):
File "/home/xiaolong/development/pycharm-workspace/MCVE/mcve/main.py", line 2, in <module>
from mcve.ListManager import ListManager
File "/home/xiaolong/development/pycharm-workspace/MCVE/mcve/ListManager.py", line 2, in <module>
from mcve.changesitems import changesitems
File "/home/xiaolong/development/pycharm-workspace/MCVE/mcve/changesitems.py", line 3, in <module>
from mcve.ListManager import ListManager as ListMan
ImportError: cannot import name 'ListManager'
Process finished with exit code 1
Try:
from Foo import Foo as foo
Now you will have access to the package, as Foo, and to the decorator, as foo.
I defined a class called Parser in a file called parser.py, that parses a test result....
import sys
import re
class Parser:
def __init__(self):
pass
def udp_parse(self, filename=""):
# ... some code over here
Now, in main.py. I have:
from dbconn import *
from parser import *
import os
import subprocess
def main()
dbconn = Dbconn()
parse = Parser()
# more code here ...
if __name__ == '__main__':
main()
and I'm getting:
Traceback (most recent call last):
File "iperf.py", line 108, in <module>
main()
File "iperf.py", line 49, in main
parse = Parser()
NameError: global name 'Parser' is not defined
parser.py is in the same directory as dbconn.py and main.py. Dbconn() works without any problem, but I'm not understanding why Parser() can't work too ...
Parser is an existing python module. Use a different file name (not parser.py) or insert your path in sys.path before stdlibs.
import sys
sys.path.insert(0,'parser/directory')
from parser import *