如何检测代码是否适用于Python 3

35

我正在使用openstack/bandit进行静态代码分析。有很多个代码库,其中一些是用Python 2编写的,另一些是用Python 3编写的。如何在不运行代码的情况下检测代码是否与Python 3的语法兼容。

5个回答

20

基本验证方法是检查2to3工具是否打印出任何差异(请参见 https://docs.python.org/3/library/2to3.html 了解基本用法)。

对于像a.py这样的简单文件:

import urllib2

print "printing something"

您需要执行以下命令:

> 2to3 a.py

RefactoringTool: Skipping optional fixer: buffer
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: set_literal
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored a.py
--- a.py    (original)
+++ a.py    (refactored)
@@ -1,4 +1,4 @@
-import urllib2
+import urllib.request, urllib.error, urllib.parse

-print "printing something"
+print("printing something")

RefactoringTool: Files that need to be modified:
RefactoringTool: a.py

同样的想法,只是由于某些原因我无法发布答案。 :D +1 - derM
12
我认为如果给予Python 3代码,那么它会产生很多错误的答案。例如,我刚试过,它想用print((42))替换print(42),很痛苦。所以你会看到一个差异并认为它是Python 2吗? - Stefan Pochmann
@StefanPochmann 刚刚验证了一下,似乎将其解释为元组(错误地)。print("testing") 没有被修改。 - Jann
3
2to3 是否假定输入代码总是 Python 2 的情况可能存在吗? - aisbaa
这很有可能是真的。该问题中的链接名为“25.4. 2to3 - 自动化Python 2到3代码转换”-https://docs.python.org/2/library/2to3.html - SDsolar

19

以下是需要翻译的内容:

这里有一件你可能想做的事情。我认为这是你可以知道代码是否至少在语法上兼容的最简单方法。

编写一个Python3程序来加载Python模块(但不执行它们)。如果代码是兼容的,它将加载模块;如果不兼容,则会引发语法错误。

使用ast模块。

import ast

def test_source_code_compatible(code_data):
    try:
        return ast.parse(code_data)
    except SyntaxError as exc:
        return False

ast_tree = test_source_code_compatible(open('file.py', 'rb').read())
if not ast_tree:
    print("File couldn't get loaded")

如果代码无法加载,则会引发SyntaxError错误。 Ast模块的文档 如果无法加载抽象语法树,则可能需要检查Python2中不存在的方法或更改了行为的方法。
例如,Python3和Python2中的除法工作方式不同。在Python2中,除法将整数除以结果,因此如果您不使用相同的除法方案,则除法的结果将不同。在这种情况下,您需要查看模块是否导入from __future__ import division以在Python2和Python3中具有相同的行为。
以下是您可能想要处理的详尽列表: http://python-future.org/compatible_idioms.html 加载模块的ast将立即提供绝对无法工作的内容...但是,知道可解析的代码是否在Python3中工作存在许多误报。准确地检测代码是否在Python2和3中实际上可以100%工作是困难甚至不可能的,必须运行代码并比较结果。

如果代码兼容,它将加载模块并执行该模块中的所有顶层代码。 - vaultah
2
也许你应该写一下如何加载它们。 - Stefan Pochmann
@LoïcFaure-Lacroix 这个部分代码现在已经写好了,不是原来的。你还没有展示出code_data是如何得到的。 - Stefan Pochmann
@StefanPochmann 在您发表评论时,答案中已经写明了。但是如果您坚持要获取code_data的方法... - Loïc Faure-Lacroix
没有任何输出。 print("ast_tree = ", ast_tree) #ast_tree = <_ast.Module object at 0x00000252ABEAD2E0> print("ast_tree type = ", type(ast_tree)) # ast_tree type = <class '_ast.Module'> - boardtc
显示剩余2条评论

10

确保你的代码在语法上与Python3兼容的最基本验证是针对该特定模块运行pylint3并查找错误。

安装pylint3

sudo apt-get install pylint3

运行pylint3检查Python模块

pylint3 -E <module.py>

上述内容可用于捕获模块在Python3方面的语法错误。


6
您可以使用“compileall”模块进行操作,如下所示:
python3.6 -m compileall -q .

根据您想要使用的Python版本做适当修改。

自Python3(从3.x开始)以来,编译后的模块会被放置到一个名为__pycache__的目录中,并带有特定于架构的扩展名,因此它们不会与Python2或其他Python3版本冲突。

给定的命令只会显示错误,并从当前目录递归。使用python3.6 -m compileall --help可以显示所有选项。


6
你可以使用Pycharm集成开发环境来进行编程。只需在Pycharm编辑器中打开Python文件,它会显示警告,如果代码不兼容Python2或Python3。
这是一个屏幕截图,显示了print命令语法警告。 enter image description here

5
个人最低费用为每年89美元。 - SDsolar
5
@SDsolar 这个未来功能在社区版中得到支持。 - El Ruso
在今天的Python 3中,这仍然是错误的吗? - Akito

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接