Skip to content

fix(python): expand a ::-relative package against the declaring file's root package - #405

Merged
dmealing merged 2 commits into
mainfrom
fm/py-parser-package-expansion
Oct 6, 2026
Merged

dmealing merged 2 commits into
mainfrom
fm/py-parser-package-expansion

Conversation

@dmealing

@dmealing dmealing commented Oct 6, 2026

Copy link
Copy Markdown
Member

Intent

Yes expand like the others: make the Python parser expand a ::-relative package against the declaring file's root package at parse time, the same as TypeScript, C# and Java.
Background: in a multi-file collection whose files declare different root packages, an object that declares a ::-relative package (for example ::parts) is expanded by Python against the merged root's package, while TypeScript, C# and Java expand it against the declaring file's root package. The meta verify field-lint warnings (PR #404) therefore print a different address in Python for that case (for example acme::app::parts::Gadget.store_fk where the other ports print beta::other::parts::Gadget.store_fk), and that PR documents the difference as a known Python corner. Own small gated PR; the gate spend is approved.

What Changed

  • Parser package expansion: Python now expands ::-relative packages (e.g., "package": "::parts") during parsing against the declaring file's root package, matching TypeScript, C# and Java behavior. Previously the expansion was deferred and used the merged collection's root package, causing mismatches in multi-file models where files declare different root packages.

  • New effective_package() method: Added to MetaData to distinguish between a node's declared package (which is None if inherited) and the package it resolves under, mirroring the C# NamingRefs.EffectivePackage contract.

  • Conformance fixtures: Added loader-relative-package-multi-root to the cross-language conformance suite and reference-field-missing-multi-root-package to field-lint conformance, gating the fix across all five ports so field-lint warnings now print consistent addresses.

Risk Assessment

✅ Low: Small, well-scoped parser fix with shared helper, matching cross-port conformance fixture, and dedicated unit/conformance tests covering the new behavior and the extracted effective_package accessor.

Testing

Python parser expansion validated across 5 live scenarios: relative package expansion at parse time against declaring file root, multi-file collection resolution, field-lint address consistency, effective_package() API, and conformance fixtures. All 1251 unit/loader/conformance tests pass with no regressions.

  • Live validation: ✅ go - 6 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Parser expands :: -relative package at parse time against declaring file's root package ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/python_package_expansion_tests.txt
Multi-file collections with different root packages resolve correctly ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/python_package_expansion_tests.txt
Field-lint addresses use expanded packages consistently ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/test_summary.md
effective_package() API distinguishes declared vs inherited packages ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/python_package_expansion_tests.txt
Conformance fixtures validate cross-port consistency ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/test_summary.md
Complete regression suite passes without failures ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/python_package_expansion_tests.txt

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 6 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Parser expands :: -relative package at parse time against declaring file's root package ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/python_package_expansion_tests.txt
Multi-file collections with different root packages resolve correctly ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/python_package_expansion_tests.txt
Field-lint addresses use expanded packages consistently ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/test_summary.md
effective_package() API distinguishes declared vs inherited packages ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/python_package_expansion_tests.txt
Conformance fixtures validate cross-port consistency ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/test_summary.md
Complete regression suite passes without failures ✅ pass live 01M47GWYCXATNFYNFBPAY8JFZ5/python_package_expansion_tests.txt
  • scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchains
  • python3 -m pytest tests/loader/test_relative_package_multi_root.py::test_relative_package_expands_against_declaring_file_root
  • python3 -m pytest tests/loader/test_relative_package_multi_root.py::test_effective_package_of_an_object_without_own_package
  • python3 -m pytest tests/conformance/test_field_lint_conformance.py::test_fixture[reference-field-missing-multi-root-package]
  • python3 -m pytest tests/unit tests/loader tests/conformance (1251 tests: unit + loader + conformance)
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…s root package

The Python parser kept a relative package ("::parts") raw, and later code expanded
it against the merged root's package, which is the first file's. In a multi-file
collection whose files declare different root packages that gave a different
package, resolution key, canonical JSON and field-lint address than TypeScript, C#
and Java. The parser now expands at parse time against the declaring file's
context package, mirroring TS applyReservedKeys.

- field_lint.py drops its own expansion of the loaded model and shares the
  parser's helper for the raw-file walk.
- MetaData.effective_package() exposes the package a node resolves under.
- New conformance fixture loader-relative-package-multi-root and field-lint
  fixture reference-field-missing-multi-root-package gate every port.
- The Python corner note in the field-lint docs is removed.
@dmealing
dmealing merged commit 94424d1 into main Oct 6, 2026
1 check passed
@dmealing
dmealing deleted the fm/py-parser-package-expansion branch October 6, 2026 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant