I have a callback chain with an errback at the end. If any of the callbacks fail, I need to pass an object to be used on errBack.
How can I pass an object from callback to the errback?
The following code exemplifies what I want to do:
from twisted.internet.defer import FAILURE
from twisted.internet import defer
class CodMsg(object):
def __init__(self, code, msg):
self.code = code
self.msg = msg
class Resource(object):
#classmethod
def checkCondition(cls, result):
if result == "error":
cdm = CodMsg(1, 'Error 1')
raise FAILURE, cdm
else:
return "ok"
#classmethod
def erBackTst (cls, result):
####### How to get the value of cdm here? ######## <<<===
print 'Error:'
print result
return result
d = defer.Deferred()
d.addCallback(Resource.checkCondition)
d.addErrback(Resource.erBackTst)
d.callback("error")
print d.result
In this case you can just raise an exception, containing all info you need
For example:
from twisted.internet import defer
class MyCustomException(Exception):
def __init__(self, msg, code):
self.code = code
self.message = msg
def callback(result):
print result
raise MyCustomException('Message', 23)
def errback(failure):
# failure.value is an exception instance that you raised in callback
print failure.value.message
print failure.value.code
d = defer.Deferred()
d.addCallback(callback)
d.addErrback(errback)
d.callback("error")
Also for better understanding deffereds and async programming you can read this nice twisted tutorial http://krondo.com/an-introduction-to-asynchronous-programming-and-twisted/.
It uses a little bit outdated twisted version in examples but it is still an exellent source to start learning twisted
Related
I'm new to python and trying to remove/trim gevent stacktrace output when an exception is raised. I read somewhere that I can make it happen by using AsyncResult, however it seems like I can't figure out how to use this.
Here is an example I started with and iterated over to make it similar to the real code I'm troubleshooting, but I got stuck in the last phase when I tried to add my_decor to work().
Any help fixing this is much appreciated.
from gevent.event import AsyncResult
import gevent
from functools import wraps
def my_decor(k, *args, **kwargs):
#wraps(k)
def wrapper(*args, **kwargs):
r = AsyncResult()
try:
value = k()
except Exception as e:
r.set_exception(e)
else:
r.set(value)
return r.exception or r.value
result = gevent.spawn(wrapper, k)
return result
def f():
def foo():
if True:
raise Exception('tttttttt')
return foo
def p():
def bar():
if True:
raise Exception('ppppppppppppp')
return bar
#my_decor
def work():
foo1 = gevent.spawn(f())
bar1 = gevent.spawn(p())
gevent.joinall([foo1, bar1])
return foo1.get() or bar1.get()
Found the answer, figured it might be a help to those with the same problem.
from gevent.event import AsyncResult
import gevent
from functools import wraps
def my_decor(k):
#wraps(k)
def wrapper(*args, **kwargs):
r = AsyncResult()
try:
value = k(*args, **kwargs)
except Exception as e:
r.set_exception(e)
else:
r.set(value)
return r.exception or r.value
return wrapper
def f(msg):
#my_decor
def foo():
if True:
raise Exception('tttttttt %s' % msg)
# print('test')
return foo
def p(msg):
#my_decor
def bar():
if True:
raise Exception('ppppppppppppp %s', msg)
return bar
def work():
test = "test"
seti = "set"
foo1 = gevent.spawn(f(test)) # returns a function that coroutine uses
bar1 = gevent.spawn(p(seti))
gevent.joinall([foo1, bar1])
return foo1.get() or bar1.get()
res = work()
print res
In the following code, I'm trying to create a class 'TimedExecutor' which would stop the execution of the function(bar) passed to its method 'execute' if exceeds a certain time limit. But, the program execution doesn't stop, even though the error message is displayed.
Note: We must not make any changes to the function bar(), as it is provided by an external module.
import signal
import time
class MyError(Exception):
"""Base error"""
class MyInheritedError(MyError):
"""Class to inherit from base error"""
class TimeoutListener(object):
def __init__(self, timeout_seconds, error_message="Timeout executing."):
self.timeout_seconds = timeout_seconds
self.error_message = error_message
self.alarm = None
def __enter__(self):
signal.signal(signal.SIGALRM, self._handle_timeout)
signal.alarm(self.timeout_seconds)
def __exit__(self, listener_type, value, traceback):
# Disable the alarm.
if self.alarm:
self.alarm = None
else:
signal.alarm(0)
def _handle_timeout(self, signum, frame):
print("Got the signum %s with frame: %s" % (signum, frame))
raise MyInheritedError(self.error_message + "aditya")
class TimedExecutor(object):
#staticmethod
def execute(timeout_secs, functor, *args, **kwargs):
msg = "Timeout executing method - %s." % functor.__name__
timeout_signal = TimeoutListener(timeout_secs, error_message=msg)
try:
with timeout_signal:
output = functor(*args, **kwargs)
except MyInheritedError as ex:
print("%s did not complete in %s: %s."
% (functor.__name__, timeout_secs, repr(ex)))
raise
return output
def bar():
for _ in range(5):
try:
time.sleep(1)
print("SLEEPING")
except MyInheritedError as ex:
print ex
ob = TimedExecutor.execute(2, bar)
Your functor is swallowing the exception you intend to be fatal.
It is bar()'s except clause in one of its loops that prints and then discards the error raised by the TimeoutListener context manager. Then the loop resumes.
bar() should probably not be aware of the exception your TimedExecutor can raise. Instead, bar()'s caller who invokes .execute() should be aware of it:
from aditya.utils import TimedExecutor, TimeoutException
...
try:
TimedExecutor.execute(2, bar)
except TimeoutException:
print("Timed out executing bar")
I try to build a udp server to receive binary messages, the socket emits processMsg signal when it received message and the processMsg function tries to emit different signal according to the message type. The QDefines object defines the message type and signal to be generated. I use dict to work around the missing switch/case in python. The problem is that the setRfRsp function didn't execute when UCSI_SET_RF_RSP_E message recevied.
Main.py file:
class mainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
super(mainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.defines = QDefines()
self.connect(self.defines,QtCore.SIGNAL("signalSetRfRsp(PyQt_PyObject)"), self.setRfRsp)
self.socket = QUdp(self.localIp, self.localPort, self.remoteIp, self.remotePort)
self.connect(self.socket, QtCore.SIGNAL("processMsg(int,PyQt_PyObject)"), self.processMsg)
def setRfRsp(self, msg):
if msg == 0x00000000:
print "open"
else:
print "closed"
def processMsg(self, msgType, msg):
defines = QDefines()
msg_dict = defines.msgDictGen();
msg_dict[msgType](msg)
defines.py file:
class QDefines(QtCore.QObject):
UCSI_SET_RF_RSP_E = 0x000d
def __init__(self, parent = None):
super(QDefines, self).__init__()
def UCSI_SET_RF_RSP(self, msg):
self.emit(QtCore.SIGNAL("signalSetRfRsp(PyQt_PyObject)"), msg)
def msgDictGen(self):
self.msgDict = {
self.UCSI_SET_RF_RSP_E : self.UCSI_SET_RF_RSP
}
return self.msgDict
The instance of QDefines that emits the signal never has any of its signals connected to anything, and it just gets garbage-collected when processMsg returns.
Perhaps you meant to write:
def processMsg(self, msgType, msg):
msg_dict = self.defines.msgDictGen()
msg_dict[msgType](msg)
You should also consider getting rid of that nasty, old-style signal syntax, and use the nice, clean new-style instead:
class QDefines(QtCore.QObject):
signalSetRfRsp = QtCore.pyqtSignal(object)
...
def UCSI_SET_RF_RSP(self, msg):
self.signalSetRfRsp.emit(msg)
class mainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
...
self.defines = QDefines()
self.defines.signalSetRfRsp.connect(self.setRfRsp)
Also, I would advise you to forget about trying to replicate switch statements in python, and just use if/elif instead. You'd need a very large number of branches before this started to become a significant performance issue.
I am trying to find a good way to log a warning message but appending to it information that is only known by the caller of the function.
I think it will be clear with an example.
# log method as parameter
class Runner1(object):
def __init__(self, log):
self.log = log
def run(self):
self.log('First Warning')
self.log('Second Warning')
return 42
class Main1(object):
def __init__(self):
self._runner = Runner1(self.log)
def log(self, message):
print('Some object specific info: {}'.format(message))
def run(self):
print(self._runner.run())
e1 = Main1()
e1.run()
The Main object has a log function that adds to any message its own information before logging it. This log function is given as a parameter (in this case to a Runner object). Carrying this extra parameter all the time is extremely annoying and I would like to avoid it. There are usually lots of object/functions and therefore I have discarded the use of the logging method as I would need to create a different logger for each object. (Is this correct?)
I have tried to bubble the warning using the warning module:
# warning module
import warnings
class Runner2(object):
def run(self):
warnings.warn('First Warning')
warnings.warn('Second Warning')
return 42
class Main2(object):
def __init__(self):
self._runner = Runner2()
def log(self, message):
print('Some object specific info: {}'.format(message))
def run(self):
with warnings.catch_warnings(record=True) as ws:
warnings.simplefilter("always")
out = self._runner.run()
for w in ws:
self.log(w.message)
print(out)
e2 = Main2()
e2.run()
But according to the docs, this is not thread safe.
Finally, I have also tried some generators:
# yield warning
class _Warning(object):
def __init__(self, message):
self.message = message
class Runner3(object):
def run(self):
yield _Warning('First Warning')
yield _Warning('Second Warning')
yield 42
class Main3(object):
def __init__(self):
self._runner = Runner3()
def log(self, message):
print('Some object specific info: {}'.format(message))
def run(self):
for out in self._runner.run():
if not isinstance(out, _Warning):
break
self.log(out.message)
print(out)
e3 = Main3()
e3.run()
But the fact that you have to modify the Runner.run to yield (instead of return) the final result is inconvenient as functions will have to be specifically changed to be used in this way (Maybe this will change in the future? Last QA in PEP255). Additionally, I am not sure if there is any other trouble with this type of implementation.
So what I am looking for is a thread-safe way of bubbling warnings that does not require passing parameters. I also would like that methods that do not have warnings remain unchanged. Adding a special construct such as yield or warning.warn to bubble the warnings would be fine.
Any ideas?
import Queue
log = Queue.Queue()
class Runner1(object):
def run(self):
log.put('First Warning')
log.put('Second Warning')
return 42
class Main1(object):
def __init__(self):
self._runner = Runner1()
def log(self, message):
print('Some object specific info: {0}'.format(message))
def run(self):
out=self._runner.run()
while True:
try:
msg = log.get_nowait()
self.log(msg)
except Queue.Empty:
break
print(out)
e1 = Main1()
e1.run()
yields
Some object specific info: First Warning
Some object specific info: Second Warning
42
I tried to get support on this but I am TOTALLY confused.
Here's my code:
from twisted.internet import reactor
from twisted.web.client import getPage
from twisted.web.error import Error
from twisted.internet.defer import DeferredList
from sys import argv
class GrabPage:
def __init__(self, page):
self.page = page
def start(self, *args):
if args == ():
# We apparently don't need authentication for this
d1 = getPage(self.page)
else:
if len(args) == 2:
# We have our login information
d1 = getPage(self.page, headers={"Authorization": " ".join(args)})
else:
raise Exception('Missing parameters')
d1.addCallback(self.pageCallback)
dl = DeferredList([d1])
d1.addErrback(self.errorHandler)
dl.addCallback(self.listCallback)
def errorHandler(self,result):
# Bad thingy!
pass
def pageCallback(self, result):
return result
def listCallback(self, result):
print result
a = GrabPage('http://www.google.com')
data = a.start() # Not the HTML
I wish to get the HTML out which is given to pageCallback when start() is called. This has been a pita for me. Ty! And sorry for my sucky coding.
You're missing the basics of how Twisted operates. It all revolves around the reactor, which you're never even running. Think of the reactor like this:
(source: krondo.com)
Until you start the reactor, by setting up deferreds all you're doing is chaining them with no events from which to fire.
I recommend you give the Twisted Intro by Dave Peticolas a read. It's quick and it really gives you all the missing information that the Twisted documentation doesn't.
Anyways, here is the most basic usage example of getPage as possible:
from twisted.web.client import getPage
from twisted.internet import reactor
url = 'http://aol.com'
def print_and_stop(output):
print output
if reactor.running:
reactor.stop()
if __name__ == '__main__':
print 'fetching', url
d = getPage(url)
d.addCallback(print_and_stop)
reactor.run()
Since getPage returns a deferred, I'm adding the callback print_and_stop to the deferred chain. After that, I start the reactor. The reactor fires getPage, which then fires print_and_stop which prints the data from aol.com and then stops the reactor.
Edit to show a working example of OP's code:
class GrabPage:
def __init__(self, page):
self.page = page
########### I added this:
self.data = None
def start(self, *args):
if args == ():
# We apparently don't need authentication for this
d1 = getPage(self.page)
else:
if len(args) == 2:
# We have our login information
d1 = getPage(self.page, headers={"Authorization": " ".join(args)})
else:
raise Exception('Missing parameters')
d1.addCallback(self.pageCallback)
dl = DeferredList([d1])
d1.addErrback(self.errorHandler)
dl.addCallback(self.listCallback)
def errorHandler(self,result):
# Bad thingy!
pass
def pageCallback(self, result):
########### I added this, to hold the data:
self.data = result
return result
def listCallback(self, result):
print result
# Added for effect:
if reactor.running:
reactor.stop()
a = GrabPage('http://google.com')
########### Just call it without assigning to data
#data = a.start() # Not the HTML
a.start()
########### I added this:
if not reactor.running:
reactor.run()
########### Reference the data attribute from the class
data = a.data
print '------REACTOR STOPPED------'
print
########### First 100 characters of a.data:
print '------a.data[:100]------'
print data[:100]