Skip to content

chore: add type annotation to cloudinit.net.network_manager - #7120

Open
anujsingh-cse wants to merge 5 commits into
canonical:mainfrom
anujsingh-cse:fix/untyped-defs-network-manager-5445
Open

anujsingh-cse wants to merge 5 commits into
canonical:mainfrom
anujsingh-cse:fix/untyped-defs-network-manager-5445

Conversation

@anujsingh-cse

Copy link
Copy Markdown
Contributor

Proposed Commit Message

chore: add type annotation to cloudinit.net.network_manager

Removing cloudinit.net.network_manager from the mypy override list in
pyproject.toml surfaces two errors on the same line.

__init__ assigns the builtin str as the optionxform transform, the
documented configparser idiom for preserving option name case. mypy
cannot express assigning a class to a method, so it is ignored with a
comment explaining why, matching the comment added in
cloudinit/sources/helpers/vmware/imc/config_file.py.

Refs GH-5445

Additional Context

Refs GH-5445. Claimed in #5445 (comment).

Removing the module from the override list surfaces two errors:

network_manager.py:56: error: Cannot assign to a method  [method-assign]
network_manager.py:56: error: Incompatible types in assignment
                (expression has type "type[str]",
                 variable has type "Callable[[str], str]")  [assignment]

self.config.optionxform = str is the documented configparser pattern
for preserving option name case (NM requires it). mypy cannot express
assigning a class to a method, so the line is ignored — with a comment
documenting why, per the review feedback on #7098.

Test Steps

$ python -m mypy cloudinit/net/network_manager.py
(0 errors with the override removed)

$ pytest tests/unittests/net/test_network_manager.py -q
7 passed

$ ruff check / black --check / isort --check-only (target file)
All green

tox -e py3 and tox -e check_format to be confirmed by CI
(developed on Windows where the full tox suite cannot run).

Merge type

  • Squash merge using "Proposed Commit Message"
  • Rebase and merge unique commits. Requires commit messages per-commit each referencing the pull request number (#<PR_NUM>)

@blackboxsw blackboxsw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @anujsingh-cse for continuing to help on the type annotations front.
Some things we would like to keep in mind is that we are not just silencing type warnings via ignore. We are looking to improve the typing coverage throughout the file by adding type annotations to all public and private methods, inputs and return values, and avoid type limiting where possible. Some helpful additional guidance is on 5445 to help make this a more helpful contribution to upstream.

@anujsingh-cse

Copy link
Copy Markdown
Contributor Author

Follow-up in 7ff25f8: every method in the module is now annotated, per the GH-5445 guidance on the linked comment.

Coverage and types:

  • All 18 NMConnection methods plus the Renderer class and all four module functions (nm_conn_filename, sysconfig_conn_filename, conn_filename, cloud_init_nm_conf_filename, available).
  • Concrete types: section/option/value are str; _get_config_option -> Optional[str]; _config_option_is_set/valid -> bool; dump/con_uuid -> str; mac_addr(addr: str) -> str; Renderer.connections: Dict[str, NMConnection]; get_conn -> NMConnection; con_ref -> str; render_network_state(..., templates: Optional[Dict[str, str]], target: Optional[str]) matching the base Renderer; filename helpers (str, Optional[str]) -> str with conn_filename -> Optional[str; available() -> bool.
  • The only remaining Any is in Dict[str, Any] for the NetworkState iface/subnet/route payloads — those dicts have no concrete upstream types until cloudinit.net.network_state itself gains coverage (it is still on the override list); this is the honest current type rather than a convenience Any.
  • No asserts or casts. The optionxform assignment retains the documented-ignore comment from the previous review round.

mypy is clean with the override removed, ruff/black/isort pass, pylint is 10.00/10, and the network-manager-related suites pass (7/7 in test_network_manager.py; 15/15 across the nm-keyed net tests).

Removing cloudinit.net.network_manager from the mypy override list in
pyproject.toml surfaces two errors on the same line.

__init__ assigns the builtin str as the optionxform transform, the
documented configparser idiom for preserving option name case. mypy
cannot express assigning a class to a method, so it is ignored with a
comment explaining why, matching the comment added in
cloudinit/sources/helpers/vmware/imc/config_file.py.

Refs canonicalGH-5445
Follows the canonicalGH-5445 review guidance: full annotation coverage of the
module, not only the errors check_untyped_defs surfaced.

Every NMConnection method, the Renderer class, and all four module
functions are now typed. Concrete types throughout:

- section/option/value parameters are str; _get_config_option returns
  Optional[str] (None when unset); _config_option_is_set and valid
  return bool; dump and con_uuid return str.
- family/subnet/iface/route parameters are Dict[str, Any] — the honest
  type of the dict-based NetworkState payloads until network_state
  itself gains coverage; subnet_type is Optional[str].
- Renderer.connections is declared Dict[str, NMConnection]; get_conn
  returns NMConnection and con_ref returns str (the UUID, or the
  caller's id when the connection is unknown).
- render_network_state's templates are Optional[Dict[str, str]] and
  target Optional[str], matching the base Renderer signature.
- The filename helpers are (str, Optional[str]) -> str, except
  conn_filename -> Optional[str], and available() -> bool.
- mac_addr is (str) -> str.

The optionxform assignment keeps the documented-ignore comment from
the earlier review round. No asserts, casts, or added Any beyond the
network-state dict payloads.

Refs canonicalGH-5445
canonical#6958 added base64 error-message parameters to
test_azure_helper.py with implicitly concatenated strings inside
collection literals, which the pinned ruff flags as ISC004. CI for
every open PR runs against the merge ref, so this fails check_format
across the board. Wrap the two concatenations in parentheses; the
string values are unchanged.
@anujsingh-cse
anujsingh-cse force-pushed the fix/untyped-defs-network-manager-5445 branch from 7ff25f8 to 6ca403a Compare October 13, 2026 18:48
@anujsingh-cse

Copy link
Copy Markdown
Contributor Author

The PR: Lint failure on this head was the ISC004 regression #6958 introduced to main (test_azure_helper.py implicit string concatenation), inherited by every merge-ref CI run.

Branch rebased onto current main (which brings #7083 and the #6958 lines) and the identical parenthesization from #7098/#7148 carried in 6ca403a, so check_format is green on the merge-ref; it becomes a no-op once either of those merges.

Re-verified on the rebased head with the pinned toolchain: ruff check . passes on the whole tree, mypy clean for cloudinit/net/network_manager.py, black/isort clean, and all 7 network-manager tests pass.

net_convert builds the renderer from distro.renderer_configs, whose
values are MutableMapping[str, Any] (the base Distro declaration), so
the Dict[str, Any] parameter rejected the real caller payload under
the full-tree mypy run.
@anujsingh-cse

Copy link
Copy Markdown
Contributor Author

The follow-up check_format run surfaced one more real error from the annotation coverage, now fixed in 1c7855a: net_convert.py constructs every renderer from distro.renderer_configs, whose values are MutableMapping[str, Any] per the base Distro declaration, so the Dict[str, Any] parameter type rejected the actual caller payload under the full-tree mypy. The Renderer config parameter now takes Optional[MutableMapping[str, Any]] — the honest type of what callers pass.

Full-tree mypy on the rebased head is clean for this module and the caller (the remaining local errors are the pre-existing platform-dependent ones on this Windows sandbox, unchanged from untouched main), ruff/black/isort pass, and all 7 network-manager tests pass.

@nryanl nryanl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nryanl nryanl added the incomplete Action required by submitter label Oct 19, 2026
@anujsingh-cse

Copy link
Copy Markdown
Contributor Author

Rebased onto current main by merge — head 11165cd, no force-push after review. The duplicate tests/unittests/sources/test_azure_helper.py change is gone (empty diff against main; main carries the parenthesization from #7157).

Every method and module function in network_manager.py is annotated with concrete types (con_id: str, subnet_type: Optional[str], mac_addr(addr: str) -> str, render_network_state(..., templates: Optional[Dict[str, str]], target: Optional[str]), available() -> bool). Any remains only where the payload is genuinely heterogeneous:

  • subnet/route/iface: Dict[str, Any] — entries of a parsed network-state config whose keys and value types differ per interface/route;
  • Renderer.__init__(config: Optional[MutableMapping[str, Any]]) — net_convert.py builds renderers from distro.renderer_configs, declared Mapping[str, MutableMapping[str, Any]] in the base Distro; a Dict[str, Any] parameter rejected that caller under full-tree mypy, so the parameter now takes the type callers actually pass.

The optionxform = str assignment carries the same documented type: ignore [method-assign, assignment] as #7098, with the configparser idiom explained in-line.

Gates on this head: black 26.5.1, ruff and mypy clean; all 7 test_network_manager tests pass. The fresh CI runs will need approval to start.

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

Labels

incomplete Action required by submitter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants