88 lines
2.9 KiB
Python
88 lines
2.9 KiB
Python
"""把当前源码编译结果与最后一版正确源码的 .pyc 逐个 code 对象比对。
|
|
|
|
这是修复正确性的最终判据:注释吞掉语句、误拆行等问题都会在字节码上暴露。
|
|
行号允许不同(注释多一行少一行不影响语义),比对的是 co_code、常量与名字。
|
|
"""
|
|
|
|
import marshal
|
|
import os
|
|
import types
|
|
|
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|
_ROOT = os.path.dirname(_HERE)
|
|
|
|
|
|
def index_code(root, prefix=""):
|
|
table = {}
|
|
|
|
def walk(c, path):
|
|
key = path
|
|
suffix = 0
|
|
while key in table:
|
|
suffix += 1
|
|
key = f"{path}#{suffix}"
|
|
table[key] = c
|
|
for const in c.co_consts:
|
|
if isinstance(const, types.CodeType):
|
|
walk(const, f"{path}/{const.co_name}")
|
|
|
|
walk(root, prefix or root.co_name)
|
|
return table
|
|
|
|
|
|
def scalars(c):
|
|
return tuple(
|
|
x for x in c.co_consts if not isinstance(x, types.CodeType)
|
|
)
|
|
|
|
|
|
def main():
|
|
source = open(os.path.join(_ROOT, "wechat_bot.py"), encoding="utf-8").read()
|
|
current = compile(source, "wechat_bot.py", "exec")
|
|
good = marshal.loads(
|
|
open(os.path.join(_HERE, "wechat_bot.lastgood.pyc"), "rb").read()[16:]
|
|
)
|
|
|
|
left = index_code(current)
|
|
right = index_code(good)
|
|
|
|
only_current = sorted(set(left) - set(right))
|
|
only_good = sorted(set(right) - set(left))
|
|
print(f"当前 code 对象 {len(left)} 个,正确版 {len(right)} 个")
|
|
if only_good:
|
|
print(f"缺失的 code 对象 {len(only_good)} 个(说明有语句被吞进注释):")
|
|
for name in only_good[:20]:
|
|
print(" ", name)
|
|
if only_current:
|
|
print(f"多出来的 code 对象 {len(only_current)} 个:")
|
|
for name in only_current[:20]:
|
|
print(" ", name)
|
|
|
|
differing = []
|
|
for name in sorted(set(left) & set(right)):
|
|
a, b = left[name], right[name]
|
|
if a.co_code != b.co_code:
|
|
differing.append((name, "字节码"))
|
|
elif scalars(a) != scalars(b):
|
|
differing.append((name, "常量"))
|
|
elif a.co_names != b.co_names or a.co_varnames != b.co_varnames:
|
|
differing.append((name, "名字表"))
|
|
|
|
if differing:
|
|
print(f"\n有差异的 code 对象 {len(differing)} 个:")
|
|
for name, kind in differing[:25]:
|
|
print(f" [{kind}] {name}")
|
|
if kind == "常量":
|
|
a, b = scalars(left[name]), scalars(right[name])
|
|
for x, y in zip(a, b):
|
|
if x != y:
|
|
print(f" 当前={x!r}")
|
|
print(f" 应为={y!r}")
|
|
break
|
|
else:
|
|
print("\n所有 code 对象逐字节一致:代码语义与最后一版正确源码完全相同。")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|