Skip to content

aliases.py and _eager.py import a deprecated-3.1.8 TmpxMacro at module scope, and its constraint set has no node in the shipped 3.2 bundle #1894

Open

Description

@KonstantinMirin

Measured on main at bef739e02, and on the PyPI wheel adcp 9.6.1 for the bundle half.

The observation

src/adcp/types/aliases.py imports a deprecated-3.1.8 compatibility class at module scope, only in order to re-export it under two flat names:

# src/adcp/types/aliases.py:2164
from adcp.types.domains.trusted_match.identity_match_response import (
    TmpxMacro as IdentityMatchTmpxMacro,
)
# :2167
from adcp.types.domains.trusted_match.provider_registration import (
    TmpxMacro as ProviderRegistrationTmpxMacro,
)

(__all__ at :2290-2291; nothing else in the module uses either name.) src/adcp/types/_eager.py:706 and :773 import the same two names the same way.

The class's own generated docstring says what it is:

# src/adcp/types/domains/trusted_match/provider_registration.py:24
class TmpxMacro(ScalarStr):
    """Deprecated 3.1.8 registered macro-name compatibility model."""
    _constraints = {'max_length': 64, 'min_length': 1, 'pattern': '^[A-Z][A-Z0-9_]*$'}

And that constraint set has no node in the 3.2 bundle the wheel ships

Scanning adcp/_schemas/3.2 from the 9.6.1 wheel (manifest.json → adcp_version 3.2.7), excluding the bundled/ and mcp/ projections, for a node carrying pattern: ^[A-Z][A-Z0-9_]*$:

document#pointer maxLength minLength
core/reporting-adjustment-receipt.json#/definitions/ReportingAdjustmentRejectionCode 128 1
core/reporting-receipt.json#/properties/rejection_codes/items 128 1
core/reporting-materialization.json#/properties/failure_code 128 1

Three positions, all maxLength: 128. Nothing in the bundle states the 64 the class pins, and the two trusted-match documents the class is generated into now state ^[A-Za-z0-9_]+$ (identity-match-response.json#/properties/tmpx_providers/propertyNames) and ^[a-zA-Z][a-zA-Z0-9_]*$ (provider-registration.json#/properties/tmpx_slots/items) instead. So the class looks like a 3.1.8 leftover that survives in the generated tree rather than a projection of a node the current bundle states.

Why the module scope matters

One unguarded module-scope import of a name a regeneration may not produce takes the whole module with it:

  • aliases.py binds 254 names at module scope and exports 311;
  • _eager.py binds 903 and exports 965 — and adcp/types/__init__.py resolves every flat type symbol by importing _eager (its own docstring at :1164: "to any type symbol, by importing :mod:adcp.types._eager"). So an ImportError there is not one missing word, it is the flat surface.

We hit this building a tree from the published 3.2 bundle where the node is not stated: with every other name resolving, these two imports alone were enough to make import adcp.types fail.

The ask, and it is a pattern this file already uses

aliases.py:2002-2009 already guards exactly this situation for a name whose home moved:

try:
    from adcp.types.domains.enums.duration_unit import DurationUnit
except ModuleNotFoundError as exc:
    if exc.name != "adcp.types.domains.enums.duration_unit":
        raise
    from adcp.types.domains.core.duration import Unit as DurationUnit

Would you take the same guard around the two deprecated-3.1.8 re-exports — try/except ImportError, and on failure simply not bind the two flat words? Then a consumer on a bundle that no longer states the node loses a deprecated compatibility word and keeps the module, which seems like the right trade for something whose own docstring says "Deprecated 3.1.8".

It is also worth asking the prior question: should TmpxMacro still be generated at all, given no node in the shipped 3.2 bundle carries its constraint set? If it is retained deliberately for 3.1.x peers, the guard is the smaller ask and this is only a request to confirm the intent.

Reproduction

python -c "import adcp.types.aliases as a; print(a.IdentityMatchTmpxMacro._constraints)"
# {'max_length': 64, 'min_length': 1, 'pattern': '^[A-Z][A-Z0-9_]*$'}

python - <<'EOF'
import json, pathlib, adcp
B = pathlib.Path(adcp.__file__).parent / "_schemas" / "3.2"
hits = [f for f in B.rglob("*.json")
        if not str(f.relative_to(B)).startswith(("bundled/", "mcp/"))
        and '"^[A-Z][A-Z0-9_]*$"' in f.read_text()]
print([str(f.relative_to(B)) for f in hits])   # the three reporting documents, all maxLength 128
EOF

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions