Skip to content

CI matrix tests Python 3.10 below the collection's declared 3.11 floor #299

@allenrobel

Description

@allenrobel

Summary

The CI matrix in .github/workflows/ansible-test.yml tests Python 3.10 against stable-2.16 and stable-2.17, but the collection's declared Python floor is 3.11+. The matrix should be the intersection of cisco/nd's floor and ansible-core's supported Python range — i.e., drop the two 3.10 cells.

Current state

pyproject.toml line 6 declares the floor:

requires-python = ">=3.11"

CLAUDE.md mirrors it:

Python >= 3.11 required

But .github/workflows/ansible-test.yml matrix (lines 60–74) still includes:

# Ansible 2.17: supports Python 3.7 - 3.12
- ansible_version: "stable-2.17"
  python_version: "3.12"
- ansible_version: "stable-2.17"
  python_version: "3.11"
- ansible_version: "stable-2.17"
  python_version: "3.10"     # below declared floor

# Ansible 2.16: supports Python 3.10 - 3.12
- ansible_version: "stable-2.16"
  python_version: "3.12"
- ansible_version: "stable-2.16"
  python_version: "3.11"
- ansible_version: "stable-2.16"
  python_version: "3.10"     # below declared floor

ansible-core itself supports 3.10 in those versions, but cisco/nd does not.

How it surfaced

On the nd_interface_ethernet_access stack, CI unit tests failed only on the two 3.10 cells with:

AttributeError: 'ModelPrivateAttr' object has no attribute 'match'

This is a real Pydantic v2 behavior: leading-underscore class attributes on a BaseModel (e.g. _INTERFACE_NAME_PREFIX_RE: ClassVar = re.compile(...)) get wrapped in ModelPrivateAttr regardless of the ClassVar annotation. The Pydantic build that resolves under Python 3.10 doesn't unwrap the descriptor on class access, so cls._INTERFACE_NAME_PREFIX_RE.match(...) raises AttributeError. On Python 3.11+ the bundled Pydantic does unwrap and the call works. Every cell at or above our declared floor (3.11/3.12/3.13 across 2.16–2.19) was green.

The right response to "an unsupported configuration fails" is to stop testing the unsupported configuration, not to work around it in the source — the workaround silently extends de-facto support without updating pyproject.toml, and ages poorly.

Proposed change

Edit .github/workflows/ansible-test.yml:

  • Drop matrix entry ansible_version: "stable-2.17" + python_version: "3.10" (line 65–66)

  • Drop matrix entry ansible_version: "stable-2.16" + python_version: "3.10" (line 73–74)

  • Fix the comment on line 60: ansible-core 2.17 needs Python 3.10+, not 3.7+ — the comment currently reads "Ansible 2.17: supports Python 3.7 - 3.12" which is wrong

  • Update the remaining comments to note cisco/nd's 3.11 floor, e.g.:

    # Ansible 2.17: supports Python 3.10 - 3.12; cisco/nd floor is 3.11
    # Ansible 2.16: supports Python 3.10 - 3.12; cisco/nd floor is 3.11

Blast radius

Workflow-only change. Every open PR's next CI run will lose two job entries but no existing job semantics change:

  • PRs green today stay green.
  • PRs red only on the two 3.10 cells turn green — correct, since those configurations are unsupported.

Alternative considered

Raise the declared floor commitment to include 3.10 (update pyproject.toml and CLAUDE.md, keep the matrix) and apply Pydantic workarounds in the source. Rejected because it extends maintenance burden to an older Python without a stated reason and because the cisco/nd codebase already uses Python 3.11+ syntax features (PEP 604 unions, X | None) per CLAUDE.md.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdocumentationImprovements or additions to documentation

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions