I'm trying to access to an instanced class build by firstscript.py from secondscript.py.
I run secondscript.py from firstscript.py by os.system('sudo secondscript.py') and I want access to the namespace of firstscript.py. For example I have the following code:
# firstscript.py
import wx
import abcd
class MyFrame(abcd):
def __init__(self, *args, **kwds):
abcd.__init__(self, *args, **kwds)
def log(self,str_log):
self.text_ctrl_logging.SetForegroundColour(wx.BLACK)
self.text_ctrl_logging.AppendText(str_log+'\n')
def runsudo(self):
os.system('sudo ./secondscript.py')
class fghi(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
if __name__ == "__main__":
app = fghi(0)
app.MainLoop()
and the following is the secondscript.py
from firstscript import MyFrame
MyFrame.log("HELLO")
From secondscript.py I want print some string on text_ctrl_logging by log method.
But the following is the error:
TypeError: log() missing 1 required positional argument: 'str_log'
I'm sorry I'm a newbie then be patient for the stupid question.
Related
I have a collection of ever more specialized classes which correspond to collections of the same kind of data (temperature, density, etc) but for different drifts, for example, one subclass has dimensions (nx, ny) and a different suclass has dimensions (ncv), and I want to reflect that in the docstrings, for having a better documentation using Sphinx.
After reading many very useful threads here in Stack Overflow, I have arrived to this model:
import numpy as np
from functools import wraps
def class_decorator(cls):
import ipdb; ipdb.set_trace()
clsdict = {}
mro = cls.mro()
mro.reverse()
for tmp in mro[1:]: ##Ignore object class parent.
clsdict.update(tmp.__dict__)
for name, method in clsdict.items():
if hasattr(method, '__og_doc__'):
try:
method.__doc__ = method.__og_doc__.format(**clsdict)
except:
pass
else:
try:
method.__og_doc__ = method.__doc__
method.__doc__ = method.__doc__.format(**clsdict)
except:
pass
return cls
def mark_documentation(fn):
if not hasattr(fn, '__og_doc__'):
try:
fn.__og_doc__ = fn.__doc__
except:
pass
#wraps(fn)
def wrapped(*args, **kwargs):
return fn(*args, **kwargs)
return wrapped
def documented_property(fn):
if not hasattr(fn, '__og_doc__'):
try:
fn.__og_doc__ = fn.__doc__
except:
pass
#wraps(fn)
def wrapped(*args, **kwargs):
return fn(*args, **kwargs)
prp= property(wrapped)
prp.__og_doc__ = fn.__og_doc__
return prp
#class_decorator
class Base(object):
_GRID_DIM = 'nx, ny'
_TYPE = 'BaseData'
def __init__(self, name):
self.name = name
def shape(self):
""" This docstring contains the type '{_TYPE}' of class."""
print('Simple')
def operation(self, a, b, oper=np.sum, **kwargs):
""" Test for functions with args and kwargs in {_TYPE}"""
return oper([a,b])
#classmethod
def help(cls, var):
try:
print(get(cls, var).__doc__)
except:
print("No docstring yet.")
#class_decorator
class Advanced(Base):
_GRID_DIM = 'ncv'
_TYPE = 'AdvancedData'
def __init__(self,name):
super().__init__(name)
#property
#mark_documentation
# #documented_property
def arkansas(self):
"""({_GRID_DIM}, ns): Size of Arkansaw."""
return 'Yeah'
I am aiming to get the correctly formatted docstring when I call the help method or I use Sphinx, so that:
> adv = Advanced('ADV')
> adv.help("arkansas")
(ncv, ns): Size of Arkansaw.
> adv.help("operation")
Test for functions with args and kwargs in AdvancedData
I have managed to make it work so far, except for properties, because I assigned __og_doc__ to the function, but the property does not have that attribute. My last attempt at monkeypatching this, documented_property, fails because property is inmutable (as expected), and I cannot come up with any way to avoid this roadblock.
Is there any way around this problem?
I'm trying to write a unit test class in python but feel like I'm missing something fundamental as it's not doing what I would expect. Here is my class:
from unittest import TestCase
class MyTestClass(TestCase):
def __init__(self):
self.file_name = None
def setUp(self):
self.file_name = 'give this file a name'
return self.file_name
def test_a_file_name(self):
assert self.file_name == 'give this file a name', 'fail'
tester = MyTestClass()
tester.setUp()
tester.test_a_file_name()
I would expect when running this that the test would pass but I'm getting a __init__() takes 1 positional argument but 2 were given error and I can't see why?
When running unittest.main your class that inherits from TestCase gets handed the test method to call. As such you need to allow your class to be handed that argument and pass it on to the parent class __init__.
from unittest import TestCase, main
class MyTestClass(TestCase):
# accept arbitrary positional and keyword arguments
def __init__(self, *args, **kwargs):
self.file_name = None
# pass them on to the parent
super().__init__(*args, **kwargs)
def setUp(self):
self.file_name = 'give this file a name'
return self.file_name
def test_a_file_name(self):
assert self.file_name == 'give this file a name', 'fail'
if __name__ == '__main__':
main()
As you noticed, you also don't need to handle instantiation and method calling. unittest.main() will do that for you.
In the future, if you ever get an error with arguments, a helpful debugging tip is throwing in an *args, **kwargs and printing them to see what is being handed that you're not handling.
I would like to do something in my unit testing before it fails and using decorator to do so
Here is my code :
import requests
import unittest
import test
class ExceptionHandler(object):
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
try:
self.f(*args, **kwargs)
except Exception as err:
print('do smth')
raise err
class Testing(unittest.TestCase):
#ExceptionHandler
def test_connection_200(self):
r = requests.get("http://www.google.com")
self.assertEqual(r.status_code, 400)
if __name__ == '__main__':
unittest.main(verbosity=2)
But it throws me an :
TypeError: test_connection_200() missing 1 required positional argument: 'self'
How can I do something when my test fail, then having the normal failing behavior of unitest?
Edit :
I would like to do something before my test fail like write a log and then continue the normal process of failing.
If possible with a decorator.
Edit bis the solution thanks to #Thymen :
import requests
import unittest
import test
class ExceptionHandler(object):
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
try:
self.f(*args, **kwargs)
except Exception as err:
print('do smth')
raise err
class Testing(unittest.TestCase):
def test_connection_200(self):
#ExceptionHandler
def test_connection_bis(self):
r = requests.get("https://www.google.com")
print(r.status_code)
self.assertEqual(r.status_code, 400)
test_connection_bis(self)
if __name__ == '__main__':
unittest.main(verbosity=2)
My comment may not have been clear, so hereby the solution in code
class Testing(unittest.TestCase):
def test_connection_200(self):
#ExceptionHandler
def test_connection():
r = requests.get("http://www.google.com")
self.assertEqual(r.status_code, 400)
with self.assertRaises(AssertionError):
test_connection()
The reason that this works is that there is no dependency on the call for the test (test_connection_200) , and the actual functionality that you are trying to test (the ExceptionHandler).
Edit
The line
with self.assertRaises(AssertionError):
test_connection()
Checks if test_connection() raises an AssertionError. If it does not raises this error, it will fail the test.
If you want the test to fail (because of the AssertionError), you can remove the with statement, and only call test_connection(). This will make the test fail directly.
I have a method decorator looking like
def debug_run(fn):
from functools import wraps
#wraps(fn)
def wrapper(self, *args, **kw):
# log some stuff
# timeit fn
res = fn(self, *args, **kw)
return wrapper
Right now I used to use it apply on each method that I want to debug. Now i'm trying to apply to all class method using a class decorator looking like.
Rather doing
class A():
#debug_run
def f(self):
pass
I do
#decallmethods(debug_run)
class A():
def f(self):
pass
def decallmethods(decorator):
def dectheclass(cls):
for name, m in inspect.getmembers(cls, inspect.ismethod):
if name in getattr(cls, 'METHODS_TO_INSPECT', []):
setattr(cls, name, decorator(m))
return cls
return dectheclass
Trying to apply to decorator to the base class, not working as expected. no log to the console. Now i wonder if this approach is the good or I should used something else (apply the debug decorator to selected method from base class to all sub classes).
[EDIT]
Finally found why no logs were printed
Why is there a difference between inspect.ismethod and inspect.isfunction from python 2 -> 3?
Here a complete example reflecting my code
import inspect
import time
import logging as logger
from functools import wraps
logger.basicConfig(format='LOGGER - %(asctime)s %(message)s', level=logger.DEBUG)
def debug_run(fn):
#wraps(fn)
def wrapper(self, *args, **kw):
logger.debug(
"call method %s of instance %s with %r and %s "
% (fn.__name__, self, args, kw))
time1 = time.time()
res = fn(self, *args, **kw)
time2 = time.time()
logger.debug(
"%s function %0.3f ms" % (fn, (time2-time1)*1000.0))
return res
return wrapper
def decallmethods(decorator):
def dectheclass(cls):
for name, m in inspect.getmembers(
cls, predicate=lambda x: inspect.isfunction(x) or inspect.ismethod(x)):
methods_to_inspect = getattr(cls, 'METHODS_TO_INSPECT', [])
if name in methods_to_inspect:
setattr(cls, name, decorator(m))
return cls
return dectheclass
class B(object):
METHODS_TO_INSPECT = ["bfoo1", "bfoo2", "foo"]
def __str__(self):
return "%s:%s" % (repr(self), id(self))
def bfoo1(self):
pass
def bfoo2(self):
pass
def foo(self):
pass
def run(self):
print("print - Base run doing nothing")
class C(object):
pass
#decallmethods(debug_run)
class A(B, C):
METHODS_TO_INSPECT = ["bfoo1", "bfoo2", "foo", "run"]
def foo(self):
print("print - A foo")
def run(self):
self.bfoo1()
self.bfoo2()
self.foo()
a = A()
b = B()
a.run()
b.run()
In this case applying decallmethods to B, will not affect the A so i must to apply to both A and B thus to all sub classes of B.
It is possible to have such mechanism that permit to apply decallmethods to all sub classes methods ?
look at this:
How can I decorate all functions of a class without typing it over and over for each method added? Python
delnan has a good answer,
only add this rule to his answer
if name in getattr(cls, 'METHODS_TO_INSPECT', []):
The goal:
B in inherits from A.
A and B have a factory method create, which harmonizes different input types before initializing the actual class.
create calls different create methods create_general_1, create_general_2, create_specific_b_1 via their name, supplied as a string.
This is my current approach:
import sys
class A:
def __init__(self, text):
self.text = text
print("I got initialized: {}".format(text))
def create(create_method_str):
# This is where it breaks:
create_method = getattr(sys.modules[__name__], create_method_str)
return create_method()
def create_general_style_3():
return A("a, #3")
class B(A):
def create_b_style_1():
return B("b, #1")
if __name__ == "__main__":
B.create("create_b_style_1")
It fails with the following error:
Traceback (most recent call last): File "test.py", line 22, in
B.create("create_b_style_1") File "test.py", line 10, in
create create_method = getattr(sys.modules[__name__],
create_method_str) AttributeError: 'module' object has no attribute
'create_b_style_1'
So in a way, I'm trying to combine three things: factory methods, inheritance, and function calling by name.
It would be great if someone had a smarter approach, or knew how to get this approach to work.
Thanks a great lot!
Thanks to Two-Bit Alchemist's comment, I've created this solution, which seems to work fine. Any improvements / other proposals are more than welcome :)
All is well explained here.
import sys
class A:
def __init__(self, text):
self.text = text
print("I got initialized: {}".format(text))
#classmethod
def create(cls, create_method_str):
create_method = getattr(cls, create_method_str)
return create_method()
#classmethod
def create_general_style_3(cls):
return cls("a, #3")
class B(A):
#classmethod
def create_b_style_1(cls):
return cls("b, #1")
if __name__ == "__main__":
B.create("create_b_style_1")