Add python 3.14 to supported versions (#1599)

* Add python 3.14 to our supported versions and to our CI
* Convert to use pyproject.toml standard dependency groups
* Fix any issues reported by CI
This commit is contained in:
Teemu R.
2026-07-07 20:46:57 +02:00
committed by GitHub
parent 531be8437a
commit 8840fc395e
11 changed files with 1488 additions and 895 deletions

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.13]
python-version: [3.14]
steps:
- name: Checkout Source Files
id: checkout
@@ -51,7 +51,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: [3.11, 3.12, 3.13]
python-version: [3.11, 3.12, 3.13, 3.14]
os: [ubuntu-latest, macos-latest, windows-latest]
extras: [false, true]
exclude:

View File

@@ -2,13 +2,13 @@ repos:
- repo: https://github.com/astral-sh/uv-pre-commit
# uv version.
rev: 0.5.30
rev: 0.9.5
hooks:
# Update the uv lockfile
- id: uv-lock
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -22,14 +22,14 @@ repos:
- "--indent=4"
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.6
rev: v0.14.2
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/PyCQA/doc8
rev: 'v1.1.2'
rev: 'v2.0.0'
hooks:
- id: doc8
additional_dependencies: [tomli]

View File

@@ -11,12 +11,8 @@ build:
tools:
python: "3"
jobs:
install:
- pip install --upgrade pip
- pip install --group 'docs'
pre_build:
- python -m sphinx -b linkcheck docs/source/ $READTHEDOCS_OUTPUT/linkcheck
python:
install:
- method: pip
path: .
extra_requirements:
- docs

View File

@@ -166,7 +166,7 @@ async def handle_device(
if autosave:
save = "y"
else:
save = click.prompt(
save = await click.prompt(
f"Do you want to save the above content to {save_filename} (y/n)"
)
if save == "y":

View File

@@ -96,7 +96,7 @@ def json_formatter_cb(result: Any, **kwargs) -> None:
async def invoke_subcommand(
command: click.BaseCommand,
command: click.Command,
ctx: click.Context,
args: list[str] | None = None,
**extra: Any,
@@ -200,7 +200,7 @@ async def _get_child_device(
if child_option is not None:
if child_option is OPTIONAL_VALUE_FLAG:
msg = _list_children()
child_index_option = click.prompt(
child_index_option = await click.prompt(
f"\n{msg}\nEnter the index number of the child device",
type=click.IntRange(0, len(device.children) - 1),
)

View File

@@ -414,7 +414,7 @@ async def shell(dev: Device) -> None:
@click.argument("parameters", default=None, required=False)
async def raw_command(ctx, module, command, parameters):
"""Run a raw command on the device."""
logging.warning("Deprecated, use 'kasa command --module %s %s'", module, command)
logging.warning("Deprecated, use 'kasa command --module %s %s'", module, command) # noqa: LOG015
return await ctx.forward(cmd_command)

View File

@@ -746,6 +746,8 @@ class Discover:
device = device_class(config.host, config=config)
sys_info = _extract_sys_info(info)
device_type = sys_info.get("mic_type", sys_info.get("type"))
if device_type is None:
raise UnsupportedDeviceError("type nor mic_type found in sysinfo response")
login_version = (
sys_info.get("stream_version") if device_type == "IOT.IPCAMERA" else None
)

View File

@@ -25,7 +25,7 @@ from warnings import warn
from ..device import Device, DeviceInfo, WifiNetwork
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..exceptions import KasaException
from ..exceptions import KasaException, UnsupportedDeviceError
from ..feature import Feature
from ..module import Module
from ..modulemapping import ModuleMapping, ModuleName
@@ -763,6 +763,9 @@ class IotDevice(Device):
# Get other info
device_family = sys_info.get("type", sys_info.get("mic_type"))
if device_family is None:
raise UnsupportedDeviceError("type nor mic_type found in sysinfo response")
device_type = IotDevice._get_device_type_from_sys_info(info)
fw_version_full = sys_info["sw_ver"]
if " " in fw_version_full:

View File

@@ -11,7 +11,7 @@ dependencies = [
"cryptography>=1.9",
"aiohttp>=3",
"tzdata>=2024.2 ; platform_system == 'Windows'",
"mashumaro>=3.14",
"mashumaro>=3.20"
]
classifiers = [
@@ -21,17 +21,11 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]
[project.optional-dependencies]
speedups = ["orjson>=3.9.1", "kasa-crypt>=0.2.0"]
docs = [
"sphinx_rtd_theme~=2.0",
"sphinxcontrib-programoutput~=0.0",
"myst-parser",
"docutils>=0.17",
"sphinx>=7.4.7",
]
speedups = ["orjson>=3.11.1", "kasa-crypt>=0.2.0"]
shell = ["ptpython", "rich"]
[project.urls]
@@ -43,8 +37,8 @@ shell = ["ptpython", "rich"]
[project.scripts]
kasa = "kasa.cli.__main__:cli"
[tool.uv]
dev-dependencies = [
[dependency-groups]
dev = [
"pytest",
"pytest-cov",
"pytest-asyncio",
@@ -64,7 +58,13 @@ dev-dependencies = [
"ruff>=0.9.0",
"uv>=0.11.26",
]
docs = [
"sphinx_rtd_theme~=2.0",
"sphinxcontrib-programoutput~=0.0",
"myst-parser",
"docutils>=0.17",
"sphinx>=7.4.7",
]
[build-system]
requires = ["hatchling"]

View File

@@ -15,6 +15,7 @@ import aiohttp
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding as asymmetric_padding
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
from freezegun.api import FrozenDateTimeFactory
from yarl import URL
@@ -501,6 +502,7 @@ class MockAesDevice:
client_pub_key_data = base64.b64decode(client_pub_key.encode())
client_pub_key = serialization.load_der_public_key(client_pub_key_data, None)
assert isinstance(client_pub_key, RSAPublicKey)
encrypted_key = client_pub_key.encrypt(KEY_IV, asymmetric_padding.PKCS1v15())
key_64 = base64.b64encode(encrypted_key).decode()
return self._mock_response(

2320
uv.lock generated

File diff suppressed because it is too large Load Diff