Difference between revisions of "Python3"
(→OpenStack Libraries) |
(→Common Libraries (Oslo Projects)) |
||
Line 195: | Line 195: | ||
| [https://pypi.python.org/pypi/oslo.log oslo.log] || style="background-color: lightgreen;" | Yes || | | [https://pypi.python.org/pypi/oslo.log oslo.log] || style="background-color: lightgreen;" | Yes || | ||
|- | |- | ||
− | | [https://pypi.python.org/pypi/oslo.messaging oslo.messaging] || style="background-color: | + | | [https://pypi.python.org/pypi/oslo.messaging oslo.messaging] || style="background-color: orange;" | Yes, except of Qpid & AMQP drivers. py34 is not more voting because of [//bugs.launchpad.net/ubuntu/+source/python3.4/+bug/1367907 ubuntu still uses 3.4.0 which has a severe bug] || oslo.messaging 1.11.0 fully works on Python 3, except of Qpid and AMQP 1.0 transports which are Python 2 only. The py34 gate is voting. |
|- | |- | ||
| [https://pypi.python.org/pypi/oslo.middleware oslo.middleware] || style="background-color: lightgreen;" | Yes || | | [https://pypi.python.org/pypi/oslo.middleware oslo.middleware] || style="background-color: lightgreen;" | Yes || |
Revision as of 13:09, 16 July 2015
This page tracks the progress of Python 3 effort porting for OpenStack.
Contents
- 1 Python 3
- 2 Python 2: Python 2.6 support dropped, Python 2.7 only
- 3 Port Python 2 code to Python 3
- 4 Python 3 Status of OpenStack projects
- 5 Status of Python 3 in Linux distributions
- 6 Reports at OpenStack Summits
- 7 Pycon Montreal 2014: Sprint Port OpenStack to Python 3
Python 3
Why should OpenStack move to Python 3 right now?
- Python 3 is usually seen as the new Python version which breaks compatibility and raises new Unicode issues. Python 3 is much more than that. It’s a new clean language which has a more consistent syntax. It has many new features, not less than 15 new modules. Python 3 is already well supported by major Linux distributions, whereas Python 2.7 reached its end-of-life. Slowly, some bugs cannot be fixed in Python 2.7 anymore and are only fixed in the latest Python 3 release. Python 3 is now 5 years old and considered as a mature programming language.
Python 2: Python 2.6 support dropped, Python 2.7 only
OpenStack Liberty targets Python 2.7 and 3.4.
Python 2.6 support is being dropped in OpenStack since OpenStack Juno for servers. Python 2.6 support is currently kept in Oslo libraries and clients. See juno-cross-project-future-of-python etherpad.
Python 3.3 support is being dropped since OpenStack Liberty.
Port Python 2 code to Python 3
OpenStack project chose to use the same code base for Python 2 and Python 3. The Six: Python 2 and 3 Compatibility Library helps to write code working on both versions. OpenStack supported Python 2.6 for RHEL up to Juno, but not Python 2.5 and older. Debian Stable provides Python 3 but only Python 3.2, so u'unicode' syntax should be avoided (use six.u('unicode') instead).
sixer tool
The sixer tool helps to replace most basic patterns to add Python 3 compatibility and it respects OpenStack coding style.
Common patterns
- Replace dict.iteritems() with dict.items()
- Replace dict.itervalues() with dict.values()
- Replace "for key in dict.iterkeys()" with "for key in dict"
- Replace iterator.next() with next(iterator)
- Replace basestring with six.string_types
- Replace unicode with six.text_type
- Replace (str, unicode) with six.string_types
- Replace (int, long) with six.integer_types
- Replace text.encode('hex') with base64.b64encode(text) which requires to encode (Unicode) text to UTF-8 on Python 3
if six.PY3: text = text.encode('utf-8') text_b64 = base64.b64encode(text)
- Replace raw.decode('hex') with base64.b64decode(raw). The output may be decoded from UTF-8 to get back text (Unicode) on Python 3.
text = base64.b64decode(raw) if six.PY3: text = text.decode('utf-8')
Note: Replacing dict.iteritems() with six.iteritems(dict) was preferred in the past, but there was a discussion suggesting to avoid six for this.
bytes.decode and unicode.encode
Python has a notion of "default encoding": sys.getdefaultencoding(). On Python 2, the default encoding is ASCII, whereas it is UTF-8 on Python 3.
Don't write data.decode()
or text.encode()
without parameter, because you will use a different encoding on Python 2 and Python 3.
Use an explicit encoding instead. Example: data.decode('utf-8')
or text.encode('utf-8')
. The right encoding depends on the use case, but UTF-8 is usually a good candidate (it is a superset of ASCII).
safe_decode
Olso Incubator has a function safe_decode() which can be used to decode a bytes string and pass text strings unchanged.
The default encoding is sys.stdin.encoding or sys.getdefaultencoding()
:
- Python 3: the locale encoding, or UTF-8 if sys.stdin is "mocked" (io.StringIO instance)
- Python 2: the locale encoding, or ASCII if stdin is not a TTY or if sys.stdin is "mocked" (StringIO.StringIO instance)
It's safer to explicit the encoding to not rely on the locale encoding and have the same behaviour even if sys.stdin is "mocked".
Safe usage:
-
safe_decode(data, 'utf-8')
: decode bytes from UTF-8 or returns data unchanged if it's already a text string
Unsafe usage:
-
safe_decode(data)
By default, the decoder is strict. You can specify a different error handler using the optional errors
parameter. Example: safe_decode(b'[\xff]', 'ascii', 'ignore') returns '[]'.
safe_encode
Olso Incubator has a function safe_encode() which can be used to encode a string. Its usage is tricky and you should understand how it works and which encodings are used.
-
safe_encode(text)
encodes text to the output encoding -
safe_encode(bytes)
may decode the string and then reencode to a different encoding if input and output encodings are different
The default input encoding (incomding
parameter) is sys.stdin.encoding or sys.getdefaultencoding()
:
- Python 3: the locale encoding, or UTF-8 if sys.stdin is "mocked" (io.StringIO instance)
- Python 2: the locale encoding, or ASCII if stdin is not a TTY or if sys.stdin is "mocked" (StringIO.StringIO instance)
The default output encoding (encoding
parameter) is UTF-8.
It's safer to explicit the input encoding to not rely on the locale encoding and have the same behaviour even if sys.stdin is "mocked".
Safe usage:
-
safe_encode(data, incoming='utf-8')
: encode text to UTF-8 or returns data unchanged if it's already a bytes string (since the input and output encoding are UTF-8)
Unsafe usage:
-
safe_encode(data)
Example:
-
safe_encode(b'\xe9', incoming='latin-1')
returnsb'\xc3\xa9'
.
By default, the encoder and the decoder are strict. You can specify a different error handler using the optional errors
parameter. Example: safe_encode(b'[\xff]', incoming='ascii', errors='ignore')
returns b'[]'
.
logging module and format exceptions
On Python 2, the logging module accepts bytes and text strings. On Python 3, it only accepts text strings. For example, logging.error(b'hello') logs b'hello'
instead of 'hello'
.
There is no clear rule for format exceptions yet. There are different choices depending on the project:
-
str(exc)
: native string, so use bytes on Python 2 -
six.text_type(exc)
: always use Unicode. It may raise unicode error depending on the exception, be careful. Example of such error in python 2:unicode(Exception("nonascii:\xe9"))
. -
six.u(str(exc))
: unsafe on Python 2 if str(exc) contains non-ASCII bytes, ex:unicode(str(Exception("\xff")))
-
LOG.exception(_LE("... %(exc)s ..."), {"exc": exc, ...})
Since logging functions expect text strings on Python 3, logged exceptions should be formatted using str(exc)
. Example: LOG.debug(str(exc))
.
HTTP
The HTTP protocol is based on bytes:
- HTTP body contains bytes. For example, use io.BytesIO for a stream storing an HTTP body.
- HTTPConnection.getresponse().read() returns bytes (in Python 3, str which is bytes in Python 2)
- On Python 3, the http.client accepts text for HTTP headers: keys are encoded to ASCII and values to ISO 8859-1 (which is only a small subset of the Unicode charset)
- It looks like Swift encodes internally HTTP headers to UTF-8 (directly using the UTF-8 encoding, not using a MIME encoding like =?UTF-8?Q?...?=. See the HTTP [RFC 2047 http://www.ietf.org/rfc/rfc2047.txt] and HTTP header should use what character encoding?
References to port Python 2 code to Python 3
- Porting to Python 3 Book by Lennart Regebro, especially the Language differences and workarounds.
- HOWTO: Porting Python 2 Code to Python 3 by Brett Cannon
- Porting Python Code to 3.x
- python-incompatibility: Demonstrates incompatibilities between Python versions.
Common pitfalls
What is a string ?
You should definitely not talk about "strings" in your commit logs/reviews. In Python 2, a 'string' is bytes; in Python 3, it's a Unicode text string. The following code snippet may help in understanding the difference:
Python 2:
>>> type('foo') <type 'str'> >>> type(u'foo') <type 'unicode'> >>> type(b'foo') <type 'str'> >>> isinstance('foo', six.text_type) False >>> isinstance(u'foo', six.text_type) True >>> bytes is str True >>> b'foo'[0] 'f'
Python 3:
>>> type('foo') <class 'str'> >>> type(u'foo') <class 'str'> >>> type(b'foo') <class 'bytes'> >>> isinstance('foo', six.text_type) True >>> isinstance(b'foo', six.text_type) False >>> bytes is str False >>> b'foo'[0] 102
tox/testr error: db type could not be determined
The "db type could not be determined" error comes from .testrepository/times.dbm used by testr.
Workaround: "rm -rf .testrepository/" and then run "tox -e py34" before running "tox -e py27". You only have to do this once. The problem only occurs with "tox -e py34" when .testrepository/ was created by Python 2.
Python 3 Status of OpenStack projects
Common Libraries (Oslo Projects)
For the list of Common Libraries, see http://git.openstack.org/cgit/openstack/governance/tree/reference/programs.yaml#n160
Project | Python 3 compatibility | Comment |
---|---|---|
cliff | Yes | |
oslo.concurrency | Yes | |
oslo-incubator | Yes | py34 gate is voting |
oslo.config | Yes | |
oslo.context | Yes | |
oslo.db | Yes |
PyMySQL driver is now used by default for MySQL. setup.cfg contains the Python 3 classifier. |
oslo.i18n | Yes | |
oslo.log | Yes | |
oslo.messaging | Yes, except of Qpid & AMQP drivers. py34 is not more voting because of ubuntu still uses 3.4.0 which has a severe bug | oslo.messaging 1.11.0 fully works on Python 3, except of Qpid and AMQP 1.0 transports which are Python 2 only. The py34 gate is voting. |
oslo.middleware | Yes | |
oslo.rootwrap | Yes | |
oslo.serialization | Yes | |
oslosphinx | ? | The project only contains two short .py files, it looks to be Python 3 compatible. Is Sphinx Python 3 compatible? |
oslotest | Yes | |
oslo.versionedobjects | Yes | |
oslo.vmware | Yes | Supports Python 3 since oslo.vmware 0.13.0 |
oslo.utils | Yes | |
pylockfile | Yes | |
stevedore | Yes | |
taskflow | Yes |
Development tools
Project | Python 3 compatibility | Comment |
---|---|---|
cookiecutter | yes | |
hacking | yes | py33 gate is not voting |
pbr | yes | |
stackforge/python-jenkins | yes | py33 gate is voting |
openstack-infra/jenkins-job-builder | partial | https://review.openstack.org/172238 |
OpenStack clients
Project | Python 3 compatibility | CI tests running? | Python 3 classifiers ? | Blocked by | Comment |
---|---|---|---|---|---|
keystonemiddleware | Yes, but requires patched python-memcached | No | Yes | python-memcached | keystonemiddleware 1.6.1 supports Python 3, but it is still blocked by python-memcached which has pending pull request for Python 3. |
python-barbicanclient | Yes | Voting | On PyPI | ||
python-ceilometerclient | Yes | Voting | On PyPI | ||
python-cinderclient | Yes | Voting | On PyPI | ||
python-ganttclient | ? | ? | ? | ? | |
python-glanceclient | Yes | Voting | On PyPI | ||
python-heatclient | Yes | Voting | On PyPI | ||
python-ironicclient | Yes | Voting | On PyPI | ||
python-keystoneclient | Yes | Voting | On PyPI | ||
python-marconiclient | Yes | Voting | Yes | ||
python-melangeclient | ? | ? | ? | ||
python-novaclient | Yes | Voting | On PyPII | ||
python-neutronclient | Yes | Voting | Yes | ||
python-openstackclient | OK | Voting | Yes | As of 0.9 | |
python-savannaaclient | In progress | Non-voting | Yes | python-savannaclient: enable the py33 gates abandonned: "We haven't enough tests to ensure that savanna client works correctly on py33, so, it's kind of premature step. We already have py33 and pypy jobs in experimental pipeline." | |
python-saharaclient | OK | Voting | On PyP | ||
python-swiftclient | Yes | Voting | On PyPI | ||
python-tuskarclient | Yes | Voting | On PyPI | ||
python-troveclient | Yes | Voting | On PyPI |
OpenStack Libraries
Project | Python 3 compatibility | CI tests running? | Python 3 classifiers ? | Comment | |
---|---|---|---|---|---|
glance_store | Yes in master | voting | Yes in git |
Patches: py3 topic glance_store 0.6.0 is not compatible yet with Python 3. A new release is needed. | |
os-brick | Yes in master | voting | Yes | ||
sqlalchemy-migrate | Yes | voting | Yes | ||
taskflow | Yes | voting | Yes |
Dependencies
There are two ways to express dependencies that should differ between Python 2.x and 3.x. We currently support using multiple requirements files, and will shortly be supporting and recommending the use of environment markers. Recent releases of all the tools in our ecosystem are needed for environment markers.
requirements-py3.txt
This approach generates a different requirements list depending on what Python version is running when the egg info is created (which goes into wheels and sdists). As a consequence this can't work with tox, publishing sdists to PyPI, or wheels. It is however useful for anything installing from git. To use it, create two requirements files:
- requirements-py2.txt: all dependencies for Python 2 (not only dependencies specific to Python 2)
- requirements-py3.txt: all dependencies for Python 3 (not only dependencies specific to Python 3)
- (same for test-requirements.txt)
You have to edit tox.ini to specify the right requirements file. Extract of a tox.ini file:
... [testenv:py33] deps = -r{toxinidir}/requirements-py3.txt -r{toxinidir}/test-requirements-py3.txt ...
Environment markers
Environment markers provide a mini-language to express when a dependency is relevant. We hope the next release of pbr will support them. Recent pip, setuptools and wheel versions do support them, but until pbr exports the requirements metadata with them intact and structured correctly for setuptools, we can't use them anywhere.
- PEP 0345 -- Metadata for Python Software Packages 1.2 (accepted): Environment markers
- PEP 0426 -- Metadata for Python Software Packages 2.0 (draft): Environment markers
When placed in a requirements.txt file, the markers are interpreted directly by pip in `pip install -r requirements.txt`, and indirectly via setuptools when installing an sdist or wheel (including `pip install .`. For instance:
six futures; python_version < '3.2'
See also:
- oslo.db: Refactor deps to use extras and env markers (require pip 7, not released yet)
- pip: Fix issue #1433: parse requirements in markers #1472
- setuptools: pkg_resources doesn't understand environment markers: pkg_resources.parse_requirements() raises ValueError
- pbr: Teach pbr to read extras and env markers, Handle PEP426 markers (abandoned)
- wheel: wheel should support PEP 426 environment markers (closed), wheel supports environment markers in extra requirements
- tox: tox must create the source distribution with the Python of the virtual environment, Issue #236: subcommand_test() rebuilds sdist with venv python (declined)
Oslo Messaging issue:
- futures is not needed on Python 3, since concurrent.futures is now part of the Pyhon stdlib since Python 3.2
- futures was added to requirements-py3.txt because tox creates the source tarball using Python 2 which reads requirements.txt
- The correct fix would be to use environment markers on futures
Dependencies status
Porting status for global-requirement.txt.
Project | Python 3 compatibility | CI tests running? | Python 3 classifiers ? | Blocked by | Comment |
---|---|---|---|---|---|
boto | Yes | N/A | Yes | See https://github.com/boto/boto3 (experimental) <- This seems dead, and https://github.com/boto/boto works with Python 3.x (since 2.32). | |
django-compressor | Yes | N/A | Yes | Requirements upgraded: https://review.openstack.org/94357 | |
tablib | Yes | N/A | Yes | setup.py installs tablib.packages.markup which is not compatible with Python 2. setup.py displays a warning on compiling the bytecode of markup.py.
tablib is needed by cliff-tablib, itself needed by python-neutronclient | |
django-openstack-auth | Yes | N/A | Yes |
As of 1.1.6 | |
dnspython | Yes | N/A | Yes | Must use the Python 3 version, see https://github.com/rthalley/dnspython/issues/60 | |
ecdsa | Yes | N/A | Yes | Py3 support merge before the 0.10 release (see https://github.com/warner/python-ecdsa/commits/master) | |
eventlet | Yes | Yes | Yes | eventlet 0.17.3 now fully support Python 3 | |
jsonrpclib | No | N/A | No | The project seems dead :( | |
libvirt-python | Yes | N/A | Yes | ||
MySQL-Python | No, but mysqlclient or PyMySQL are compatible | N/A | No |
Patches: MySQL-Python: 2 pending pull requests for Python 3. INADA Naoki, the maintainer of PyMySQL, wrote mysqlclient: fork of MySQL-Python using libmysqlclient.so which is Python 3 compatible. He recommends to use mysqlclient instead of MySQL-python even on Python 2. mysqlclient fixes some bugs, build issues and it support Python 3. For example: support MariaDB's libmysqlclient.so, support microsecond in TIME column. PyMySQL is compatible with Python 3: see PyMySQL evaluation discussion to eventually replace mysql-python with PyMySQL in OpenStack. | |
netifaces | Yes | N/A | Yes | Patch sent by Victor Stinner (in private): netifaces_python3.patch, Debian has patches too. Python 3 support as of 0.10.4. Pushed to requirements: https://review.openstack.org/94358 . | |
nose-exclude | No | No | No | https://bitbucket.org/kgrandis/nose-exclude/issue/10/test-failures-with-python-3 | |
nosehtmloutput | No | No | No |
|
|
nosexcover | No | N/A | On PyPI | Python 3 support since 1.0.9 | |
openstack.nose-plugin | No | No | No | ||
pam | No for pam, Yes for simplepam | NA | No | The fork simplepam works on Python 2 and 3 | |
paramiko | Yes | N/A | On PyPI | Requirements upgraded: https://review.openstack.org/#/c/81132/ | |
paste | Yes | N/A | Yes | Compatible with Python 3 since Paste 2.0 | |
pycadf | Yes | Yes | Yes | ||
python-ldap | No | No | No | The project seems dead. See ldap3 which is Python 3 compatible (license: LGPL, one of the optional deps is BSD-4-Clause). | |
python-memcached | No, but there is a pending pull request | No | No |
python-memcached 1.54 includes many fixes for Python 3, but it doesn't work on Python 3 yet. Pull request: Port memcache to Python 3 #67. Julien Danjou ported pymemcache to Python 3, another memcached client, he suggests to use this one instead | |
qpid-python | No | No | No | Required if using oslo.messaging's qpid backend. That is the old pure python amqp 0-10 client library. That only speaks 0-10 and works with qpidd broker. It is used by the impl_qpid.py driver in oslo.messaging. That client is legacy - it isn't being ported to use AMQP 1.0 | |
pyngus | No | No | No |
pyngus is required if using oslo.messaging's AMQP 1.0 driver. pyngus is a wrapper for proton and proton has not been ported to python 3 yet: see Proton issue #490. Proton is a C library with various bindings in other languages. The language bindings are auto generated via the SWIG tool, plus a the python wrapper bits. All the python stuff is found under proton-c/bindings/python in the git tree. The first bit of work is to refactor the SWIG file cproton.i to work for both Python 2 and 3. | |
rtslib-fb | No | No | No | ||
Routes | Yes using 2to3 | Yes | Yes | Routes doesn't work on Python 3 when building wheel packages using Python 2, see: Port Routes to Python 3 (patch merged, not release yet) | |
sphinxcontrib-docbookrestapi | Yes | Yes | In the Git repo, not on PyPI | ||
sphinxcontrib-httpdomain | Yes | N/A | No | ||
sphinxcontrib-pecanwsme | No | No | No | ||
thrift | No | No | No | ||
websockify | No | No | No |
OpenStack applications
Project | Python 3 compatibility | py34 gate | Comments |
---|---|---|---|
ceilometer | work in progress | voting |
Victor Stinner is working on porting Ceilometer to Python 3. Patches: |
cinder | work in progress | voting |
cinder-python3 blueprint (written by Victor Stinner) has been accepted for Liberty. Patches: |
glance | work in progress | voting |
Victor Stinner is working on porting Glance to Python3. Patches: |
gnocchi | Yes | Yes | |
heat | work in progress | non voting |
Python34 Support spec (by Sirushti Murugesan) accepted for Liberty. Patches: bp/heat-python34-support topic. |
horizon | work in progress | No |
George Peristerakis wrote Make Horizon python3.4 compatible. Patches:
|
ironic | Yes | Yes |
Python 3.4 unit tests are now being run for openstack/ironic. The unit tests are a voting job. Thanks to Victor Sergeyev for all of his work to update the Ironic code to make it pass the unit tests using Python 3.4: Run tests in py34 environment |
keystone | work in progress | voting |
The spec Add spec for python-3 compatibility (by Morgan Fainberg) was accepted for Liberty. See also the blueprint python3 started by Dolph Mathews on 2014-07-22; David Stanek is working on it. Patches: bp/python3 topic. pysaml2 dependency has been ported to Python 3, a release is still needed. Aslo blocked by ldappool and [python-ldap https://pypi.python.org/pypi/python-ldap]? python-ldap may be replaced with ldap3. |
neutron | work in progress | voting |
Porting to Python 3 spec (by Cyril Roelandt) accepted for Liberty, port in progress. Patches: |
nova | work in progress | voting |
Adding Python 3.4 support to Nova spec (by Victor Stinner) accepted for Liberty. Port in progress. Patches: See also Py3.4 Compatibility in Liberty nova priorities tracking. |
sahara | work in progress | voting | |
swift | work in progress | non voting (need to fix tox -e py34 |
swift now depends on six. Patches: Dependencies:
|
Functional tests
Doug Hellmann wrote a cross-project specification to run integration tests on Python 3: Enabling Python 3 for Application Integration Tests.
Patch for DevStack: Enable optional Python 3 support.
Status of Python 3 in Linux distributions
- ArchLinux already switched to Python 3 by default in 2011
- Ubuntu wants to remove Python 2 from the default installation: see Ubuntu Plans For Python 3 By Default For Ubuntu 16.04 LTS
- Fedora schedules the switch in Fedora 23 (october 2015): Python 3 as the Default Implementation
- RHEL: Python 3.3 and Python 3.4 are available on RHEL6 and RHEL7 using SCL.
- CentOS: Python 3.3 and Python 3.4 are available on CentOS 6 and 7 using SCL (no Red Hat subscription needed, CentOS has its own flavor of SCL)
- In Debian, the plan is to deprecate Python 2 in Stretch (aka: Debian 9, the next Stable Debian after Jessie) and to completely remove Python 2 for the Buster release of Debian (aka: Debian 10, to be release in approximatively 2019).
Reports at OpenStack Summits
- Liberty Summit
- Cross-project session on enabling app integration testing: https://etherpad.openstack.org/p/liberty-cross-project-python3
- Kilo Summit
- Doug Hellmann: "Moving our applications to Python 3" cross-project session
- Victor Stinner: "Port nova to Python 3", https://etherpad.openstack.org/p/liberty-nova-summit-ideas
- Juno summit notes: https://etherpad.openstack.org/p/juno-cross-project-future-of-python (Oslo) and https://etherpad.openstack.org/p/juno_swift_python3 (Swift)
- Icehouse summit notes: https://etherpad.openstack.org/p/IcehousePypyPy3
- Havana summit notes: https://etherpad.openstack.org/p/havana-python3
Pycon Montreal 2014: Sprint Port OpenStack to Python 3
Enovance organized a sprint to Port OpenStack to Python 3 during 4 days: between April, 14 (Monday) and April, 17 (Thursday) 2014. See the page Python3/SprintPycon2014.