chore: Python 3.12 is the floor (NAPALM/driver-standard#6) #56

Merged
christianmanivong merged 2 commits from chore/python-312-floor into main 2026-10-27 10:19:38 +00:00
6 changed files with 18 additions and 16 deletions

No files matched your search

+6
View File
@@ -7,6 +7,12 @@ recorded here; their history is the git log.
## [Unreleased]
### Changed
- Python 3.12 is the floor (`requires-python = ">=3.12"`): netOrk runs every driver
on 3.12, so 3.10 and 3.11 are no longer tested (NAPALM/driver-standard#6).
- The floor on napalm is 5.1: older releases import `pkg_resources`, which a Python
3.12 venv no longer has.
### Added
- `HostShutdownMixin.shutdown_host()`, on `DeviceTypeDriver`: shut the device itself
down cleanly through its own means; declared, so `hasattr` says whether a driver
+1 -1
View File
@@ -390,7 +390,7 @@ detection vs. presentation there.
pip install napalm-device-types
```
Requires Python ≥ 3.10 (tested up to 3.13) and NAPALM ≥ 4.0.
Requires Python ≥ 3.12 (tested up to 3.13) and NAPALM ≥ 4.0.
## Available base classes
+4 -5
View File
@@ -8,12 +8,9 @@ name a single entry, and guessing would overwrite one the caller never meant.
from __future__ import annotations
from collections.abc import Callable, Iterable
from typing import TypeVar
T = TypeVar("T")
def index_live(entries: Iterable[T], key: Callable[[T], str]) -> tuple[dict[str, T], set[str]]:
def index_live[T](entries: Iterable[T], key: Callable[[T], str]) -> tuple[dict[str, T], set[str]]:
"""Live entries by key, and the keys more than one of them holds.
Entries without a key are left out: they are not the caller's to match.
@@ -32,7 +29,9 @@ def index_live(entries: Iterable[T], key: Callable[[T], str]) -> tuple[dict[str,
return by_key, shared
def check_desired(entries: list[T], key: Callable[[T], str], shared: set[str], what: str) -> None:
def check_desired[T](
entries: list[T], key: Callable[[T], str], shared: set[str], what: str
) -> None:
"""``ValueError`` for a desired entry with no key, a key given twice, or a
key that names more than one live entry."""
seen: set[str] = set()
+2 -2
View File
@@ -5,9 +5,9 @@ These supplement the types defined in napalm.base.models and are used by the
abstract device-type driver classes in this package.
"""
from typing import Literal, get_args
from typing import Literal, NotRequired, get_args
from typing_extensions import NotRequired, TypedDict
from typing_extensions import TypedDict
# ---------------------------------------------------------------------------
# Common (shared across device types)
+4 -6
View File
@@ -7,7 +7,7 @@ name = "napalm-device-types"
version = "4.22.0"
description = "Abstract device-type base classes for NAPALM drivers"
readme = "README.md"
requires-python = ">=3.10"
requires-python = ">=3.12"
license = "Apache-2.0"
authors = [
{ name = "Christian Manivong", email = "christian@manivong.de" },
@@ -30,8 +30,6 @@ classifiers = [
"Intended Audience :: System Administrators",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: System :: Networking",
@@ -39,7 +37,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"napalm>=4.0",
"napalm>=5.1", # older releases import pkg_resources, which a 3.12 venv lacks
"typing-extensions>=4.0",
]
@@ -65,7 +63,7 @@ napalm_device_types = ["py.typed"]
[tool.ruff]
line-length = 100
target-version = "py310"
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]
@@ -75,7 +73,7 @@ select = ["E", "F", "I", "UP", "B"]
"tests/**" = ["E501"]
[tool.mypy]
python_version = "3.10"
python_version = "3.12"
strict = true
ignore_missing_imports = true
+1 -2
View File
@@ -30,8 +30,7 @@ def test_a_missing_license_may_say_what_the_device_withholds_without_it():
# A Supermicro X10 with only SFT-OOB-LIC answers Redfish but keeps its drives and
# firmware inventory until DCMS is activated: partly licensed, not unlicensed.
hints = get_type_hints(LicenseDict)
# Python 3.10 keeps NotRequired[...] around the type; later versions strip it.
assert "list[str]" in str(hints["withholds"])
assert hints["withholds"] == list[str]
assert "withholds" not in LicenseDict.__required_keys__