The Ups and Downs of Migrating to Python 3

A Pragmatic Approach

python

Overview

What's New

What's Touchy

What's Coming

Catching Up

Catching Up

Conception

  • Python 2 has "mistakes"

  • No we don't need a special function that does:

    def input():
        eval(sys.stdin.readline())
          

  • Wat

    wat
        > 1 + "0"
        '10'

    Wat

    wat
    >>> 1 < "0"
    True
    

    A million names to be cruel

    url...wat?

    Wat

    >>> d = {u"foo" : 12, b"bar" : "monkeys"}
    >>> d[b"foo"], d[u"bar"]
    (12, "monkeys")

    Wat

    def add(s1, s2):            
        return " ".join(s1, s2) 
    
    >>> print add(u"hello", "world")
    "hello world"
    >>> print add(u"hello", "w ⓞ rld")
    Traceback (most recent call last):
        ...
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 3: ordinal not in range(128)

    Walk the Line

    So you want to write 2.x+3.x code

    Figure out how!

    So you want to write 2.x+3.x code

    Ignore <2.6 and <(=)3.1

        try:
            int("Arg!")
        except ValueError, e:
            pass
        
    

    So you want to write 2.x+3.x code

    Be clever.

        from __future__ import unicode_literals, division
    
        if PY3:
            from urllib import parse as urlparse
            from urllib.parse import unquote
            from urllib.request import urlopen
            basestring = unicode = str
            iteritems = operator.methodcaller("items")
        else:
            from itertools import izip as zip
            from urllib import unquote
            from urllib2 import urlopen
            import urlparse
            iteritems = operator.methodcaller("iteritems")
        
    

    Lighten Up

    tricycle

    The Stragglers

    The Tragic Tale of twisted.internet.test.test_tcp

        $ bin/trial twisted.test.test_tcp
        ...
        Ran 36 tests in 0.875s
    
    $ admin/run-python3-tests twisted.test.test_tcp
        ...
        Ran 36 tests in 38.698s
    

    zerozerozerozero

  • Python 2:
  • >>> bytes(14)
    '14'
    
    
  • Python 3:
  • >>> bytes(14)
    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    

    contextlib.ExitStack

        def process(file=None):
            if file is None:
                file = open("a/default/file")
                cleanup_needed = True
    
            try:
                result = perform_operation()
                if result:
                    cleanup_needed = False
            finally:
                if cleanup_needed:
                    cleanup_resources()
        
    

    contextlib.ExitStack

        from contextlib import ExitStack
    
        def process(file=None):
            with ExitStack() as stack:
                if file is None:
                    file = open("a/default/file")
                    stack.enter_context(file)
                process(file)
        
    

    Oh no! An exception!

        try:
            with open("document.txt") as f:
                content = f.read()
        except IOError as err:
            if err.errno == ENOENT:
                pass
            raise
    try:                                
        with open("document.txt") as f: 
            content = f.read()          
    except FileNotFoundError:           
        pass                            
    

    Subtests

        class TestMultiplication(unittest.TestCase):
            def test_multiply(self):
                for i, j in itertools.product(range(2, 5), range(1, 3)):
                        with self.subTest(i=i, j=j):
                            self.assertEqual(multiply(i, j), i * j)
        
    

    Optional Subparsers

        $ git --version
        $ git commit -m "Hi!"
        $ git --color commit -m "Hi!"
        
    

    Thanks

    /

    #