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
basestringwithsix.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() + list2withlist(dict.keys()) + list2 - same for
dict.values() + list2anddict.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.ifilterwithsix.moves.filter, addimport six - similar change for
ifilterfalse(),imap(),izip()andizip_longest()of theitertoolsmodule
- replace
long:- replace
123Lwith123(decimal) - replace
0xABlwith0xAB(hexadecimal) - replace
0600Lwith0o600(octal) - replace
(int, long)withsix.integer_types - replace
long(1)with1
- replace
next:- replace
iter.next()withnext(iter)
- replace
print:- Replace
print msgwithprint(msg) - Replace
print msg,withprint(msg, end=' ')and addfrom __future__ import print_functionimport - Replace
printwithprint()and addfrom __future__ import print_functionimport - Replace
print >>sys.stderr, "hello"'withprint("hello", file=sys.stderr)and addfrom __future__ import print_functionimport
- Replace
raise:- replace
raise exc[0], exc[1], exc[2]withsix.reraise(*exc), addimport six - replace
raise exc_type, exc_value, exc_tbwithsix.reraise(exc_type, exc_value, exc_tb), addimport six - replace
raise exc, msgwithraise exc(msg), addimport six
- replace
six_moves:- replace Python 2 imports with imports from
six.moves, addimport six. Python 2 modules:BaseHTTPServerConfigParserCookieHTMLParserQueueSimpleHTTPServerSimpleXMLRPCServer__builtin__cPicklecookielibhtmlentitydefshttplibreprxmlrpclib
- 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.xxxis 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.StringIOwithsix.StringIO, addimport six - replace
cStringIO.StringIOwithmoves.cStringIO, addfrom six import moves - replace
from StringIO import StringIOwithfrom six import StringIO - replace
from cStringIO import StringIOwithfrom six.moves import cStringIO as StringIO - later you may have to replace it with
six.BytesIO(orio.BytesIOif you don't support Python 2.6) when bytes are expected on Python 3
- replace
unicode:- replace
unicodewithsix.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)
dict0now also matches any integer index, not only0longnow also replaceslong(1)with1
- Version 1.5 (2016-05-30)
- six_moves: replace
ConfigParser.ConfigParserwithconfigparser.ConfigParser, not withconfigparser.configparser - remove the
octaloperation, 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
stringoperation. For example, replacestring.upper("abc")with"abc".upper(). printnow also replacesprint >>sys.stderr, "hello"'withprint("hello", file=sys.stderr)
- add
- Version 1.2 (2015-11-26)
- add
octaloperation: replace0123with0o123 - add
printoperation: replaceprint msgwithprint(msg), handle also other print statements (but not all of them yet) - add
has_keyoperation: replacedict.has_key(key)withkey in dict longnow also handles octal and hexadecimal numbers. For example,0xffLis replaced with0xff, and0600lis replace with0o600.exceptnow handles also exception with dots (ex:except select.error, exc:)iterkeysnow replacesfor key in dict.iterkeys():withfor key in dict:to avoid the usage of six.- Enhance
exceptandraiseregex to match also expressions without spaces after commas
- add
- Version 1.1 (2015-10-22)
- add
--third-partycommand 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
--writeto really modify files inplace. longoperation now also replaces(int, long)withsix.integer_typesitertoolsnow also replacesifilterfalse(),izip()andizip_longest()of theitertoolsmodulesix_movesnow also replacesunichr(ch)withsix.unichr(ch)- command line: it's now possible to exclude an operation using
-prefix. For example,all,-iteritemsapplies 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
unicodeoperation 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
longalso replaces1l(lower case L suffix for long numbers)
- Version 0.7 (2015-09-29)
- Add new
dict0,dict_addandexceptoperations - 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_movesnow also patchesreduce()andreload(). For example,reduce()is replaced withsix.moves.reduce().six_movesnow also patchesmock.patch(). For example,with mock.patch('__builtin__.open'): ...is replaced withwith mock.patch('six.moves.builtin.open'): ...urllibnow also replacesfrom ... import ...imports. For example,from urllib import quoteis 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
stringiooperation 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