Files
kefu/wechat_rpa/tmp/verify_against_pyc.py
2026-08-18 17:25:22 +08:00

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()