fix(python): honor version-specific code equality

Fixes #6547
This commit is contained in:
morluto committed 2026-10-23 17:04:03 +08:00
1 parent 012959e3cc
commit 60981e0801
3 files changed
+124 -2

No files matched your search

+62
View File
@@ -918,6 +918,68 @@ it("accepts code objects as set members and dictionary keys", () => {
expect(pythonPycSchema.safeParse(report).success).toBe(true);
});
it("uses the code equality fields for each CPython layout", () => {
const codeCollections = (
layout: "py38" | "py311",
different: boolean,
): [Buffer, Buffer] => {
const lineA = marshalCode(layout, {
name: "f",
filename: "fixture.py",
firstlineno: 1,
linetable: Buffer.from([2, 1]),
});
const lineB = marshalCode(layout, {
name: "f",
filename: "fixture.py",
firstlineno: 1,
linetable: Buffer.from([2, different ? 2 : 1]),
});
const frozenSet = Buffer.concat([
Buffer.from([0x3e]),
u32(2),
lineA,
lineB,
]);
const dict = Buffer.concat([
Buffer.from([0x7b]),
lineA,
Buffer.from([0x4e]),
lineB,
Buffer.from([0x54, 0x30]),
]);
return [frozenSet, dict];
};
for (const [magic, layout] of [
[3413, "py38"],
[3439, "py38"],
] as const) {
const [frozenSet, dict] = codeCollections(layout, true);
const report = parse(
Buffer.concat([
pythonPycHeader(magic),
marshalCode(layout, { consts: [frozenSet, dict] }),
]),
);
expect(root(report).consts).toEqual([
{ kind: "frozenset", length: 1 },
{ kind: "dict", length: 1 },
]);
}
const [frozenSet, dict] = codeCollections("py311", true);
const py312 = parse(
Buffer.concat([
pythonPycHeader(3531),
marshalCode("py311", { consts: [frozenSet, dict] }),
]),
);
expect(root(py312).consts).toEqual([
{ kind: "frozenset", length: 2 },
{ kind: "dict", length: 2 },
]);
});
it("keeps the first dictionary key when a later key compares equal", () => {
const key = (filename: string): Buffer =>
marshalCode("py311", {
+6 -2
View File
@@ -1156,8 +1156,12 @@ class MarshalReader {
`${node.bytecode.bytes}:${node.bytecode.sha256}`,
this.#constKeyItems(material.consts),
...nameTables,
material.linetable,
material.exceptiontable,
// CPython started including line and exception tables in code equality
// with the 3.11 code layout; earlier layouts still retain their digests
// in CodeEquality, but those fields do not affect container identity.
...(this.layout === "py311"
? [material.linetable, material.exceptiontable]
: []),
];
const key = this.#boundedJoin(
"",