Best way to import modules inside a class? - python

I have a Python module file which is actually a class with its associated public and private functions. I want to use the logging module inside the class and inside all the functions. But the issue is if I import only once inside __init__() the import is not visible in the rest of the functions.Do I have to import it in every function of the class?
What is the best way to import such modules inside a class. I searched various discussions about the same in stackoveflow forums but could not come with something concrete.
Below is my sample class:
class Add:
def __init__(self,no1,no2):
import logging
logging.basicConfig(filename='example2.log',level=logging.INFO)
logging.info("The two parameters passed are {0} and {1}:".format(no1,no2))
self.num1 = no1
self.num2 = no2
def add(self):
logging.debug("Inside add function of Add class")
logging.info("Adding the two class properties")
self.result = self.num1 + self.num2
logging.debug("Exiting add function")
def display(self):
logging.debug("Inside display class")
return self.result
if __name__ == '__main__':
a = Add(10,11)
a.add()
print (a.display)
When I try to run this:
C:\Users\bhatsubh\Desktop\Everything\Codes\Python>python Test.py
Traceback (most recent call last):
File "Test.py", line 21, in <module>
a.add()
File "Test.py", line 10, in add
logging.debug("Inside add function of Add class")
NameError: name 'logging' is not defined

So the problem here is one of scope. When you import inside a function (which occasionaly, see below) then the scope of that import is limited to inside that function:
def foo():
import a
a.something()
def bar():
a.something() # won't work
instead you should try to always import at the top:
import a
def foo():
a.something()
def bar():
a.something()
you should also come up with a good, maintainable way of ordering your imports.
Now, you can do it inside a function, and you can do funky things like dynamic imports and reflection and all kinds of cool stuff, but 99.9% of the time you don't need to, so adding that kind of complexity detracts from maintainability (which should be your goal).
The good times you do want to do it is to resolve complex cyclic imports, or if you're trying to do something funky with dynamic loading for performance. But when it comes to optimising performance, you should always build it first then see where it is breaking.

You could simply assign it to a variable to it:
class Foo:
def __init__(self):
import logging
self._logging = logging
But I would advise to just import it on the module level. It feels very wrong to attach a module to a member variable of a class.
Another option would be to only store the Logger you are going to use:
class Foo:
def __init__(self):
import logging
self.logger = logging.getLogger(__name__ + "." + self.__class__.__name__)
PS: This is probably not the proper way to create a logger for a class, I've never done it and only improvised it here. Read up on how to do it.

Related

What is the scope of an imported function

If I have a python file as follows
import time
class abc:
def func1(self):
while True:
do something
time.sleep(5)
xyz = abc()
xyz.func1()
The above works exactly as expected
If I move the class definition out to a seperate .py file and import it
import time
from test1 import abc
xyz = abc()
xyz.func1()
Works as expected until it hits the time.sleep(5) when it errors
saying time is not defined
I have tried adding the time import into the class definition but
still seem to get the same problem
What am I missing.
Moving the import to the class definition file doesn't seem to resolve the problem, either adding it at the top or in the init .
Take a look at the python documentation about the import statement.
Quote from there:
define a name or names in the local namespace for the scope where the import statement occurs.
So your toplevel import is bound on module level and the name time is accessible from wherever in that module.
If you move the import inside the method, it will be accessible in the local scope of the method and won't be visible outside of that method.
So, you don't want to move the import in your other module, as you don't use it there. To make things work, you should preserve the import of time where it is now and only move your function calls outside:
# test1.py
import time
class ABC:
def func1(self):
while True:
# do something
time.sleep(5)
print('slept 5 secs')
# main.py
from test1 import ABC
abc = ABC()
abc.func1()
[Not related to your question tip] You should also take a look at PEP8 and follow it's conventions.

Is there a way to monkey patch a class inside a module before the module body is executed in python?

I have file main.py which contains the following code:
class A:
def __init__(self, a):
self.a = a
def run(self):
return self.a+10
a = A(4)
print(a.run())
In file test.py, I tried to monkey patch class A in main.py as follows:
import main
class A:
def __init__(self, a):
self.a = a
def run(self):
return self.a+5
main.A = A
Unfortunately, when I run import test from a python interpreter, the module still prints out 14 as opposed to my expected output which is 9.
Is there a way to monkey patch a class inside a module before the module body is executed?
The problem here is that when you imported the main.py file, it executed the code a = A(4) using the real implementation of the class A. Then the rest of your test.py was executed and you replaced the A reference, but it was too late.
You can check that by adding in your test :
print(__name__) # __main__
print(main.__name__) # so70731368_main
print(A.__module__) # __main__
print(main.A.__module__) # __main__
print(main.a.__class__.__module__) # so70731368_main
Here, __main__ is a bit confusing but that's how Python call the first file you run (in your case test.py). The a instance is declared in the so70731368_main module, and it used the A class from the same module, you just changed A after the fact with the definition from the test file (__main__).
The fact that you need to patch two definitions (A and a) defined in the same file is very tricky. unittest.mock.patch is not powerful enough to patch inside an import (it patches after the import).
You can not, in a clean and simple way, prevent a to be instantiated as a main.A (real) class and get printed. What you can do is patch it after, for later uses, that is what you showed.
To answer directly your question : "patching" means replacing one reference by another, so the reference has to already be defined. In your example, it would require to patch between the class definition and the class instantiation (for the print to not use the real a), which is not supported.
There is no simple solution to this problem. If you have control over the code of the main.py file, then try to change it so that it does not instantiate a at import time.

PyCharm "Unused import statement" when adding method to class

I want add a method to a class, without extending another class (for the import statements should be unaltered).
Conceptually, my current approach is:
add_method.py
def new_method():
pass
MyObject.new_method = new_method
main.py
from package import MyObject
import add_method
ob = MyObject()
ob.new_method()
This does the job, however, PyCharm does not recognize that the import add_method import statement is acutally used: "Unused import statement". Is there an elegant way to obtain the same effect with PyCharm recognizing the import?

Python 2.7 mock a void method of a class

I am trying to use unittests.mock to mock a void method call of an object.
My package is like below
common
baseupgradehandler.py
baseupgradehandler.py
class BaseUpgradeHandler(object):
def __init__(self, upgrade_config, upgrade_state, system_config, pre_step, main_step, post_step):
...
# Method call to be supressed
def start(self, service_manifest, upgrade_bundle):
# type: (service_version_pb2.ServiceManifest, str) -> ()
...
In my test code I am trying to mock the call to start() like below as explained in the documentation.
from workflow.upgradeworkflow import UpgradeWorkflow
from common.serviceregistry import ServiceRegistry
# The above imports are at the start of the test file
...
with patch('common.baseupgradehandler.BaseUpgradeHandler') as handler_mock: # type: Mock
handler_mock.return_value.start.return_value = ''
wf = UpgradeWorkflow(ServiceRegistry(self.service_bundle, config, sys_config, state),
config,
state,
sys_config)
BaseUpgradeHandler object is returned by get_upgrade_handler() method of ServiceRegistry. When I am executing the above code in test I am seeing the BaseUpgradeHandler.start() is still getting called.
Can someone let me know how can I mock the call to a start() so that the method is not called?
EDIT
If I change my patching code like below it is working as expected and BaseUpgradeHandler is getting mocked and start is not getting called.
with patch('common.baseupgradehandler.BaseUpgradeHandler') as handler_mock: # type: Mock
handler_mock.return_value.start.return_value = ''
with patch('common.serviceregistry.ServiceRegistry') as serviceregistry_mock: # type: Mock
serviceregistry_mock.return_value.get_upgrade_handler.return_value = handler_mock
wf = UpgradeWorkflow(ServiceRegistry(self.service_bundle, config, sys_config, state), config, state, sys_config)
wf.start()
Can someone explain me why do I have to patch ServiceRegistry as well?
The code you provided is not enough to see the part that causes the issue. We'd need to see the module serviceregistry to be sure but I'd take an educated guess:
You have a file a.py (aka baseupgradehandler) like this:
class A:
def method(self):
print("It's real!")
And a file b.py (aka serviceregistry) like this:
from a import A
class B:
def get_A(self):
return A()
In your test files you do this:
import unittest
from unittest.mock import patch
from b import B
from a import A
GAME OVER!
The B module right now has already got its reference to the original A class. When, afterwards, you patch('a.A') only the reference in the a module is changed, but patch has no way to know that B has its own reference to the original A.
You can fix this in three ways:
patch the method: this will modify the existing class so all references to that class will be automatically patched
patch b.A too:
with patch('a.A') as h_a, patch('b.A') as h_b:
h_a.return_value.method.return_value = ''
h_b.return_value.method.return_value = ''
Avoid importing the modules before patching (probably not feasible or a good idea):
import unittest
from unittest.mock import patch
class MyTest(unittest.TestCase):
def test_one(self):
with patch('a.A') as h:
h.return_value.method.return_value = ''
from b import B
B().get_A().method()
I have been using unittest.mocks for a while, and I have been re-inventing the wheel sometimes. I decided to make mockito part of my project and now things look way better. Any kind of mock verification is really simple, if you can, I definitively encourage you to make mockito part of your libraries. This library has a good documentation and so far it has been easier than unittest.mock IMHO.

solving cyclic dependency with python inheritance

Using the OOP 'State' pattern in python leaded me to this dependency problem:
StateA, StateBand StateC are 3 states implementing the same method event1.
StateB inherits its behavior from StateA.
file a.py:
#from b import StateB
from c import StateC
class StateA(object):
def event1(self):
return StateC()
print type(StateA().event1())
file b.py:
import a
class StateB(a.StateA):
def event1(self):
return self
file c.py:
class StateC(object):
def event1(self):
return self
As long as I don't need StateB in a.py, this works. But what if I want to use type StateB in StateA?
Importing StateB (see the first commented line in a.py) leads to this cyclic dependency error:
ImportError: cannot import name StateB
Circle dependencies is a problem connected with code design. In practice, you could meet that probably only in badly organized code. Try to refactor your code to resolve this issue.
Another approach (which I not suggest you to do, just FYI) is an import outside of module-level import, but you should avoid such an approach.
Since your classes are tightly coupled, I would just put them into the same module:
file my_state.py:
class StateA(object):
def event1(self):
return StateC()
class StateB(StateA):
def event1(self):
return self
class StateC(object):
def event1(self):
return self
print(type(StateA().event1()))

Categories