Python3
此页面跟踪 OpenStack Python 3 移植工作的进展情况。
目录
- 1 IRC: #openstack-dev
- 2 当前状态
- 3 Python 3
- 4 OpenStack 项目的 Python 3 状态
- 5 Python 2:已放弃 Python 2.6 支持,仅支持 Python 2.7
- 6 将 Python 2 代码移植到 Python 3
- 6.1 开始之前
- 6.2 sixer 工具
- 6.3 常见模式
- 6.4 序列化:base64、JSON 等
- 6.5 contextlib.nested
- 6.6 oslo_utils.encodeutils.to_utf8
- 6.7 bytes.decode 和 unicode.encode
- 6.8 safe_decode
- 6.9 safe_encode
- 6.10 logging 模块和格式化异常
- 6.11 HTTP
- 6.12 将 Python 2 代码移植到 Python 3 的参考资料
- 6.13 常见陷阱
- 6.14 在 DevStack 中启用 Python 3
- 6.15 功能和集成测试
- 6.16 Python 3.5
- 6.17 Python 3.6 状态
- 7 Linux 发行版中 Python 3 的状态
- 8 依赖项中 Python 2 支持被放弃的状态
- 9 进度报告、会议和冲刺
- 10 文章
- 11 Pycon Montreal 2014:冲刺将 OpenStack 移植到 Python 3
IRC: #openstack-dev
加入 Freenode 网络的 #openstack-dev IRC 频道讨论 Python 3。
当前状态
自 Ussuri 以来,OpenStack 除 Swift 和 Storlets 之外均为 Python3。所有其他项目的 Python2.7 支持和测试已被移除。有关更多详细信息,请参阅 Drop py2.7 社区目标
| 发布 | Python 版本 | 笔记 |
|---|---|---|
| V | python3.6 python3.7 python3.8 [1] |
|
| Ussuri (放弃 Python 2.7) | python3.6 python3.7 [2] |
在 Ussuri 中,OpenStack 除 Swift 和 Storlets 之外均为 python3-only。请参阅 放弃 Python 2.7 目标 |
| Train | python2.7 python3.6 python3.7 [3] |
Train 是需要 python2.7 测试的最后一个版本。 |
Python 3
为什么现在 OpenStack 要迁移到 Python 3?
- Python 3 通常被认为是新的 Python 版本,它破坏了兼容性并引发了新的 Unicode 问题。Python 3 不仅仅是这样。它是一种新的、干净的语言,具有更一致的语法。它具有许多新功能,多达 15 个新模块。Python 3 已经得到主要 Linux 发行版的良好支持,而 Python 2.7 已经达到其生命周期结束。慢慢地,一些错误无法在 Python 2.7 中修复,只能在最新的 Python 3 版本中修复。Python 3 已经发布 5 年了,被认为是一种成熟的编程语言。
OpenStack 项目的 Python 3 状态
通用库 (Oslo 项目)
请参阅 programs.yaml 以获取通用库的列表。
| 项目 | 仅支持 Python 3 (Ussuri 及以后) | Python 3 兼容性 | 备注 |
|---|---|---|---|
| automaton | Yes | Yes | |
| castellan | Yes | Yes | |
| cliff | Yes | Yes | |
| debtcollector | Yes | Yes | |
| futurist | Yes | Yes | |
| oslo.cache | Yes | Yes | |
| oslo.concurrency | Yes | Yes | |
| oslo.config | Yes | Yes | |
| oslo.context | Yes | Yes | |
| oslo.db | Yes | Yes | |
| oslo.i18n | Yes | Yes | |
| oslo.log | Yes | Yes | |
| oslo.messaging | Yes | Yes | |
| oslo.middleware | Yes | Yes | |
| oslo.policy | Yes | Yes | |
| oslo.privsep | Yes | Yes | |
| oslo.reports | Yes | Yes | |
| oslo.rootwrap | Yes | Yes | |
| oslo.serialization | Yes | Yes | |
| oslo.service | Yes | Yes | |
| oslotest | Yes | Yes | |
| oslo.versionedobjects | Yes | Yes | |
| oslo.vmware | Yes | Yes | |
| oslo.utils | Yes | Yes | |
| pylockfile | 不适用 | Yes | 项目已弃用。 |
| stevedore | Yes | Yes | |
| taskflow | Yes | Yes | |
| tooz | Yes | Yes |
开发工具
| 项目 | 仅支持 Python 3 (Ussuri 及以后) | Python 3 兼容性 | 备注 |
|---|---|---|---|
| cookiecutter | Yes | 是 | |
| hacking | Yes | 是 | |
| pbr | 否 | 是 | pbr 没有上限,因此我们需要继续支持 py2.7 代码以确保安全。 |
| stackforge/python-jenkins | 否 | 是 | |
| openstack-infra/jenkins-job-builder | 否 | 部分 | https://review.openstack.org/172238 |
OpenStack 客户端
| 项目 | 仅支持 Python 3 (Ussuri 及以后) | Python 3 兼容性 | CI 测试正在运行? | Python 3 分类器? | 被以下问题阻塞 | 备注 |
|---|---|---|---|---|---|---|
| keystonemiddleware | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-barbicanclient | 否 | Yes | 投票 | 在 PyPI 上 | https://review.opendev.org/#/c/699096/ | |
| python-ceilometerclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-cinderclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-fuelclient | 不适用 | Yes | voting | 在 PyPI 上 | 该项目不再维护。 | |
| python-glanceclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-heatclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-ironicclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-keystoneclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-manilaclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-zaqarclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-masakariiclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-monascaclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-novaclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-neutronclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-octaviaclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-openstackclient | Yes | Yes | 投票 | 在 PyPI 上 | 截至 0.9 | |
| python-saharaclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-searchlightclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-senlinclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-swiftclient | 否 | Yes | 投票 | 在 PyPI 上 | Swift 将继续支持 python2。 | |
| python-tuskarclient | 不适用 | Yes | 投票 | 在 PyPI 上 | 该项目不再维护。 | |
| python-troveclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-watcherclient | Yes | Yes | 投票 | 在 PyPI 上 | ||
| python-designateclient | Yes | Yes | 投票 | 在 PyPI 上 |
OpenStack 库
| 项目 | 仅支持 Python 3 (Ussuri 及以后) | Python 3 兼容性 | CI 测试正在运行? | Python 3 分类器? | 备注 |
|---|---|---|---|---|---|
| blazar-nova | Yes | Yes | voting | Yes | |
| ceilometermiddleware | Yes | Yes | voting | Yes | |
| django_openstack_auth | 不适用 | Yes | voting | Yes |
代码已合并到 openstack/horizon 中。 |
| glance_store | Yes | Yes | voting | Yes | |
| heat-translator | Yes | Yes | voting | Yes | |
| ironic-lib | Yes | Yes | voting | Yes | |
| keystoneauth | Yes | Yes | voting | Yes | |
| keystonemiddleware | Yes | Yes | voting | Yes | |
| ldappool | Yes | Yes | voting | Yes | |
| monasca-statsd | Yes | Yes | voting | Yes | |
| mistral-lib | Yes | Yes | voting | Yes | |
| neutron-lib | Yes | Yes | voting | Yes | |
| octavia-lib | Yes | Yes | voting | Yes | |
| os-brick | Yes | Yes | voting | Yes | |
| os-client-config | Yes | Yes | voting | Yes | |
| os-traits | Yes | Yes | voting | Yes | |
| os-vif | Yes | Yes | voting | Yes | |
| os-win | Yes | Yes | voting | Yes | |
| osc-lib | Yes | Yes | voting | Yes | |
| osc-placement | Yes | Yes | voting | Yes | |
| pycadf | Yes | Yes | voting | Yes | |
| shade | 否 | Yes | voting | Yes | shade 处于扩展维护状态。 |
| sqlalchemy-migrate | 不适用 | Yes | voting | Yes | 该项目不在 OpenStack 的维护范围内 |
| sushy | Yes | Yes | voting | Yes | |
| taskflow | Yes | Yes | voting | Yes | |
| tosca-parser | Yes | Yes | voting | Yes |
依赖项:环境标记
示例:不为 Python 3.3 及更高版本安装“futures”依赖项
futures; python_version < '3.2'
OpenStack 应用程序 (tc:approved-release)
OpenStack 应用程序 经 OpenStack 技术委员会批准。
| 项目 | 仅支持 Python 3 (Ussuri 及以后) | 单元测试通过 Python 3 | py35 gate | 功能测试 | 评论 |
|---|---|---|---|---|---|
| ceilometer | Yes | Yes | voting | ||
| cinder | Yes | Yes | voting | integrated-gate-py35 |
cinder-python3 蓝图(由 Victor Stinner 编写)已接受用于 Liberty。补丁:bp/cinder-python3 主题。注意:提交消息必须使用“Partial-Implements: blueprint cinder-python3”才能链接到蓝图。Kendall Nelson、Ivan Kolodyazhny (核心) 和 Eric Harney (核心) 偏好这种语法:请参阅 COMMIT_MSG。 |
| designate | Yes | Yes | voting | designate-bind9-py36 designate-bind9-py35 | 依赖于 oslo.service WSGI 代码,该代码在使用 SSL 的情况下无法在 Python 3 下工作。功能 tempest 测试在这两个作业上运行。[4] |
| glance | Yes | Yes | voting | integrated-gate-py35 | 依赖于 oslo.service WSGI 代码,该代码无法在 Python 3 下工作。[5] Victor Stinner 正在将 Glance 移植到 Python3。补丁:Glance (主题: py3) 的补丁。 |
| heat | Yes | Yes | voting | heat-functional-convg-mysql-lbaasv2-py35 |
Sirushti Murugesan 编写并实施了规范 Python34 支持(已接受用于 Liberty)。Mitaka 版本将完全支持 Python 3。Sirushti Murugesan 完成了几乎所有的工作! |
| horizon | Yes | Yes | voting | horizon-openstack-tox-python3-django111,horizon-integration-tests, horizon-dsvm-tempest-plugin |
George Peristerakis 编写了 使 Horizon python3.4 兼容 于 2015 年 5 月,该蓝图已获得批准。补丁:bp/porting-python3 主题。 |
| ironic | Yes | Yes | voting | ironic-tempest-dsvm-ipa-partition-pxe_ipmitool-tinyipa-python3 |
Python 3.4 单元测试现在正在 openstack/ironic 上运行。单元测试是一个投票作业。 感谢 Victor Sergeyev 完成所有工作,更新 Ironic 代码以使其通过使用 Python 3.4 的单元测试:在 py34 环境中运行测试 |
| keystone | Yes | Yes | voting | integrated-gate-py35 |
转向 pyldap 和新的 ldappool 是 Newton 中解决的主要障碍。感谢 Keystone 团队在 Newton 中完成所有工作。 |
| neutron | Yes | Yes | voting | integrated-gate-py35 |
移植到 Python 3 规范(由 Cyril Roelandt 编写)已接受用于 Liberty,移植正在进行中。蓝图 neutron-python3 的补丁 |
| neutron-lbaas | 不适用 | Yes | voting | neutron-lbaasv2-dsvm-py3x-api 和 neutron-lbaasv2-dsvm-py3x-api-namespace | 该项目不再维护。 |
| neutron-fwaas | Yes | Yes | voting | neutron-fwaas-networking-midonet-cross-py35 (非投票) | |
| neutron-vpnaas | Yes | Yes | voting | ||
| nova | Yes | Yes | voting | integrated-gate-py35 |
2019-01-24 状态:单元测试全部运行并通过 Python 3 投票,通过使用 mox3 包。只有 3 个单元测试文件仍在 mox3 中(nova/tests/unit/cells/test_cells_messaging.py、nova/|tests/unit/network/test_neutronv2.py、nova/tests/unit/network/test_manager.py)。 我们建议贡献者不要花时间替换正在测试 cells v1 和 nova-network(test_cells_messaging.py 和 test_manager.py)的文件中的 mox,因为两者都计划尽快删除。进度跟踪:https://blueprints.launchpad.net/nova/+spec/mox-removal-stein |
| sahara | Yes | Yes | voting | sahara-tests-scenario-py3 (实验) | 2018-02-23 状态:作业在 devstack 部署期间失败,因为 swift 未启动。其依赖项列表很小,像 keystone 这样的组件是可选的。这通过一个额外的依赖项部分解决了:https://review.openstack.org/#/c/544121/ 但这需要 a) devstack 中的支持(https://review.openstack.org/#/c/544383/ 中的临时支持) b) 至少另一个额外的依赖项,或者一种更通用的方法;即使在 devstack 中明确要求额外的依赖项,从 pip 安装的额外依赖项也会破坏依赖补丁的测试。 我们面临 pickle 库和 python 3 的问题,一旦解决,我们就可以尝试使 python 3 gate 投票。 |
| swift | 否 | Yes | voting | Swift 将继续支持 python2。 更新 (2016-06-27):master 分支目前处于软冻结状态,以便合并加密中间件 Python 3 错误:https://bugs.launchpad.net/swift/+bug/1614289 计划向 Swift 添加 Python 3 支持。补丁:带有主题 py3 的补丁 Python 3 单元测试需要 liberasurecode >= 1.0.9 和 PyEClib >= 1.0.9。要在 /usr 中安装 liberasurecode git clone https://bitbucket.org/tsg-/liberasurecode/ cd liberasurecode /autogen.sh && /configure --prefix=/usr && make && sudo make install liberasurecode >= 1.0.9 在 Ubuntu Precise、Ubuntu Trusty、Fedora 22、Fedora 23 和 CentoOS 7 中可用。 更新 2018-02-22:当前阻止器的列表:https://gist.github.com/tipabu/833b03a865dba96e9fa2230b82f5d075 更新 2018-03-06:当前阻止器的列表,附带进度说明:https://etherpad.openstack.org/p/Swift_py3 | |
| trove | Yes | Yes | voting | trove-devstack-base |
2019-01-06 状态:单元测试 - 1708 个测试,1707 个通过,1 个跳过。 集成测试基于 trove-devstack-base 作业。 2016-07-25 状态:1,155 / 2,014 (run_tests.py: 398; testr: 1,521; generate_examples: 95) 单元测试 (57%),TODO:859 个测试 2016-06-22 状态:839 (testtools) / 1,992 (run_tests.py: 398; testr: 1,499; generate_examples: 95) 单元测试 (42%),TODO:1,153 个测试 2018-02-22 状态:现在只有一个测试在黑名单中:guestagent.test_operating_system run_tests.py (proboscis) 失败:https://review.openstack.org/#/c/346905/1 Victor Stinner 提出了 trove-python3 蓝图 用于 Mitaka。 来自 Victor (2016/3/17):"我建议在峰会之前讨论 Python 3。例如,准备一个将 Trove 移植到 Python 3 的具体计划,列出技术问题,如 MySQL-Python 等。" |
其他 OpenStack 应用程序和项目
OpenStack 所有项目的列表:projects.yaml。
| 项目 | 仅支持 Python 3 (Ussuri 及以后) | 单元测试通过 Python 3 | py35 gate | 功能测试 | 评论 | |
|---|---|---|---|---|---|---|
| adjutant | Yes | Yes | voting | 部分* | (*) Adjutant 的单元测试包括针对 Adjutant API 使用 DRF 内部测试类的一套 API 测试。虽然不是真正的功能测试,但它们会启动一个内部 Web 服务器并处理来自 Adjutant 的真实工作负载,对我们接触到的外部 API 和服务(Keystone、Nova、Neutron 等)进行模拟。 这测试了 92% 的代码,因此很可能涵盖了大多数 py3 与 py2 的问题。 Tempest 测试也计划在以后进行。 | |
| aodh | Yes | Yes | voting | |||
| barbican | Yes | Yes | voting | 未指定 |
蓝图 barbican-py3。 | |
| blazar | Yes | Yes | voting | blazar-devstack-dsvm-py35 | ||
| cloudkitty | Yes | Yes | voting | cloudkitty-tempest-full-python3 | ||
| congress | Yes | Yes | 投票* | congress-devstack-py35-api-mysql |
(*) py35 支持需要对 antlr3 包进行微小修改,从而导致 Debian 打包困难 Random Stacker 编写了一个 support-python3 蓝图。补丁:搜索主题 bp/support-python3。 | |
| cyborg | Yes | 没有作业 | 没有作业 | |||
| designate | Yes | Yes | voting | designate-devstack-pdns4-py35(仅检查队列) |
Pradeep Kumar Singh 提出了 blueprint designate-py3,该蓝图已被 Liberty 接受。补丁:主题:bp/designate-py3。 | |
| ec2-api | Yes | Yes | voting | openstack-tox-py35 | ||
| freezer | Yes | Yes | voting | |||
| karbor | Yes | Yes | voting | |||
| kuryr | Yes | Yes | voting | openstack-tox-py35 | ||
| magnum | Yes | Yes | voting | (投票:magnum-functional-api) 且 (非投票:magnum-functional-k8s 且 magnum-functional-swarm-mode) | ||
| manila | Yes | Yes | voting | manila-tempest-minimal-dsvm-dummy | ||
| manila-ui | Yes | Yes | voting | horizon-openstack-tox-python3-django111 | ||
| masakari | Yes | Yes | voting | openstack-tox-py35 | ||
| mistral | Yes | Yes | voting | |||
| monasca-agent | Yes | Yes | voting | monasca-tempest-python3-influxdb | https://storyboard.openstack.org/#!/story/2000975 | |
| monasca-api | Yes | Yes | voting | monasca-tempest-python3-influxdb | https://storyboard.openstack.org/#!/story/2000975 | |
| monasca-log-api | Yes | Yes | voting | monascalog-python3-tempest | ||
| monasca-ui | Yes | Yes | voting | https://storyboard.openstack.org/#!/story/2000975 | ||
| murano | Yes | Yes | voting | |||
| murano-agent | Yes | Yes | voting | |||
| octavia | Yes | Yes | voting | octavia-tox-functional-py35 | ||
| panko | Yes | Yes | voting | panko-tox-py35-mysql 和 panko-tox-py35-postgresql | ||
| qinling | Yes | Yes | voting | |||
| rally | Yes | Yes | voting | rally-tox-functional-py3 和 rally-tox-self |
非常感谢 Andrey Kurilin 为此方向所做的许多工作 | |
| searchlight | Yes | Yes | voting | openstack-tox-py36 | ||
| senlin | Yes | Yes | voting | senlin-dsvm-tempest-py35-api、senlin-dsvm-tempest-py35-functional、senlin-dsvm-tempest-py35-integration(仅检查,非投票) | ||
| solum | Yes | Yes | voting | solum-devstack-py35(仅检查) |
Victor Stinner 提出了 blueprint solum-python3,该蓝图已被批准。补丁:搜索 bp/solum-python3 主题(开放的评审)。 | |
| storlets | 否 | Yes | voting | Storlets 将保留 python2 支持。 | ||
| tacker | Yes | Yes | voting | tacker-functional-devstack-python3(仅检查,非投票) | ||
| tricircle | Yes | Yes | voting | |||
| vitrage | Yes | Yes | voting | vitrage-dsvm-api-py35 和 vitrage-dsvm-datasources-py35 | ||
| watcher | Yes | Yes | voting | |||
| zaqar | Yes | Yes | voting | |||
| zun | Yes | Yes | voting | zun-tempest-py35-docker-sql | ||
| networking-l2gw | Yes | Yes | voting | |||
| vmware-nsx | Yes | Yes | voting | 所有第三方 CI 作业都在运行 python 3 | ||
| vmware-nsxlib | Yes | Yes | voting | tempest-api-vmware-nsxv3 正在运行 python 3.5 并且是投票的 |
未排序的项目
- 应用目录
- Chef OpenStack (Ruby)
- Kolla:~2100 行 Python 代码,但没有“tox -e py27”目标
- OpenStack Ansible (Python):用于部署的 Ansible 剧本和角色
- Puppet OpenStack (Ruby)
- TripleO
Python 2:已停止支持 Python 2.6,仅支持 Python 2.7
OpenStack Liberty 目标 Python 2.7 和 3.4。
Python 2.6 支持在 OpenStack Juno for servers 中已被停止。Python 2.6 支持当前保留在 Oslo 库和客户端中。请参阅 juno-cross-project-future-of-python etherpad。
Python 3.3 支持在 OpenStack Liberty 中已被停止。
Python 2.6 正在整个 OpenStack 项目中逐渐停止,例如:Remove p26 job from DIB。
Python 2.6 支持将在 Oslo 和 Clients 客户端中为 OpenStack Mitaka 删除:Oslo libraries dropping python 2.6 compatability。
将 Python 2 代码移植到 Python 3
OpenStack 项目选择使用相同的代码库来支持 Python 2 和 Python 3。Six: Python 2 and 3 Compatibility Library 有助于编写在两个版本上都能运行的代码。OpenStack 支持 RHEL 最高到 Juno 的 Python 2.6,但不支持 Python 2.5 及更早版本。由于我们正在定位 Python 3.4 及更高版本,因此无需避免 u'unicode' 语法。不要使用 six.u('unicode')。
开始之前
如果您使用 Ubuntu/Debian 进行开发(而不是使用 USE_PYTHON 标志设置的 devstack),则需要安装以下软件包才能运行项目中 py34 tox 单元测试目标
sudo apt-get install python3.4 python3.4-dev
sixer 工具
sixer 工具有助于替换大多数基本模式以添加 Python 3 兼容性,并且它尊重 OpenStack 编码风格。
常见模式
- 将“for key in dict.iterkeys()”替换为“for key in dict”
- 将 dict.iteritems() 替换为 dict.items()
- 将 dict.itervalues() 替换为 dict.values()
注意:过去首选将 dict.iteritems()/.itervalues() 替换为 six.iteritems(dict)/six.itervalues(dict),但有一个 讨论建议避免在六中对此进行操作。在 Python 2 上创建临时列表的开销可以忽略不计。
- 将 iterator.next() 替换为 next(iterator)
- 将 basestring 替换为 six.string_types
- 将 unicode 替换为 six.text_type
- 将 (str, unicode) 替换为 six.string_types
- 将 (int, long) 替换为 six.integer_types
- 将 func.func_name 替换为 func.__name__
- 将 exceptions.OSError 替换为 OSError 并删除“import exceptions”
- map() 和 filter() 如果需要 Python 3 中的列表
- 将 map(func, data) 替换为 [func(item) for item in data]
- 将 filter(lambda obj: test(obj), data) 替换为 [obj for obj in data if test(obj)]
- 注意:通常,测试失败是因为 map() 或 filter() 对象没有长度
序列化:base64、JSON 等
- [使用 oslo.serialization 1.10 或更高版本] 从 oslo_serialization(from oslo_serialization import base64)获取 base64 模块 以获取函数
- oslo_serialization.base64.decode_as_bytes(encoded)
- oslo_serialization.base64.decode_as_text(encoded, encoding='utf-8')
- oslo_serialization.base64.encode_as_bytes(s, encoding='utf-8')
- oslo_serialization.base64.encode_as_text(s, encoding='utf-8')
- 替换 text.encode('base64') 和 base64.b64encode(text) 为
- base64.b64encode(text):仅接受字节并返回字节,
- 或者:oslo_serialization.base64.encode_as_bytes(text):接受字节或 Unicode 并返回字节
- 或者:oslo_serialization.base64.encode_as_text(text):接受字节和 Unicode 并返回 Unicode
- 警告:base64.encodestring(raw) 添加一个换行符(“\n”),而 encode_as_bytes() 和 encode_as_text() 不添加。
- 替换 raw.decode('base64') 为
- base64.b64decode(raw):返回字节
- oslo_serialization.base64.decode_as_bytes(encoded):接受字节和 Unicode,返回字节
- oslo_serialization.base64.decode_as_text(encoded):接受字节和 Unicode,返回 Unicode
十六进制
- 替换 raw.decode('hex') 为 binascii.unhexlify(raw)
- 替换 bytes.encode('hex') 为 binascii.hexlify(bytes)
JSON
- [使用 oslo.serialization 1.10 或更高版本] 替换 json.dumps(obj) 为 oslo_serialization.jsonutils.dump_as_bytes(obj)
- 替换 json.loads(obj) 为 oslo_serialization.jsonutils.loads(obj):它接受字节和 Unicode,字节从 UTF-8 解码。它避免了“if isinstance(obj, bytes): obj = obj.decode('utf-8')”,这可能需要第二个临时变量。
contextlib.nested
要替换 contextlib.nested 是使用 contextlib.ExitStack。它在 Python 2 上可用,使用 contextlib2.ExitStack。对于 contextlib.nested,nova/test.py 定义
if six.PY3:
@contextlib.contextmanager
def nested(*contexts):
with contextlib.ExitStack() as stack:
yield [stack.enter_context(c) for c in contexts]
else:
nested = contextlib.nested
另一种替换 contextlib.nested 的方法是使用 @mock.patch 装饰器。带有嵌套函数的示例
def test_thing(self):
@mock.patch(...)
@mock.patch(...)
@mock.patch(...)
def do_test(...):
...
do_test()
更多选项
- Mock 提供了一个可以修补多个内容的环境,因此不需要嵌套:mock.patch.multiple()
- oslotest 提供了 mock 的 fixtures,因此您不需要 context:oslotest.mockpatch。
oslo_utils.encodeutils.to_utf8
oslo.utils 3.5 具有一个 oslo_utils.encodeutils.to_utf8() 函数,用于将 Unicode 编码为 UTF-8 并保持字节不变。
bytes.decode 和 unicode.encode
Python 有“默认编码”的概念:sys.getdefaultencoding()。在 Python 2 上,默认编码是 ASCII,而在 Python 3 上是 UTF-8。
不要在没有参数的情况下编写 data.decode() 或 text.encode(),因为您将在 Python 2 和 Python 3 上使用不同的编码。
使用显式编码。例如:data.decode('utf-8') 或 text.encode('utf-8')。正确的编码取决于用例,但 UTF-8 通常是一个不错的选择(它是 ASCII 的超集)。
safe_decode
Olso Incubator 具有一个函数 safe_decode(),可用于解码字节字符串并保持文本字符串不变。
默认编码是 sys.stdin.encoding or sys.getdefaultencoding()
- Python 3:区域设置编码,或者如果 sys.stdin 是“mocked”(io.StringIO 实例)则为 UTF-8
- Python 2:区域设置编码,或者如果 stdin 不是 TTY 或如果 sys.stdin 是“mocked”(StringIO.StringIO 实例)则为 ASCII
为了不依赖于区域设置编码并在 sys.stdin 被“mocked”时具有相同的行为,最好显式指定编码。
安全用法
-
safe_decode(data, 'utf-8'):从 UTF-8 解码字节或如果已经是文本字符串则返回数据不变
不安全用法
-
safe_decode(data)
默认情况下,解码器是严格的。可以使用可选的 errors 参数指定不同的错误处理程序。例如:safe_decode(b'[\xff]', 'ascii', 'ignore') 返回 '[]'。
safe_encode
Olso Incubator 具有一个函数 safe_encode(),可用于编码字符串。它的用法很复杂,您应该了解它的工作方式以及使用了哪些编码。
-
safe_encode(text)将文本编码为输出编码 -
safe_encode(bytes)可能会解码字符串,然后重新编码为不同的编码,如果输入和输出编码不同
默认输入编码(incomding 参数)是 sys.stdin.encoding or sys.getdefaultencoding()
- Python 3:区域设置编码,或者如果 sys.stdin 是“mocked”(io.StringIO 实例)则为 UTF-8
- Python 2:区域设置编码,或者如果 stdin 不是 TTY 或如果 sys.stdin 是“mocked”(StringIO.StringIO 实例)则为 ASCII
默认输出编码(encoding 参数)是 UTF-8。
为了不依赖于区域设置编码并在 sys.stdin 被“mocked”时具有相同的行为,最好显式指定输入编码。
安全用法
-
safe_encode(data, incoming='utf-8'):将文本编码为 UTF-8 或如果已经是字节字符串则返回数据不变(因为输入和输出编码都是 UTF-8)
不安全用法
-
safe_encode(data)
示例
-
safe_encode(b'\xe9', incoming='latin-1')返回b'\xc3\xa9'。
默认情况下,编码器和解码器是严格的。可以使用可选的 errors 参数指定不同的错误处理程序。例如:safe_encode(b'[\xff]', incoming='ascii', errors='ignore') 返回 b'[]'。
logging 模块和格式化异常
oslo_utils.encodeutils 的 exception_to_unicode(exc) 函数是格式化异常为 Unicode 的推荐方法。此函数适用于 Python 2 和 Python 3,并且在大多数情况下应避免 mojibake。
在 Python 2 上,logging 模块接受字节和文本字符串。在 Python 3 上,它仅接受文本字符串。例如,logging.error(b'hello') 会记录 b'hello' 而不是 'hello'。
目前还没有明确的规则来格式化异常。根据项目,有不同的选择
-
str(exc):本机字符串,因此在 Python 2 上使用字节 -
six.text_type(exc):始终使用 Unicode。它可能会根据异常引发 unicode 错误,请小心。Python 2 中的一个例子:unicode(Exception("nonascii:\xe9"))。 -
six.u(str(exc)):如果在 Python 2 上 str(exc) 包含非 ASCII 字节,则不安全,例如:unicode(str(Exception("\xff"))) -
LOG.exception(_LE("... %(exc)s ..."), {"exc": exc, ...})
由于 logging 函数在 Python 3 上需要文本字符串,因此记录的异常应使用 str(exc) 格式化。例如:LOG.debug(str(exc))。
HTTP
HTTP 协议基于 字节
- HTTP 主体包含 字节。例如,使用 io.BytesIO 来存储 HTTP 主体的流。
- HTTPConnection.getresponse().read() 返回 字节(在 Python 3 中,str 在 Python 2 中是字节)
- 在 Python 3 上,http.client 接受文本作为 HTTP 标头:键编码为 ASCII,值编码为 ISO 8859-1(仅是 Unicode 字符集的一个小子集)
- Swift 似乎在内部将 HTTP 标头编码为 UTF-8(直接使用 UTF-8 编码,而不是使用 MIME 编码,如 =?UTF-8?Q?...?=。请参阅 HTTP [RFC 2047 http://www.ietf.org/rfc/rfc2047.txt] 和 HTTP header should use what character encoding?
将 Python 2 代码移植到 Python 3 的参考资料
- Porting to Python 3 Book by Lennart Regebro,尤其是 Language differences and workarounds。
- HOWTO: Porting Python 2 Code to Python 3 by Brett Cannon
- 将 Python 代码移植到 3.x
- python-incompatibility:演示 Python 版本之间的不兼容性。
常见陷阱
什么是字符串?
在你的提交日志/评审中,绝对不要谈论“字符串”。在 Python 2 中,“字符串”是字节;在 Python 3 中,它是一个 Unicode 文本字符串。以下代码片段可能有助于理解差异
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 错误:无法确定数据库类型
“无法确定数据库类型”错误来自 testr 使用的 .testrepository/times.dbm。
解决方法:“rm -rf .testrepository/”,然后运行“tox -e py34”再运行“tox -e py27”。你只需要执行一次。当 .testrepository/ 由 Python 2 创建时,问题才会发生在使用“tox -e py34”时。
在 DevStack 中启用 Python 3
- Fedora:
sudo dnf install python3-devel sudo python3 -m pip install python-memcached # needed by keystonemiddleware
- localrc:添加以下行
USE_PYTHON3=True
参见 切换到 python 3.5。
功能和集成测试
Etherpad:https://etherpad.openstack.org/p/support-python3.5-functional-tests
Doug Hellmann 编写了一个跨项目规范,用于在 Python 3 上运行集成测试:启用 Python 3 以进行应用程序集成测试(规范已获得 Liberty 的批准)。
DevStack 的补丁:启用可选的 Python 3 支持。
希望将其现有的功能测试套件对服务在 Python 3 上进行测试的项目应该:-
- 将 Python3.4 trove 分类器添加到相应服务的 setup.cfg 配置文件中。
- 在运行 stack.sh 之前,在 Devstack 的 localrc 配置文件中设置 USE_PYTHON3=True,在 DevStack 更改 合并或 cherry-pick 之前。
- 为必要的函数/集成测试环境在 tox 中设置 basepython = python3.5。
然后运行 tox -e<你的功能测试套件名称>。例如:tox -efunctional 运行某个项目的函数测试。
一旦功能测试套件能够可靠地通过在 python 3.5 环境中对服务的测试,则必须更新 trove 分类器,并为项目添加新的 gate 作业。
Sirushti Murugesan 在 Heat 上的尝试:https://review.openstack.org/#/c/188033/
Python 3.5
- project-config:添加 python35 作业
- nova:在 tox 中添加 py35 环境
- Neutron 问题:https://bugs.launchpad.net/neutron/+bug/1559191
- 目前还没有使用 Python 3.5 的 Jenkins 作业
- /usr/bin/python3 在 Fedora 24、Ubuntu 16.04 LTS (Xenial Xerus) 和 Debian Stretch (Testing) 中是 Python 3.5
Python 3.6 状态
Python 3.6 计划成为 Ubuntu 18.04 LTS (Bionic Beaver) 和 Debian 10 (Buster) 中可用的唯一 Python 版本。
已知问题
- eventlet<0.21.0 与 Python 3.6 不兼容,请参见 https://github.com/eventlet/eventlet/issues/371。 还有 https://github.com/eventlet/eventlet/issues/401,该问题在 0.22.0 中已修复,因此在我们可以进行适当的测试后,升级到 eventlet-0.22.1 似乎是可行的。
- Horizon 明确仅支持 Python 3.5,在使用 Python 3.6 运行 devstack 时,需要设置
ENABLED_PYTHON3_PACKAGES=horizon
Linux 发行版中 Python 3 的状态
- ArchLinux 已经 默认切换到 Python 3 于 2011 年
- Ubuntu 计划从 Ubuntu 18.04 LTS 的默认安装中删除 Python 2:参见 (Python) 18.04 计划。
- Fedora 计划在 Fedora 23 中进行切换(2015 年 10 月):将 Python 3 作为默认实现
- Fedora 的 Python 3 移植数据库 和 Fedora portingdb 跟踪的软件包历史记录
- Fedora 中的 Python 3(Fedora 中的 Python 3)
- RHEL:Python 3.3 和 Python 3.4 可在 RHEL6 和 RHEL7 上使用 SCL。
- CentOS:Python 3.3 和 Python 3.4 可在 CentOS 6 和 7 上使用 SCL(无需 Red Hat 订阅,CentOS 有自己版本的 SCL)
- 在 Debian 中,计划在 Stretch(即 Debian 9,Jessie 之后的下一个稳定 Debian)中弃用 Python 2,并在 Debian 的 Buster 版本(即 Debian 10,预计于 2019 年发布)中完全删除 Python 2。
请查看 项目测试接口,以获取有关每个版本在哪些平台上进行测试的更新。
依赖项中 Python 2 支持被放弃的状态
- Django 2.0 将不再包含 Python 2 支持(2017 年 1 月 23 日,我们使用 Django>=1.8,<1.9)
- Pylons/Pyramid 也在考虑放弃 Python 2
- https://github.com/Pylons/pyramid/issues/2903
- 这是维护 webob 的同一个团队,但尚不清楚他们是否打算在那里也放弃支持。
OpenStack 计划在 U 周期开始时停止放弃 Python 2 支持
进度报告、会议和冲刺
- Pike PTG:https://etherpad.openstack.org/p/ptg-pike-python35
- Ocata Summit
- openstack-dev:OpenStack 移植到 Python 3 的状态(2016 年 6 月 22 日)。80 个项目/83 个(96%)在 Python 3 上通过了单元测试,TODO(3):Nova、Swift 和 Trove。
- Mitaka Summit
- 跨项目会话:提出了 Python 3,https://etherpad.openstack.org/p/mitaka-cross-project-session-planning
- Liberty Summit
- 关于启用应用程序集成测试的跨项目会话:https://etherpad.openstack.org/p/liberty-cross-project-python3
- Kilo Summit
- Doug Hellmann:“将我们的应用程序迁移到 Python 3”跨项目会话
- Victor Stinner:“将 nova 移植到 Python 3”,https://etherpad.openstack.org/p/liberty-nova-summit-ideas
- Juno summit 笔记:https://etherpad.openstack.org/p/juno-cross-project-future-of-python(Oslo)和 https://etherpad.openstack.org/p/juno_swift_python3(Swift)
- Icehouse summit 笔记:https://etherpad.openstack.org/p/IcehousePypyPy3
- Havana summit 笔记:https://etherpad.openstack.org/p/havana-python3
文章
- OpenStack Mitaka 中 Python 3 的状态(Victor Stinner,2016 年 3 月)
- OpenStack Liberty 中 Python 3 的状态(Cyril Roelandt 和 Victor Stinner,2015 年 9 月)
- OpenStack 移植到 Python 3 的状态(Cyril Roelandt,2014 年 2 月)
- 为什么 OpenStack 现在应该迁移到 Python 3?(Victor Stinner,2013 年 12 月)
Pycon Montreal 2014:Sprint Port OpenStack to Python 3
Enovance 在 4 天内组织了一次冲刺,将 OpenStack 移植到 Python 3:2014 年 4 月 14 日(星期一)至 2014 年 4 月 17 日(星期四)。请参阅页面 Python3/SprintPycon2014。