Skip to content

Instantly share code, notes, and snippets.

@mbarkhau
Last active April 16, 2016 20:50
Show Gist options
  • Save mbarkhau/a9a7816c0652ac698fac to your computer and use it in GitHub Desktop.
Save mbarkhau/a9a7816c0652ac698fac to your computer and use it in GitHub Desktop.
pysix.py
# -*- coding: utf-8 -*-
# "Writing Python 3 code that's compatible with Python 2 is
# much more rewarding than the opposite. Not only does that
# make your code more future-proof, but Python 3’s advantages
# (like the saner string handling) start shining quickly.
# Dealing with Python 2 becomes a backwards compatibility
# requirement" – "Porting to Python 3" from the Django Project
# This file provides boilerplate for scripts to run in both
# python2.7 and python3.4. As much as possible it attempts
# to replicate semantics of python3.
# The boilerplate should only be needed so long as python2.7
# must still be supported. Once that is not the case, the
# boilerplate should be easily removed, with only minimal
# and trivial changes to the rest of the code.
# Some notes on writing compatible code where boilerplate
# cannot help.
#
# - Use the string prefix "b" to make your string type
# explicit. Using from __future__ import unicode_literals
# ensures that all other strings are unicode, as is the
# default in python 3.
#
# - Use .format instead of % to format strings, as %
# is only defined for bytes in python3.
#
# see also
# http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/
# https://docs.djangoproject.com/en/1.8/topics/python3/
# http://astrofrog.github.io/blog/2016/01/12/stop-writing-python-4-incompatible-code/
# http://python3porting.com/stdlib.html#urllib-urllib2-and-urlparse
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
from __future__ import unicode_literals
import sys
PY2 = sys.version_info.major == 2
# compat code for string types
native_chr = chr
if PY2:
str_types = (str, unicode)
bytes = str
str = unicode
chr = unichr
else:
str_types = (bytes, str)
bytes = bytes
str = str
chr = chr
# encode decode helpers
# assuming default encoding of utf-8
s2b = lambda s, encoding='utf-8': s.encode(encoding)
b2s = lambda b, encoding='utf-8': b.decode(encoding)
if PY2:
i2b = lambda ints: b"".join(map(native_chr, ints))
b2i = ord
else:
i2b = bytes
b2i = int
# compat code for int/long
# This is needed because the long type no longer
# exists in python3.
if PY2:
int_types = (int, long)
else:
int_types = (int,)
# compat code for builtins iteration
import itertools as it
if PY2:
range = xrange
py2map = map
map = it.imap
py2zip = zip
zip = it.izip
input = raw_input
else:
zip = zip
input = input
map = map
range = range
# compat code for collection iteration
if PY2:
vitems = dict.viewitems
vkeys = dict.viewkeys
vvalues = dict.viewvalues
else:
vitems = dict.items
vkeys = dict.keys
vvalues = dict.values
# In python3 the builtin open function will read decoded
# strings. For python2 the open function is replaced with
# the open function with the io module, which supports
# similar behaviour. Unless you are reading with mode='b',
# you should always supply an encoding.
import io
def open(filename, mode='r', **kwargs):
if 'encoding' not in kwargs:
kwargs['encoding'] = 'utf-8'
if 'b' in mode:
kwargs['encoding'] = None
return io.open(filename, mode, **kwargs)
if PY2:
from cStringIO import StringIO as BytesIO, StringIO
else:
from io import BytesIO, StringIO
if PY2:
from urllib import quote, unquote
else:
from urllib.parse import quote, unquote
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment