i have following python code (a bit simplified, but it did make the same error).
class traffic(object):
def __init__(self, testObj):
try:
<do something>
except AssertionError:
sys.exit (1)
def add(self, phase='TEST'):
<do something>
def check(self, phase='TEST'):
<do something>
class testcase(object):
def __init__(self):
try:
<do something>
except AssertionError:
sys.exit (1)
def addSeqPost(self, cmdObj):
print "add Seq. for POST"
cmdObj(phase='POST')
tc = testcase()
test = traffic(tc)
tc.addSeqPost(test.add())
I get the below TypeError:
Traceback (most recent call last):
File "test.py", line 25, in <module>
tc.addSeqPost(test.add())
File "test.py", line 20, in addSeqPost
cmdObj(phase='POST')
TypeError: 'NoneType' object is not callable
If i change my code to, it works, but it is not what i would like:
def addSeqPost(self, cmdObj):
print "add Seq. for POST"
cmdObj.add(phase='POST')
tc.addSeqPost(test())
I would like to make it more general because the test() could have more methods that i would like to pass into tc.addSeqPost(), like tc.addSeqPost(test.check()).
Thanks in adv. for your time and help
After the help from alKid.
One issue remains, what if i want to pass a parameter with test.check(duration=5)? As soon i do that i got the same TypeError...But i don't want/need to return anything from add!!!
Example:
...
def check(self, phase='TEST', duration=0):
<do something>
tc = testcase()
test = traffic(tc)
tc.addSeqPost(test.add)
tc.addSeqPost(test.check(duration=5))
test.add() will not return the function, it runs the function and gives back the returned value. Since add doesn't return anything, the object passed is None.
tc = testcase()
test = traffic(tc)
tc.addSeqPost(test.add)
Also, remember that test.add needs two arguments. self and phase. You need to pass both of them.
def addSeqPost(self, cmdObj):
print "add Seq. for POST"
cmdObj(self, phase='POST') #pass an instance of `testcase` to the function.
Passing another class's instance might not be what you want to do, but it's just an example.
Hope this helps!
Related
Im looking to create something that I can use to check if a string meets a condition like so:
var = "hello"
check = var.checkconditions()
Im just curious as to if its possible as I have never seen it done before.
How would the function/whatever I need to use be set out?
String is a build in class/object and can not be changed. However you can make a personal new class:
class str_class:
def __init__ (self, str):
self.str = str
def checkconditions(self):
# Enter your conditions
var = str_class('hello')
check = var.checkconditions()
Or you could simply make a funtion that takes the string as input and outputs if the condition is met or not:
def checkconditions(str):
# Enter conditions
var = 'Hello'
check = checkconditions(var)
Edit: From other comments it seems as though it is possible but not recommended.
You can use a Class and then use the method check_conditions.
class Check:
def __init__(self):
pass
def check_conditions(string):
#Do whatever you need in here
print(string)
c = Check
c.check_conditions("hello")
This should hopefully do what you need!
You can't directly add the method to the original type.what you can do is subclass the type like
class mystring(str):
def checkconditions(self):
#condition
and then you can instantiate your new class
var = mystring('hello')
var.checkcondition()
but that's still no too practical, if you want to make it more proper you can do this
import __builtin__
__builtin__.str = mystring
var = str("hello")
check = var.checkconditions()
which achieves most of the effect desired.
Unfortunately, objects created by literal syntax will continue to be of the vanilla type and won't have your new methods/attributes.
var = 'hello'
var.checkconditions()
# Output
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'checkconditions'
"""
For understanding decorators in Python, i created in a class an example. But when i run it i receive an error.
class Operation:
def __init__(self, groupe):
self.__groupe = groupe
#property
def groupe(self):
return self.__groupe
#groupe.setter
def groupe(self, value):
self.__groupe = value
def addition(self, func_goodbye):
ln_house = len('house')
ln_school = len('school')
add = ln_house + ln_school
print('The result is :' + str(add))
return func_goodbye
#addition
def goodbye(self):
print('Goodbye people !!')
if __name__ == '__main__':
p1 = Operation('Student')
p1.goodbye()
I receive this error :
Traceback (most recent call last):
File "Operation.py", line 1, in
class Operation:
File "Operation.py", line 21, in Operation
#addition
TypeError: addition() missing 1 required positional argument: 'func_goodbye'
You can have a class scoped decorator, however there won't be a self when the decorator is called
a decorator:
#foo
def bar(): ...
is roughly equivalent to
def bar(): ...
bar = foo(bar)
in your particular example, if you remove the self parameter, it should function as you expect:
def addition(func_goodbye):
ln_house = len('house')
ln_school = len('school')
add = ln_house + ln_school
print('The result is :' + str(add))
return func_goodbye
#addition
def goodbye(self):
print('Goodbye people !!')
for good measure, I might del addition after that just to ensure it isn't accidentally called later
(an aside: one unfortunate side-effect of this is many linters and type checkers will consider this "odd" so I've yet to find a way to appease them (for example mypy))
I have code that looks like the following:
class Token(object):
'''
Resulting from parse
'''
def __new__(cls,text,begin,end,*args,**kargs):
self = super(Token,cls).__new__(cls,*args,**kargs)
return self
def __init__(self,text,begin,end,*args,**kargs):
super(Token,self).__init__(*args,**kargs)
self.text = text
self.begin = begin
self.end = end
class List(Token,list):
pass
class Str(Token,str):
pass
class Int(Token,int):
pass
s = Str('hey there',0,3,'hey there'[0:3])
print(s)
x = Int('55 12',0,2,'55 12'[0:2])
print(x)
Basically what I want to do is to easily create types that are just normal Python types, but with some extra information to them.
Python 2 seems to be OK with the above code, but Python 3 complains
Traceback (most recent call last):
File "simple.py", line 71, in <module>
s = Str('',1,2,'hey')
File "simple.py", line 12, in __init__
super(Token,self).__init__(*args,**kargs)
TypeError: object.__init__() takes no parameters
I think the interpreters would be happy if I did something like
class List(list):
def __init__(self,text,begin,end,*args,**kargs):
list.__init__(*args,**kargs)
But this would mean I would have to repeat something similar for every new class I want to make... and I would rather stay relatively DRY...
Is there a 'proper' way I should handle this situation so that both Python 2 and Python 3 are happy?
Your best bet is to use exception handling here:
def __init__(self,text,begin,end,*args,**kargs):
try:
super(Token,self).__init__(*args,**kargs)
except TypeError:
# Python 3 and the mixed in type is immutable.
# Ignoring this is fine, `__new__` took care of this.
pass
self.text = text
self.begin = begin
self.end = end
I'm writing a test runner. I have an object that can catch and store exceptions, which will be formatted as a string later as part of the test failure report. I'm trying to unit-test the procedure that formats the exception.
In my test setup, I don't want to actually throw an exception for my object to catch, mainly because it means that the traceback won't be predictable. (If the file changes length, the line numbers in the traceback will change.)
How can I attach a fake traceback to an exception, so that I can make assertions about the way it's formatted? Is this even possible? I'm using Python 3.3.
Simplified example:
class ExceptionCatcher(object):
def __init__(self, function_to_try):
self.f = function_to_try
self.exception = None
def try_run(self):
try:
self.f()
except Exception as e:
self.exception = e
def format_exception_catcher(catcher):
pass
# No implementation yet - I'm doing TDD.
# This'll probably use the 'traceback' module to stringify catcher.exception
class TestFormattingExceptions(unittest.TestCase):
def test_formatting(self):
catcher = ExceptionCatcher(None)
catcher.exception = ValueError("Oh no")
# do something to catcher.exception so that it has a traceback?
output_str = format_exception_catcher(catcher)
self.assertEquals(output_str,
"""Traceback (most recent call last):
File "nonexistent_file.py", line 100, in nonexistent_function
raise ValueError("Oh no")
ValueError: Oh no
""")
Reading the source of traceback.py pointed me in the right direction. Here's my hacky solution, which involves faking the frame and code objects which the traceback would normally hold references to.
import traceback
class FakeCode(object):
def __init__(self, co_filename, co_name):
self.co_filename = co_filename
self.co_name = co_name
class FakeFrame(object):
def __init__(self, f_code, f_globals):
self.f_code = f_code
self.f_globals = f_globals
class FakeTraceback(object):
def __init__(self, frames, line_nums):
if len(frames) != len(line_nums):
raise ValueError("Ya messed up!")
self._frames = frames
self._line_nums = line_nums
self.tb_frame = frames[0]
self.tb_lineno = line_nums[0]
#property
def tb_next(self):
if len(self._frames) > 1:
return FakeTraceback(self._frames[1:], self._line_nums[1:])
class FakeException(Exception):
def __init__(self, *args, **kwargs):
self._tb = None
super().__init__(*args, **kwargs)
#property
def __traceback__(self):
return self._tb
#__traceback__.setter
def __traceback__(self, value):
self._tb = value
def with_traceback(self, value):
self._tb = value
return self
code1 = FakeCode("made_up_filename.py", "non_existent_function")
code2 = FakeCode("another_non_existent_file.py", "another_non_existent_method")
frame1 = FakeFrame(code1, {})
frame2 = FakeFrame(code2, {})
tb = FakeTraceback([frame1, frame2], [1,3])
exc = FakeException("yo").with_traceback(tb)
print(''.join(traceback.format_exception(FakeException, exc, tb)))
# Traceback (most recent call last):
# File "made_up_filename.py", line 1, in non_existent_function
# File "another_non_existent_file.py", line 3, in another_non_existent_method
# FakeException: yo
Thanks to #User for providing FakeException, which is necessary because real exceptions type-check the argument to with_traceback().
This version does have a few limitations:
It doesn't print the lines of code for each stack frame, as a real
traceback would, because format_exception goes off to look for the
real file that the code came from (which doesn't exist in our case).
If you want to make this work, you need to insert fake data into
linecache's
cache (because traceback uses linecache to get hold of the source
code), per #User's answer
below.
You also can't actually raise exc and expect the fake traceback
to survive.
More generally, if you have client code that traverses tracebacks in
a different manner than traceback does (such as much of the inspect
module), these fakes probably won't work. You'd need to add whatever
extra attributes the client code expects.
These limitations are fine for my purposes - I'm just using it as a test double for code that calls traceback - but if you want to do more involved traceback manipulation, it looks like you might have to go down to the C level.
EDIT2:
That is the code of linecache.. I will comment on it.
def updatecache(filename, module_globals=None): # module_globals is a dict
# ...
if module_globals and '__loader__' in module_globals:
name = module_globals.get('__name__')
loader = module_globals['__loader__']
# module_globals = dict(__name__ = 'somename', __loader__ = loader)
get_source = getattr(loader, 'get_source', None)
# loader must have a 'get_source' function that returns the source
if name and get_source:
try:
data = get_source(name)
except (ImportError, IOError):
pass
else:
if data is None:
# No luck, the PEP302 loader cannot find the source
# for this module.
return []
cache[filename] = (
len(data), None,
[line+'\n' for line in data.splitlines()], fullname
)
return cache[filename][2]
That means before you testrun just do:
class Loader:
def get_source(self):
return 'source of the module'
import linecache
linecache.updatecache(filename, dict(__name__ = 'modulename without <> around',
__loader__ = Loader()))
and 'source of the module' is the source of the module you test.
EDIT1:
My solution so far:
class MyExeption(Exception):
_traceback = None
#property
def __traceback__(self):
return self._traceback
#__traceback__.setter
def __traceback__(self, value):
self._traceback = value
def with_traceback(self, tb_or_none):
self.__traceback__ = tb_or_none
return self
Now you can set the custom tracebacks of the exception:
e = MyExeption().with_traceback(1)
What you usually do if you reraise an exception:
raise e.with_traceback(fake_tb)
All exception prints walk through this function:
import traceback
traceback.print_exception(_type, _error, _traceback)
Hope it helps somehow.
You should be able to simply raise whatever fake exception you want where you want it in your test runs. The python exception docs suggest you create a class and raise that as your exception. It's section 8.5 of the docs.
http://docs.python.org/2/tutorial/errors.html
Should be pretty straightforward once you've got the class created.
What is the error below? Also, is there a better way to implement the following classes?
#!/usr/bin/python
class Datacenters:
def __init__(self,name,location,cpu,mem):
self.name=name
self.location=location
self.cpu=cpu
self.mem=mem
def getparam(self):
return self.name,self.location ,self.cpu,self.mem
def getname(self):
return self.name
class WS(Datacenters):
def __init__(self,name,location,cpu,mem,obj):
#datacentername = Datacenters.__init__(self) #To which data center it is associated
self.dcname =obj.name #To which data center it is associated
Datacenters.__init__(obj,name,location,cpu,mem)
def getparam(self,obj):
self.name,self.location ,self.cpu,self.mem = obj.getparam()
print self.dcname
#return self.name,self.location ,self.cpu,self.mem,obj.name
def getwsname(self):
return self.name
class Pcs(WS):
def __init__(self,name,location,cpu,mem,obj):
self.wsname = obj.getwsname() #To which WS it is associated
WS.__init__(obj,name,location,cpu,mem)
def getparam(self,obj):
print obj.getparam()
print self.wsname
a = Datacenters("dc1","Bl1",20,30)
print a.getparam()
b = WS("WS1","Bl1",21,31,a)
print b.getparam(a)
c = Pcs("PC1","Bl1",20,30,b)
#print c.getparam(b)
output:
Press ENTER or type command to continue
('dc1', 'Bl1', 20, 30)
dc1
None
Traceback (most recent call last):
File "class1.py", line 45, in <module>
c = Pcs("PC1","Bl1",20,30,b)
File "class1.py", line 34, in __init__
WS.__init__(obj,name,location,cpu,mem)
TypeError: __init__() takes exactly 6 arguments (5 given)
The error is that you pass in five arguments, but the __init__ needs six. Count them:
def __init__(self,name,location,cpu,mem,obj):
Six arguments. You call it like so:
WS.__init__(obj,name,location,cpu,mem)
Five arguments. The first one, self is missing. What you should ask yourself is why you don't have to pass in six arguments all the time.
And that is because self is passed in automatically when you call the method on an instance. However, in this case you don't call it on an instance, you call it directly on the class. There is of course no need to do so in this case, the correct syntax is:
WS(obj,name,location,cpu,mem)
As you indeed above note works further up.