[Twisted-Python] Problem with Deferreds

Chris Norman chris.norman2 at googlemail.com
Sat Apr 2 08:22:33 MDT 2016


Hi,
Yes, that sorted the problem out no worries.

Thank you so much.



On 02/04/2016 15:00, Kevin Conway wrote:
> Hi Chris,
>
> tl;dr: Returning a value from 'dataReceived', or any of its extensions 
> such as 'lineReceived' in the 'LineReceiver' Protocol subclass, 
> triggers a disconnect and uses the returned value as the 'reason'. A 
> 'reason' must be an Exception or t.p.Failure object as other values 
> will trigger this error.
>
> Are you quite certain that your last line is not getting printed? I'm 
> not sure exactly where this feature is documented, but returning any 
> non-None value from a Protocol's 'dataReceived' method can result in 
> this behaviour. The t.protocols.basic.LineReceiver calls 
> 'lineReceived' from 'dataReceived' and returns any value it gets from 
> your implementation. The value returned from 'dataReceived' is passed 
> along to the transport's 'doRead' which, again, returns it to the 
> portion of the reactor handling selectables. The reactor assumes that 
> anything returned from a transport during a read or write operation is 
> a bad thing and disconnects the transport. During the disconnect 
> process the reactor is generating a t.p.failure.Failure object and 
> passing in your returned value as the 'why' which is expected to be an 
> Exception or Failure and not a Deferred. Try returning None instead of 
> your Deferred. That should resolve this particular issue.
>
> On Sat, Apr 2, 2016 at 4:39 AM Chris Norman 
> <chris.norman2 at googlemail.com <mailto:chris.norman2 at googlemail.com>> 
> wrote:
>
>     Hi all,
>     I recently got over myself and forced myself to read about Deferreds
>     rather than using threading opperations.
>
>     I've used them successfully in a couple of places, but this one has me
>     flummoxed:
>
>     Here's the code for the Deferred and it's sub-commands:
>
>       def do_command(self, cmd, **kwargs):
>        """Process a command in true Deferred style."""
>        if cmd.permissions(self.connection):
>         cmd(self.connection, **kwargs)
>        else:
>         logger.warning('Blocked from running command %s which is secured
>     with %s.', cmd.__name__, cmd.permissions.__name__)
>         raise CommandError('You have insufficient privileges to
>     perform this
>     action. The staff have been notified.')
>
>       def handle_error(self, err):
>        """Handle an error from do_command."""
>        if isinstance(err, CommandError):
>         return self.send_error(e.message, disconnect = e.disconnect)
>        else:
>         self.log(e, level = 'exception')
>         self.send_error('Sorry, but a problem with the server means your
>     command was not executed. The staff have been notified.')
>
>       def lineReceived(self, line):
>        """Parse an incoming command."""
>        global lines
>        lines += 1 # Increment the line count.
>        data = line.decode(settings.ENCODING)
>        try:
>         command, kwargs = json.loads(data)
>         if not isinstance(command, string_types) or not isinstance(kwargs,
>     dict):
>          raise TypeError('Expecting [str, dict]. Got [%s, %s] instead.' %
>     (type(command), type(kwargs)))
>        except (TypeError, ValueError) as e:
>         self.log('Invalid command string: %s', data, level = 'error')
>         self.log(e, level = 'exception')
>         return self.send_error('Invalid command.', disconnect = True)
>        cmd = commands.commands.get(command, None)
>        if cmd  is None:
>         self.log('Unrecognised command: %s.', command, level = 'warning')
>        elif self.connection.player or not cmd.login_required:
>         d = defer.Deferred()
>         print('Adding callback.')
>         d.addCallback(self.do_command, **kwargs)
>         print('Adding errback.')
>         d.addErrback(self.handle_error)
>         print('Calling callback.')
>         d.callback(cmd)
>         print('Called.') # Never gets this far.
>         return d
>        else:
>         return self.send_error('Not authenticated.', disconnect = True)
>
>     Here's the traceback I get when the callback gets called:
>
>     Unhandled Error
>     Traceback (most recent call last):
>        File "server/functions.py", line 88, in server_start
>          reactor.run()
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/internet/base.py",
>     line 1194, in run
>          self.mainLoop()
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/internet/base.py",
>     line 1206, in mainLoop
>          self.doIteration(t)
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/internet/epollreactor.py",
>     line 396, in doPoll
>          log.callWithLogger(selectable, _drdw, selectable, fd, event)
>     --- <exception caught here> ---
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/python/log.py",
>     line 101, in callWithLogger
>          return callWithContext({"system": lp}, func, *args, **kw)
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/python/log.py",
>     line 84, in callWithContext
>          return context.call({ILogContext: newCtx}, func, *args, **kw)
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/python/context.py",
>     line 118, in callWithContext
>          return self.currentContext().callWithContext(ctx, func,
>     *args, **kw)
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/python/context.py",
>     line 81, in callWithContext
>          return func(*args,**kw)
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/internet/posixbase.py",
>     line 610, in _doReadOrWrite
>          self._disconnectSelectable(selectable, why, inRead)
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/internet/posixbase.py",
>     line 258, in _disconnectSelectable
>          selectable.connectionLost(failure.Failure(why))
>        File
>     "/usr/local/lib/python3.5/site-packages/Twisted-16.0.0-py3.5.egg/twisted/python/failure.py",
>     line 232, in __init__
>          tb = self.value.__traceback__
>     builtins.AttributeError: 'Deferred' object has no attribute
>     '__traceback__'
>
>     Anyone have any ideas?
>
>     Cheers,
>
>     Chris
>
>     _______________________________________________
>     Twisted-Python mailing list
>     Twisted-Python at twistedmatrix.com
>     <mailto:Twisted-Python at twistedmatrix.com>
>     http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
>
>
>
> _______________________________________________
> Twisted-Python mailing list
> Twisted-Python at twistedmatrix.com
> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20160402/a95eff4d/attachment-0002.html>


More information about the Twisted-Python mailing list