Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Future of Twisted, and Pretty Much Everythi...

The Future of Twisted, and Pretty Much Everything Else (PyCon CZ Keynote, 2015)

Keynote #1 at PyCon Czech Republic.

Amber Brown (HawkOwl)

November 14, 2015
Tweet

More Decks by Amber Brown (HawkOwl)

Other Decks in Programming

Transcript

  1. It’s a generator, and Python suspends it at the yield

    point, but can run other code while it is suspended
  2. Blocking means that Python cannot run anything else at all

    during that period due to I/O operations
  3. PING google.com (150.101.170.180): 56 data bytes 64 bytes: icmp_seq=0 ttl=60

    time=13.217 ms 64 bytes: icmp_seq=1 ttl=60 time=18.227 ms 64 bytes: icmp_seq=2 ttl=60 time=13.117 ms
  4. Everything revolves around the Reactor, and all the code is

    event-driven — things happen and the Reactor tells you
  5. Protocols are given a Transport to write to when a

    client/server connection is made
  6. If the socket send buffer is full, it holds a

    secondary buffer and schedules it for later
  7. Takes a list of file descriptors (eg. sockets) and returns

    the ones that can have further data written/read
  8. If more data can be written, the Reactor tells the

    Transport to flush what it can of its send buffer
  9. If more data can be read, the Reactor notifies Transport,

    which reads it and gives it to the Protocol
  10. In [11]: d = Deferred() In [12]: d.addCallback(lambda t: t

    + 1) Out[12]: <Deferred at 0x10a52f440> In [13]: d.addCallback(print) Out[13]: <Deferred at 0x10a52f440> In [14]: d.callback(12) 13
  11. import treq from twisted.internet.task import react def get(reactor): d =

    treq.get("http://atleastfornow.net") d.addCallback(treq.content) d.addCallback(print) return d react(get)
  12. import treq from twisted.internet.task import react from twisted.internet.defer import inlineCallbacks

    @inlineCallbacks def get(reactor): request = yield treq.get("http://atleastfornow.net") content = yield treq.content(request) print(content) react(get)
  13. This is Django… …with async views… …with an async ORM…

    …running on Twisted Web… …with no WSGI.
  14. Caveats: I wrote this on a plane, the ORM runs

    in a threadpool, the tests fail hilariously
  15. Python 3.4 is still the default Python on every Linux

    distribution (Okay, except for Arch)
  16. …and assuming you have unittests for every part of your

    codebase, and every way it could be used
  17. Python 2 raise Exception, “oh no” Python 2/3 raise Exception(“oh

    no”) You must raise instances of Exceptions, not a tuple of the Exception and its arguments
  18. Python 2 print “Hello!” Python 2/3 from __future__ import print_function

    print(“Hello!”) print is a function, not a keyword.
  19. Python 2 import innerpackage Python 2/3 from __future__ import absolute_import

    import .innerpackage Python 3 imports are absolute.
  20. Python 2 2 / 5.0 == 0.4 2 / 5

    == 0 Python 2/3 from __future__ import division 2 / 5 == 0.4 2 // 5 == 0 / in Python 3 returns a float, // returns an int.
  21. Python 2 True Python 3 False In Python 2, bytes

    is an alias to str. In Python 3, it is its own type. DO NOT USE unicode_literals bytes == str
  22. Python 2 False Python 3 NameError: name 'unicode' is not

    defined The unicode type has been moved to str and is not aliased in Python 3. Use from six import text_type instead. unicode == str
  23. – RFC 7230, “3.2.4. Field Parsing" Historically, HTTP has allowed

    field content with text in the ISO-8859-1 charset, supporting other charsets only through use of RFC2047 encoding. In practice, most HTTP header field values use only a subset of the US-ASCII charset. Newly defined header fields SHOULD limit their field values to US-ASCII octets. A recipient SHOULD treat other octets in field content as opaque data.
  24. Python 2 'Hello PyCon CZ' Python 3.4 <explodes> Python 3.5

    b'Hello PyCon CZ' Python 3 removed formatting on bytes, and reinstated it in Python 3.5. b"Hello %s" % (b"PyCon CZ",)
  25. Python 2 b"Content-Length: %d" % (110,) Python 2/3 b"Content-Length: "

    + str(110).encode('ascii') Being unable to use percent- formatting means that some easy tasks become much more verbose
  26. Python 2 'Hello PyCon CZ' Python 3.4 AttributeError: 'bytes' object

    has no attribute 'format' Python 3 removed .format() on bytes, and did not return in 3.5. b"Hello {name}".format(name=b"PyCon CZ")
  27. A: Decode the format string and all arguments, then format,

    and encode back to bytes (Very slow, doesn’t work if you have random binary trash in it)
  28. B: Use percent formatting, drop 3.3 & 3.4 support (Not

    desirable, 3.4 is still a huge platform)
  29. C: Eschew formatting altogether and concatenate some bytes (Not as

    easy to read or understand, but works everywhere and is fast)
  30. response = b64encode('%s:%s' % (self.username, self.password)) response = response.strip('=')
 response

    = b64encode(b''.join([self.username, b':', self.password])) response = response.strip(b'=')
  31. So we need to rewrite every instance of percent formatting

    or use of .format() for on-wire protocols
  32. type({}.keys()) Python 2 <type ‘list'> Python 3 <class ‘dict_keys'> The

    keys, items, and values methods on dicts no longer return lists, but an iterator.
  33. Python 2 Exception(“oh no!”).message Python 2/3 Exception(“oh no!”).args[0] Exception.message was

    introduced in Python 2.5, deprecated in Python 2.6, and removed in Python 3.0.
  34. Python 2 AttributeError: class Foo has no attribute '__mro__' Python

    3 (<class '__main__.Foo'>, <class 'object'>) All classes are new-style classes in Python 3. class Foo: pass print(Foo.__mro__)
  35. Python 2 <unbound method Foo.__init__> Python 3 <function Foo.__init__ at

    0x10908cbf8> Python 3 removes the concept of “unbound methods”. class Foo(object): def __init__(self): pass print(Foo.__init__)
  36. Python 2 class MyProtocol(object): implements(ISomeInterface) pass Python 3 @implementer(ISomeInterface) class

    MyProtocol(object): pass zope.interface on Python 3 is required to be a decorator.
  37. await, async iterators, async context managers, async def PEP 492

    in Python 3.5 Not yet implemented in Twisted
  38. — Glyph “Despite the fact that implicit coroutines masquerade under

    many different names, many of which don’t include the word “thread” – for example, “greenlets”, “coroutines”, “fibers”, “tasks” – green or lightweight threads are indeed threads … In the long run, when you build a system that relies upon them, you eventually have all the pitfalls and dangers of full-blown preemptive threads.”