sixer is a tool adding Python 3 support to a Python 2 project. It was written to produces patches to port OpenStack to Python 3. It is focused on supporting Python 2.7 and 3.4.
It uses basic regular expressions to find code which needs to be modified. It emits warnings when code was not patched or looks suspicious.
- sixer project at Github (source, bug tracker)
- sixer in the Python Cheeseshop (PyPI)
See also the six module documentation.
sixer.py [--write] [options] <all|operation1[,operation2,...]> <directories or filenames>
sixer.py displays the name of patched files. It displays warnings for suspicious code which may have to be ported manually.
The first parameter can be a list of operations separated by commas. Use
"all"
to apply all operations. Operation prefixed by -
are excluded.
For example, "all,-iteritems"
applies all operations except iteritems
.
For directories, sixer.py searchs for .py
files in all subdirectories.
By default, sixer uses a dry run: files are not modified. Add --write
(or
-w
) option to modify files in place. It's better to use sixer in a project
managed by a source control manager (ex: git) to see differences and revert
unwanted changes. The original files are not kept.
Use --help
to see all available options.
See below for the list of available operations.
all
:- combine all operations all together
basestring
:- replace
basestring
withsix.string_types
, addimport six
- replace
dict0
:- replace
dict.keys()[0]
withlist(dict.keys())[0]
- same for
dict.values()[0]
anddict.items()[0]
- note: the pattern matches any integer index, not only
0
- replace
dict_add
:- replace
dict.keys() + list2
withlist(dict.keys()) + list2
- same for
dict.values() + list2
anddict.items() + list2
- replace
except
:- Replace
except ValueError, exc:
withexcept ValueError as exc:
- Replace
except (TypeError, ValueError), exc:
withexcept (TypeError, ValueError) as exc:
- Replace
has_key
:- Replace
dict.has_key(key)
withkey in dict
- Replace
iteritems
:- replace
dict.iteritems()
withsix.iteritems(dict)
, addimport six
- replace
itervalues
:- replace
dict.itervalues()
withsix.itervalues(dict)
, addimport six
- replace
iterkeys
:- Replace
for key in dict.iterkeys():
withfor key in dict:
- Replace
dict.iterkeys()
withsix.iterkeys(dict)
, addimport six
- Replace
itertools
:- replace
itertools.ifilter
withsix.moves.filter
, addimport six
- similar change for
ifilterfalse()
,imap()
,izip()
andizip_longest()
of theitertools
module
- replace
long
:- replace
123L
with123
(decimal) - replace
0xABl
with0xAB
(hexadecimal) - replace
0600L
with0o600
(octal) - replace
(int, long)
withsix.integer_types
- replace
long(1)
with1
- replace
next
:- replace
iter.next()
withnext(iter)
- replace
print
:- Replace
print msg
withprint(msg)
- Replace
print msg,
withprint(msg, end=' ')
and addfrom __future__ import print_function
import - Replace
print
withprint()
and addfrom __future__ import print_function
import - Replace
print >>sys.stderr, "hello"'
withprint("hello", file=sys.stderr)
and addfrom __future__ import print_function
import
- Replace
raise
:- replace
raise exc[0], exc[1], exc[2]
withsix.reraise(*exc)
, addimport six
- replace
raise exc_type, exc_value, exc_tb
withsix.reraise(exc_type, exc_value, exc_tb)
, addimport six
- replace
raise exc, msg
withraise exc(msg)
, addimport six
- replace
six_moves
:- replace Python 2 imports with imports from
six.moves
, addimport six
. Python 2 modules:BaseHTTPServer
ConfigParser
Cookie
HTMLParser
Queue
SimpleHTTPServer
SimpleXMLRPCServer
__builtin__
cPickle
cookielib
htmlentitydefs
httplib
repr
xmlrpclib
- replace Python 2 functions with
six.moves.<function>
, addimport six
. Python 2 functions:raw_input()
reduce()
reload()
- replace
unichr()
withsix.unichr()
, addimport six
- replace Python 2 imports with imports from
string
:- replace
string.xxx(str, ...)
withstr.xxx(...)
where.xxx
is a string method. For example, replacestring.upper("abc")
with"abc".upper()
. - replace
string.atof(str)
withfloat(str)
- replace
string.atoi(str)
andstring.atol(str)
withint(str)
- replace
stringio
:- replace
StringIO.StringIO
withsix.StringIO
, addimport six
- replace
cStringIO.StringIO
withmoves.cStringIO
, addfrom six import moves
- replace
from StringIO import StringIO
withfrom six import StringIO
- replace
from cStringIO import StringIO
withfrom six.moves import cStringIO as StringIO
- later you may have to replace it with
six.BytesIO
(orio.BytesIO
if you don't support Python 2.6) when bytes are expected on Python 3
- replace
unicode
:- replace
unicode
withsix.text_type
, addimport six
- replace
(str, unicode)
withsix.string_types
, addimport six
- replace
urllib
:- replace Python 2 urllib and urllib2 with
six.moves.urllib
, addimport six
- replace Python 2 urllib and urllib2 with
xrange
:- replace
xrange()
withrange()
and addfrom six.moves import range
- don't add the import if all ranges have 1024 items or less
- replace
To install sixer, type:
pip3 install sixer
sixer requires Python 3, it doesn't work on Python 2.
When an operation uses six
, import six
may be added. sixer repects
OpenStack coding style rules to add the import: imports grouped by standard
library, third party and application imports; and imports must be are sorted.
Since the project is implemented with regular expressions, it can produce false positives (invalid changes). For example, some operations replace patterns in strings, comments or function names even if it doesn't make sense.
Try also the 2to6 project which may be more reliable.
To run tests, type tox
. Type pip install -U tox
to install or update
the tox
program.
Or run tests manually: type python3 tests.py
.
- six module documentation
- 2to6
- modernize
- Python 3 porting book: Language differences and workarounds
- getpython3
- Version 1.6.1 (2018-10-24)
- Project homepage moved to: https://github.com/vstinner/sixer
- Version 1.6 (2016-07-25)
dict0
now also matches any integer index, not only0
long
now also replaceslong(1)
with1
- Version 1.5 (2016-05-30)
- six_moves: replace
ConfigParser.ConfigParser
withconfigparser.ConfigParser
, not withconfigparser.configparser
- remove the
octal
operation, it produces too many false positives
- six_moves: replace
- Version 1.4 (2016-03-11)
- display the name of applied operations in the final summary
- Issue #4: Don't emit warning on
six.next()
- Version 1.3 (2016-02-11)
- add
string
operation. For example, replacestring.upper("abc")
with"abc".upper()
. print
now also replacesprint >>sys.stderr, "hello"'
withprint("hello", file=sys.stderr)
- add
- Version 1.2 (2015-11-26)
- add
octal
operation: replace0123
with0o123
- add
print
operation: replaceprint msg
withprint(msg)
, handle also other print statements (but not all of them yet) - add
has_key
operation: replacedict.has_key(key)
withkey in dict
long
now also handles octal and hexadecimal numbers. For example,0xffL
is replaced with0xff
, and0600l
is replace with0o600
.except
now handles also exception with dots (ex:except select.error, exc:
)iterkeys
now replacesfor key in dict.iterkeys():
withfor key in dict:
to avoid the usage of six.- Enhance
except
andraise
regex to match also expressions without spaces after commas
- add
- Version 1.1 (2015-10-22)
- add
--third-party
command line option - emit a warning instead of failing with an error if we failed to find the best place to add an import
- fix also code to detect third-party modules, don't check for the prefix but the full name (ex: "numpypy" is not detected as third-party if only "numpy" is known)
- add
- Version 1.0 (2015-10-16)
- sixer doesn't modify files by default anymore. Add
--write
to really modify files inplace. long
operation now also replaces(int, long)
withsix.integer_types
itertools
now also replacesifilterfalse()
,izip()
andizip_longest()
of theitertools
modulesix_moves
now also replacesunichr(ch)
withsix.unichr(ch)
- command line: it's now possible to exclude an operation using
-
prefix. For example,all,-iteritems
applies all operations exceptiteritems
.
- sixer doesn't modify files by default anymore. Add
- Version 0.8 (2015-10-03)
- urllib now emits a warning on unknown symbol, instead of raising an exception
- Write warnings to stderr instead of stdout and exit with error code 1 if a filename doesn't exist or a directory doesn't contain any .py file
unicode
operation also replaces(str, unicode)
withsix.string_types
- When removing an import, don't remove the empty line following the import if the empty line is followed by a second import
long
also replaces1l
(lower case L suffix for long numbers)
- Version 0.7 (2015-09-29)
- Add new
dict0
,dict_add
andexcept
operations - Add --app command line option to specify the Python module of the application, to help sorting imports
- Code adding new imports respect better OpenStack coding style on imports. For example, it adds two empty lines after imports, instead of a single line.
- Display the name of the operation which modified files
- Display also the name of the operation in warnings
six_moves
now also patchesreduce()
andreload()
. For example,reduce()
is replaced withsix.moves.reduce()
.six_moves
now also patchesmock.patch()
. For example,with mock.patch('__builtin__.open'): ...
is replaced withwith mock.patch('six.moves.builtin.open'): ...
urllib
now also replacesfrom ... import ...
imports. For example,from urllib import quote
is replaced withfrom six.moves.urllib.parse import quote
.
- Add new
- Version 0.6 (2015-09-11)
- Add "itertools" operation
- Fix xrange() regex to not modify "from six.moves import xrange" and "moves.xrange(n)"
- Fix urllib for urllib or urlparse module get from the urllib2 module.
For example,
urllib2.urlparse.urlparse
(import urllib2
) is now replaced withurllib.parse.urlparse
(from six.moves import urllib
).
- Version 0.5 (2015-07-08)
- six_moves: support "import module as name" syntax and add cPickle module
- Add --to-stdout, --quiet and --max-range command line options
- Emit a warning if the directory does not contain any .py file or if the path does not exist
- Test also directly the sixer.py program
- Version 0.4 (2015-06-09)
- sixer.py now accepts multiple filenames on the command line, but operations becomes the first command line parameter
- the
stringio
operation now also replaces cStringIO andfrom StringIO import StringIO
- urllib: replace also urlparse.symbol
- six_moves: support more modules: Cookie, HTMLParser, SimpleHTTPServer, cookielib, xmlrpclib, etc.
- Refactor operations as classes to cleanup the code
- Version 0.3.1 (2015-05-27)
- Fix the "all" operation
- six_moves knows more modules
- urllib: add pathname2url, don't touch urllib2.parse_http_list()
- Version 0.3 (2015-05-27)
- First command line parameter can now be a filename
- Add "all", "basestring", "iterkeys", "six_moves", "stringio" and "urllib" operations
- Enhance the knownledge tables for modules (stdlib, third parties, applications)
- Ignore unparsable import lines when adding an import
- Version 0.2 (2015-05-12):
- First public release