Skip to content

Importing adcp.types.domains.formats first fails with a circular import (CanonicalFormatBase) #1784

Closed

Description

@bokelley

from adcp.types.domains.formats import Slot (or import adcp.types.domains.formats.canonical) raises ImportError when it is the first adcp types import in a process. It works only if something has already imported a model such as adcp.types.Product or adcp.types.Format. So a script, worker or test module that imports just the canonical-format types fails depending on import order, and adding or removing an unrelated import elsewhere can start or stop the failure.

Repro (9.3.0 and 10.0.0b4, fresh interpreter)

$ python -I -c "from adcp.types.domains.formats import Slot"
ImportError: cannot import name 'CanonicalFormatBase' from partially initialized module
'adcp.types.domains.formats.canonical._base' (most likely due to a circular import)

$ python -I -c "import adcp.types; from adcp.types.domains.formats import Slot"
ImportError: (same)

$ python -I -c "from adcp.types import Product; from adcp.types.domains.formats import Slot; print('ok')"
ok

The cycle:

adcp/types/domains/formats/__init__.py:19
-> formats/canonical/_base.py:14
-> core/__init__.py:207
-> core/async_response_data.py:11
-> creative/__init__.py:63
-> creative/list_creative_formats_response.py:17
-> core/format.py:23
-> formats/canonical/agent_placement.py:13  (from ._base import CanonicalFormatBase; _base is half-initialized)

Suggested fix

Break the cycle at canonical/_base.py. It should import the leaf modules it needs, not the adcp.types.domains.core package (whose __init__ pulls in every response union). Add a test that imports each public types package first, in a fresh interpreter.

Activity

  1. bokelley commented on Nov 2, 2026

    @bokelley
    ContributorAuthor

    Fixed by #1797 on next (squash 8331c88d) and #1798 on main (squash 7447d00c): the domain package roots are lazy (PEP 562), so from adcp.types.domains.formats import Slot imports first in a fresh interpreter in any order. tests/test_domain_roots_import_in_any_order.py imports every domain root first in a subprocess.

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