编译蟒蛇3.6+蟒蛇2.7+
lib3to6的Python项目详细描述
lib3to6
将Python3.6+代码编译为Python2.7+兼容代码。这个想法相当 类似于bablehttps://babeljs.io/。使用最新的翻译和 在不牺牲向后兼容性的情况下使用(大多数)新的语言功能。
项目/回购:
代码质量/ci:
<表><广告>项目状态(截至2019-02-21):实验性
我用这个图书馆主要是为了 pycalver项目无任何问题。我 在Python3.8接近发布之前,不会添加任何新的修正程序或检查程序。 请尝试发送您的反馈。
最终目标是涵盖所有记录在案的案件 http://python future.org和其中一个:
- 将文件转换为可用于任何版本的代码
- 提出错误,理想情况下指向 python-future.org或其他描述 编写向后兼容代码的替代方法。
https://docs.python.org/3.x/whatsnew/也包含了很多关于 可以检查的API更改,但检查和修复程序 只有当它们足够普遍的时候才会写,否则 工作太多了(不过也欢迎使用补丁)。
开发入门
$ git clone https://gitlab.com/mbarkhau/lib3to6.git $ cd lib3to6/ lib3to6 $ make install ... lib3to6 $ make test ... lib3to6 $ make help
动机
这个项目的主要动机是能够使用mypy
不牺牲与旧版本python的兼容性。
# my_module/__init__.pydefhello(who:str)->None:importsysprint(f"Hello {who} from {sys.version.split()[0]}!")print(__file__)hello("世界")
$ pip install lib3to6 $ python -m lib3to6 my_module/__init__.py
# -*- coding: utf-8 -*-from__future__importabsolute_importfrom__future__importdivisionfrom__future__importprint_functionfrom__future__importunicode_literalsdefhello(who):importsysprint('Hello {0} from {1}!'.format(who,sys.version.split()[0]))print(__file__)hello('世界')
应用修复程序将python3代码的语义匹配为 即使在python2.7解释器上运行,也要尽可能接近。
已应用的一些修复程序:
- PEP263 magic comment to declare the coding of the python
source file. This allows the string literal `"世界"` to
be decoded correctly.
- `__future__` imports have been added. This includes the well
known print statement -> function change. The unicode_literals
- Type annotations have been removed
- f string -> "".format conversion
cli命令lib3to6
非常适合演示,
但对于你的项目,最好在
setup.py文件。
# setup.pyimportsysimportsetuptoolspackages=setuptools.find_packages(".")package_dir={"":"."}ifany(arg.startswith("bdist")forarginsys.argv):importlib3to6package_dir=lib3to6.fix(package_dir)setuptools.setup(name="my-module",version="201808.1",packages=packages,package_dir=package_dir,)
~/my-module $ python setup.py bdist_wheel --python-tag=py2.py3
running bdist_wheel
...
~/my-module$ ls -1 dist/
my_module-201808.1-py2.py3-none-any.whl
~/my-module$ python3 -m pip install dist/my_module-201808.1-py2.py3-none-any.whl
Processing ./dist/my_module-201808.1-py2.py3-none-any.whl
Installing collected packages: my-module
Successfully installed my-module-201808.1
~/my-module$ python2 -m pip install dist/my_module-201808.1-py2.py3-none-any.whl
Processing ./dist/my_module-201808.1-py2.py3-none-any.whl
Installing collected packages: my-module
Successfully installed my-module-201808.1
为了确保我们从安装中导入我的_模块,作为 与本地目录相反,我们必须切换 目录。
~/$ python3 -c "import my_module" /home/user/my-module/my_module/__init__.py Hello 世界 from 3.6.5! ~/my-module$ cd .. ~/$ python3 -c "import my_module" /home/user/envs/py36/lib/python3.6/site-packages/my_module/__init__.py Hello 世界 from 3.6.5! ~$ python2 -c "import my_module" /home/user/envs/py27/lib/python2.7/site-packages/my_module/__init__.py Hello 世界 from 2.7.15!
功能支持
并非所有新的语言特性在旧的 版本。如果可以检测到这些,则会出现错误 使用这些功能时报告。
一个(显然不是详尽无遗的)特征列表 支持:
- 异步/等待
- 屈服于
- @/matmul运算符
支持的功能
- PEP 498:格式化字符串文本。
- 注释的省略
- 展开一般化
- 仅限关键字参数
- PEP 515:数字文本中的下划线
- 将/zip/filter映射到ITertools等效项
- 转换基于类的typing.namedtuple用法到赋值
一些新库具有后台端口,警告将指向:
- 键入
- 路径库
- 秘密
- IP地址
- csv->;backports.csv
- lzma->;backports.lzma
- 枚举->;flufl.enum
工作原理
这个项目在python抽象语法的层次上工作
树(AST)。AST被转换为仅用于
在旧版本的python中也有效的构造。为了
它将使用
str.format
方法。
>>>importsys>>>sys.version_info'3.6.5'>>>importlib3to6>>>py3_source='f"Hello {1 + 1}!"'>>>cfg={"fixers":["f_string_to_str_format"]}>>>py2_source=lib3to6.transpile_module(cfg,py3_source)>>>print(py3_source)f"Hello {1 + 1}!">>>print(py2_source)# -*- coding: utf-8 -*-"Hello {0}!".format(1+1)>>>print(lib3to6.parsedump_ast(py3_source))Module(body=[Expr(value=JoinedStr(values=[Str(s='Hello '),FormattedValue(value=BinOp(left=Num(n=1),op=Add(),right=Num(n=1),),conversion=-1,format_spec=None,),Str(s='!'),]))])>>>print(lib3to6.parsedump_ast(py2_source))Module(body=[Expr(value=Call(func=Attribute(value=Str(s='Hello {0}!'),attr='format',ctx=Load(),),args=[BinOp(left=Num(n=1),op=Add(),right=Num(n=1),)],keywords=[]))])
当然,这并不能涵盖兼容性的所有方面。 不能用这种方式自动转换API中的更改。
一个明显的例子是,没有办法传输代码
它使用异步
和等待
。在这种情况下,lib3to6
只会引发一个checkerror。这只适用于你的来源
尽管如此,如果import使用一个库,该库使用async
和
等待
,在运行测试之前,一切看起来都很好
在Python 2.7上。
一个更微妙的例子是内置的语义变化
打开
功能。
$ git clone https://gitlab.com/mbarkhau/lib3to6.git $ cd lib3to6/ lib3to6 $ make install ... lib3to6 $ make test ... lib3to6 $ make help0
通常有其他方法来编写等价的代码 适用于所有版本的python。为了这些普通的 lib3to6的不兼容将引发错误并建议 另一种方法,例如在本例中使用io.open。
$ git clone https://gitlab.com/mbarkhau/lib3to6.git $ cd lib3to6/ lib3to6 $ make install ... lib3to6 $ make test ... lib3to6 $ make help一
这里lib3to6
您将给出一个"checkerror",但是
仍然由您负责编写代码,以便
在python3中句法翻译在语义上是等价的
和蟒蛇2。
lib3to6
使用pythonast
模块解析代码。这个
意味着您需要一个现代的python解释器来从
现代python到传统python解释器。你不能透明
解释程序无法解析的功能。预期用途是
对于使用最新python的库的开发人员
版本,但希望他们的库能够处理旧版本。
FAQ
问:标语"兼容性很重要"不是很讽刺吗? 考虑到python 3.6+需要构建一个轮子?
A:讽刺的一点也不失。问题是,如何解析源 来自比python更新的python版本的代码 解释器本身支持。您可以在上安装lib3to6 旧版本的python,但是 该版本支持的功能。例如,你不会 能够在Python3.5上使用f""字符串,但大多数注释 工作正常。
问:为什么要让蟒蛇2.7活着?就让它死吧!
答:的确,lib3to6可以帮助解决这个问题。把你自己放在 一个在旧代码库工作的人的鞋子。不是 实事求是地抓住所有其他发展努力, 代码库被迁移和测试,而其他一切都在等待。
相反,增量方法通常是唯一的选择。 使用lib3to6,代码库的各个模块可以 迁移到python3,剩下的代码基 未触及的该项目仍然可以在Python2.7中运行 环境,而开发人员越来越倾向于使用 巨蟒3。
此外,lib3to6不仅仅是为了与 Python2.7,它还允许您使用新特性,如f" 字符串和变量注释,同时仍保持 与旧版本的python 3兼容。
问:为什么不
lib3to2
?A:老实说,我对lib3to2不能说太多。似乎不是 被维护并查看源代码 更容易写一些新的东西,在ast级别上工作。 lib3to6的作用域比3to2更一般,您可以 使用它,即使您只关心从Python3.6转换 至3.5。
https://gitlab.com/mbarkhau/lib3to6的更改日志
V201902.0030
- fix python 2内置项并不总是被正确覆盖。
- 修复pypy兼容性测试
- 更好的mypy覆盖率
V201812.0021-β
- 递归地应用一些修复程序。
V201812.0020-α
- 转到gitlab.com
- 使用bootstrapit
- 根据与pycalver的使用修复错误
V201809.0019-α
检查错误包括日志行号
transfile错误现在包括文件名
为重命名的模块添加了修复程序,例如 …代码块::diff
$ git clone https://gitlab.com/mbarkhau/lib3to6.git $ cd lib3to6/ lib3to6 $ make install ... lib3to6 $ make test ... lib3to6 $ make help
2
V201808.0014-α
- 更好地处理包目录
- 更改为
Calver版本控制<;https://calver.org/>;
\uu - 删除控制台脚本以支持简单的python-m lib3to6
- 重命名自
three2six
->;lib3to6