How should I properly log my class container? - python

I have the following situation:
class A():
def __init__(self, log = True):
self.log = log
def __call__(self):
if self.log:
self.log ='\n' # whatever no-Null string to reinitialize the log attribute at each call
do_things()
self.log += 'I did things'
class B()
def __init__(self):
self.a = A(log = True)
self.log_master = []
def __call__(self):
for i in range(num):
self.a()
self.log_master.append(a.log)
self.log_master.append('other things')
save_to_file(self.log_master)
So I have a class B which is initialized with an instance of class A. B calls A. When the class A is called it initializes a string which serve as a container to log the operations. When call ends, B checks A's log string and append it to log_master, besides other things. At the end of everything log_master is saved to file. Basically I have two classes, one of which serve as a container for an instance of the other. Both 'collaborate' at writing a log file.
I can feel the horror with this approach. My A code is cluttered with ugly "if self.log: ..". What is the right approach to produce a decent and customizable logfile?

Related

How to verify when an unknown object created by the code under test was called as expected (pytest) (unittest)

I have some code that creates instances from a list of classes that is passed to it. This cannot change as the list of classes passed to it has been designed to be dynamic and chosen at runtime through configuration files). Initialising those classes must be done by the code under test as it depends on factors only the code under test knows how to control (i.e. it will set specific initialisation args). I've tested the code quite extensively through running it and manually trawling through reams of output. Obviously I'm at the point where I need to add some proper unittests as I've proven my concept to myself. The following example demonstrates what I am trying to test:
I would like to test the run method of the Foo class defined below:
# foo.py
class Foo:
def __init__(self, stuff):
self._stuff = stuff
def run():
for thing in self._stuff:
stuff = stuff()
stuff.run()
Where one (or more) files would contain the class definitions for stuff to run, for example:
# classes.py
class Abc:
def run(self):
print("Abc.run()", self)
class Ced:
def run(self):
print("Ced.run()", self)
class Def:
def run(self):
print("Def.run()", self)
And finally, an example of how it would tie together:
>>> from foo import Foo
>>> from classes import Abc, Ced, Def
>>> f = Foo([Abc, Ced, Def])
>>> f.run()
Abc.run() <__main__.Abc object at 0x7f7469f9f9a0>
Ced.run() <__main__.Abc object at 0x7f7469f9f9a1>
Def.run() <__main__.Abc object at 0x7f7469f9f9a2>
Where the list of stuff to run defines the object classes (NOT instances), as the instances only have a short lifespan; they're created by Foo.run() and die when (or rather, sometime soon after) the function completes. However, I'm finding it very tricky to come up with a clear method to test this code.
I want to prove that the run method of each of the classes in the list of stuff to run was called. However, from the test, I do not have visibility on the Abc instance which the run method creates, therefore, how can it be verified? I can't patch the import as the code under test does not explicitly import the class (after all, it doesn't care what class it is). For example:
# test.py
from foo import Foo
class FakeStuff:
def run(self):
self.run_called = True
def test_foo_runs_all_stuff():
under_test = Foo([FakeStuff])
under_test.run()
# How to verify that FakeStuff.run() was called?
assert <SOMETHING>.run_called, "FakeStuff.run() was not called"
It seems that you correctly realise that you can pass anything into Foo(), so you should be able to log something in FakeStuff.run():
class Foo:
def __init__(self, stuff):
self._stuff = stuff
def run(self):
for thing in self._stuff:
stuff = thing()
stuff.run()
class FakeStuff:
run_called = 0
def run(self):
FakeStuff.run_called += 1
def test_foo_runs_all_stuff():
under_test = Foo([FakeStuff, FakeStuff])
under_test.run()
# How to verify that FakeStuff.run() was called?
assert FakeStuff.run_called == 2, "FakeStuff.run() was not called"
Note that I have modified your original Foo to what I think you meant. Please correct me if I'm wrong.

Patching built-in method or class

I would like to find all instances in the code where np.random.seed is called (without using grep). In order to set a breakpoint in ipdb, I tried to find the source file with
import inspect; inspect.getsourcefile(np.random.seed)
but it throws a TypeError because it is a built-in method (because it is coded in C).
Is it possible to watch any calls to np.random.seed by modifying something in the main source file?
Additionally, it would be suitable to patch this method, e.g. additionally logging it (or calling a debugger):
def new_random_seed(seed):
"""
This method should be called instead whenever np.random.seed
is called in any module that is invoked during the execution of
the main script
"""
print("Called with seed {}".format(seed))
#or: import ipdb; ipdb.set_trace()
return np.random.seed()
Maybe using a mock framework is the way to go?
The second question concerns the scenario in which a class B inherits from a class A in a library and I want to use the functionality of class B, but overwrite a function it uses from class A without modifying classes A and B. Probably, I should use mocking, but I am not sure about the overhead, so I wrote the following:
#in library
class A():
def __init__(self, name):
self.name = name
def work(self):
print("{} working".format(self.name))
class B():
def __init__(self):
self.A = A("Machine")
def run_task(self):
self.A.work()
# in main script
# Cannot change classes A and B, so make a subclass C
import types
class C(B):
def __init__(self, modified_work):
super().__init__()
self.A.work = types.MethodType(modified_work, self.A) #MethodType for self
b = B()
b.run_task()
modified_work = lambda self: print("{} working faster".format(self.name))
c = C(modified_work)
c.run_task()
The output is:
Machine working
Machine working faster
Is this good style?
This might be a simpler solution to your second question:
# lib.py
class A():
def work(self):
print('working')
class B():
def __init__(self):
self.a = A()
def run(self):
self.a.work()
Then in your code:
import lib
class A(lib.A):
def work(self):
print('hardly working')
lib.A = A
b = lib.B()
b.run()
Or:
import lib
class AA(lib.A):
def work(self):
print('hardly working')
class BB(lib.B):
def __init__(self):
self.a = AA()
b = lib.B()
b.run()
b = BB()
b.run()

Can I add methods into def __init__?

Using python 2.7.6, I have been trying to write a class that can extract pieces of xml data from a couple of xml files within a given zip file. I want to be able to use any of the methods in any order once I am working with the class, so wanted the unzip stage to be behind the scenes, in the class.
It is the first time I have really tried to make real use of a class as I am quite new to python, so I am learning as I go.
I defined methods to unzip the data to memory and was using those methods in other methods - then realised it would be horribly inefficient when using multiple methods. Since the unzipping step is necessary for any method in the class, is there a way to build it into the init definition so it is only done once when the class is first created?
Example of what I currently have:
class XMLzip(object):
def __init__(self, xzipfile):
self.xzipfile = xzipfile
def extract_xml1(self):
#extract the xmlfile to a variable
def extract_xml2(self):
#extract xmlfile2 to a variable
def do_stuff(self):
self.extract_xml1()
....
def do_domethingelse(self):
self.extract_xml1()
Is there a way to do something like I have shown below? And if so, what is it called - my searches haven't been very effective.
class XMLzip(object):
def __init__(self, xzipfile):
self.xzipfile = xzipfile
def extract_xml1()
# extract it here
def extract_xml2()
# extract it here
# Now carry on with normal methods
def do_stuff(self):
...
in the __init__ you can do whatever you want in order to initialize your class, in this case look like what you need is something like this
class XMLzip(object):
def __init__(self, xzipfile):
self.xzipfile = xzipfile
self.xml1 = #extract xml1 here
self.xml2 = #extract xml2 here
def do_stuff(self):
...
if you want to do the extract part only once, then do it and save result in a additional attribute in the instance of your class.
I suspect that the extract procedure is very similar, so you can make it a function be inside your class or outside, that is up to your preference, and give additional arguments to handle the specificity, for example something like this
the outside version
def extract_xml_from_zip(zip_file,this_xml):
# extract the request xml file from the given zip_file
return result
class XMLzip(object):
def __init__(self, xzipfile):
self.xzipfile = xzipfile
self.xml1 = extract_xml_from_zip(xzipfile,"xml1")
self.xml2 = extract_xml_from_zip(xzipfile,"xml2")
def do_stuff(self):
...
the inside version
class XMLzip(object):
def __init__(self, xzipfile):
self.xzipfile = xzipfile
self.xml1 = self.extract_xml_from_zip("xml1")
self.xml2 = self.extract_xml_from_zip("xml2")
def extract_xml_from_zip(self,this_xml):
# extract the request xml file from the zip_file in self.xzipfile
return result
def do_stuff(self):
...
You can call any method you have defined in your class in your initializer.
Demo:
>>> class Foo(object):
... def __init__(self):
... self.some_method()
... def some_method(self):
... print('hi')
...
>>> f = Foo()
hi
I take from your question that you need to extract the files only once. Leave your class as is and use your extract methods in __init__ and set the required attributes/variables for the extracted content.
For example
def __init__(self, xzipfile):
self.xzipfile = xzipfile
self.extract1 = self.extract_xml1()
self.extract2 = self.extract_xml2()
This of course requires your extract methods to have a return value, don't forget that.

Construct object via __init__ and ignore constructor exception

I have a Python class whose __init__ method raises a custom exception called WrongFileSpecified.
However, when I write a unit test, I want to assign the attributes of the instance object from a test fixture. So normally what I would be doing is reading data off a file and then working with the instance object.
But with the test, I cannot use any test files, so I basically need to hard code the data in the instance object in the setUp method of the unit test. Is there any way to get a instance created without __init__ complaining about the exception?
Sample code:
class A(object):
def __init__(self, folderPath):
#check folder path using os.isdir() otherwise raise exception
#...
self.folderPath = folderPath
#Call load record
self._load_records() #uses self.folderPath and raises exceptions as well
#Note i cannot avoid raising these exceptions, its required
class TestA(unittest.TestCase):
.......
obj = None
def setUp(self):
obj = A('fake folder path')
obj.val1 = "testparam1"
obj.param2 = "testparam2"
def test_1(self):
.....
You can create an empty object, bypassing __init__ by using __new__.
obj = obj_type.__new__(obj_type)
Note that obj_type is the appropriate type object. This is a little hacky but it works. You are reponsible for setting the object's members.
Edit: here is an example.
class Foo():
def __init__(self):
self.x = 1
self.y = 2
def say_hello(self):
print('Hello!')
r = Foo.__new__(Foo)
r.say_hello()
print(r.x)
Console output:
Hello!
Traceback (most recent call last):
File "C:\WinPython-64bit-3.3.5.7\python-
3.3.5.amd64\Scripts\projects\luc_utils\dev\test\
unit_test_serialization.py", line 29, in <module>
print(r.x)
AttributeError: 'Foo' object has no attribute 'x'
Here are two options:
Refactor the file loading out to a class method, which is the Pythonic method of providing an alternate constructor (see below); or
Provide an additional parameter to __init__ to suppress the exceptions when necessary (e.g. def __init__(self, folderPath, suppress=False), or validate=True, whichever makes more sense for your usage).
The latter is a bit awkward, in my opinion, but would mean that you don't have to refactor existing code creating A instances. The former would look like:
class A(object):
def __init__(self, ...):
"""Pass whatever is loaded from the file to __init__."""
...
#classmethod
def from_file(cls, folderPath):
"""Load the data from the file, or raise an exception."""
...
and you would replace e.g. a = A(whatever) with a = A.from_file(whatever).
There is a very useful module called mock, you can check it out later, I feel that in this case it will be too much. Instead, you should consider redesigning your class, like this, for example:
class A(object):
def __init__(self, folderPath):
self.folderPath = folderPath
def _load_records(self)
#check folder path using os.isdir() otherwise raise exception
...
#uses self.folderPath and raises exceptions as well
...
#classmethod
def load_records(cls, folderpath):
obj = cls(folderpath)
obj._load_records()
return obj
# Usage
records = A.load_records('/path/to/records')
Then you can do:
class TestA(unittest.TestCase):
.......
obj = None
def setUp(self):
self.obj = A('fake folder path')
self.obj.val1 = "testparam1"
self.obj.param2 = "testparam2"
def test_1(self):
self.assertRaises(self.obj._load_records, HorribleFailureError)
Also i highly recommend to check out pytest, it has wonderful facilities for test fixtures, including fixtures for files and folders.

Limit number of class instances with python

Μy Mainclass creates a simple QmainWindows like this:
class mcManageUiC(QtGui.QMainWindow):
def __init__(self):
super(mcManageUiC, self).__init__()
self.initUI()
def initUI(self):
self.show()
And at the end of my file I launch it like this:
def main():
app = QtGui.QApplication(sys.argv)
renderManagerVar = mcManageUiC()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
My problem is that each time i source it, it launches a new window.
I would like to know if there is a way to detect existence of previous class instance in my script (so that I close the old one or avoid launching a new one), or any other solutions?
Also, when compiling my code with py2exe, same problem with my .exe file on Windows; it launchs a new window every time. Could i add something in the setup.py for Windows to not act like this?
Is it possible, if yes then how?
Note: I'm using Windows 7 64bit compiling with eclipse.
There are a couple ways to do this, you can use a Class attribute to store all the instances -- If you do it this way, you may want to store them as weak references via the weakref module to prevent issues with garbage collecting:
class MyClass(object):
_instances=[]
def __init__(self):
if(len(self._instances) > 2):
self._instances.pop(0).kill() #kill the oldest instance
self._instances.append(self)
def kill(self):
pass #Do something to kill the instance
This is a little ugly though. You might also want to consider using some sort of Factory which (conditionally) creates a new instance. This method is a little more general.
import weakref
class Factory(object):
def __init__(self,cls,nallowed):
self.product_class=cls #What class this Factory produces
self.nallowed=nallowed #Number of instances allowed
self.products=[]
def __call__(self,*args,**kwargs):
self.products=[x for x in self.products if x() is not None] #filter out dead objects
if(len(self.products) <= self.nallowed):
newproduct=self.product_class(*args,**kwargs)
self.products.append(weakref.ref(newproduct))
return newproduct
else:
return None
#This factory will create up to 2 instances of MyClass
#and refuse to create more until at least one of those
#instances have died.
factory=Factory(MyClass,2)
i1=factory("foo","bar") #instance of MyClass
i2=factory("bar","baz") #instance of MyClass
i3=factory("baz","chicken") #None
You can limit the number of instances you want to create in your code just by adding a counter:
class A(object):
ins = 0 # This is a static counter
def __init__(self):
if A.ins >= 1: # Check if the number of instances present are more than one.
del self
print "Failed to create another instance" #if > 1, del self and return.
return
A.ins += 1
print "Success",str(self)
Try running via:
lst = []
for i in range(1,101):
a=A()
lst.append(a)
you could monopolize a socket
import socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
"Network Error!"
s.settimeout(30)
try:
s.connect(('localhost' , 123))
except:
"could not open...already in use socket(program already running?)"
no idea if this is a good method but I have used it in the past and it solves this problem
this was designed to prevent launching a program when it was already running not from launching a new window from within a single script that is spawning several windows...
Use a class variable:
class mcManageUiC(QtGui.QMainWindow):
singleton = None
def __init__(self):
if not mcManageUiC.singleton: #if no instance yet
super(mcManageUiC, self).__init__()
self.initUI()
...
mcManageUiC.singleton = self
else:
...
def initUI(self):
self.show()

Categories

Resources