mirror of
https://github.com/python-kasa/python-kasa.git
synced 2026-07-08 06:41:59 +00:00
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 --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [3.13]
|
python-version: [3.14]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Source Files
|
- name: Checkout Source Files
|
||||||
id: checkout
|
id: checkout
|
||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
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]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
extras: [false, true]
|
extras: [false, true]
|
||||||
exclude:
|
exclude:
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ repos:
|
|||||||
|
|
||||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||||
# uv version.
|
# uv version.
|
||||||
rev: 0.5.30
|
rev: 0.9.5
|
||||||
hooks:
|
hooks:
|
||||||
# Update the uv lockfile
|
# Update the uv lockfile
|
||||||
- id: uv-lock
|
- id: uv-lock
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v5.0.0
|
rev: v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
@@ -22,14 +22,14 @@ repos:
|
|||||||
- "--indent=4"
|
- "--indent=4"
|
||||||
|
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.9.6
|
rev: v0.14.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: [--fix, --exit-non-zero-on-fix]
|
args: [--fix, --exit-non-zero-on-fix]
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/doc8
|
- repo: https://github.com/PyCQA/doc8
|
||||||
rev: 'v1.1.2'
|
rev: 'v2.0.0'
|
||||||
hooks:
|
hooks:
|
||||||
- id: doc8
|
- id: doc8
|
||||||
additional_dependencies: [tomli]
|
additional_dependencies: [tomli]
|
||||||
|
|||||||
@@ -11,12 +11,8 @@ build:
|
|||||||
tools:
|
tools:
|
||||||
python: "3"
|
python: "3"
|
||||||
jobs:
|
jobs:
|
||||||
|
install:
|
||||||
|
- pip install --upgrade pip
|
||||||
|
- pip install --group 'docs'
|
||||||
pre_build:
|
pre_build:
|
||||||
- python -m sphinx -b linkcheck docs/source/ $READTHEDOCS_OUTPUT/linkcheck
|
- python -m sphinx -b linkcheck docs/source/ $READTHEDOCS_OUTPUT/linkcheck
|
||||||
|
|
||||||
python:
|
|
||||||
install:
|
|
||||||
- method: pip
|
|
||||||
path: .
|
|
||||||
extra_requirements:
|
|
||||||
- docs
|
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ async def handle_device(
|
|||||||
if autosave:
|
if autosave:
|
||||||
save = "y"
|
save = "y"
|
||||||
else:
|
else:
|
||||||
save = click.prompt(
|
save = await click.prompt(
|
||||||
f"Do you want to save the above content to {save_filename} (y/n)"
|
f"Do you want to save the above content to {save_filename} (y/n)"
|
||||||
)
|
)
|
||||||
if save == "y":
|
if save == "y":
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ def json_formatter_cb(result: Any, **kwargs) -> None:
|
|||||||
|
|
||||||
|
|
||||||
async def invoke_subcommand(
|
async def invoke_subcommand(
|
||||||
command: click.BaseCommand,
|
command: click.Command,
|
||||||
ctx: click.Context,
|
ctx: click.Context,
|
||||||
args: list[str] | None = None,
|
args: list[str] | None = None,
|
||||||
**extra: Any,
|
**extra: Any,
|
||||||
@@ -200,7 +200,7 @@ async def _get_child_device(
|
|||||||
if child_option is not None:
|
if child_option is not None:
|
||||||
if child_option is OPTIONAL_VALUE_FLAG:
|
if child_option is OPTIONAL_VALUE_FLAG:
|
||||||
msg = _list_children()
|
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",
|
f"\n{msg}\nEnter the index number of the child device",
|
||||||
type=click.IntRange(0, len(device.children) - 1),
|
type=click.IntRange(0, len(device.children) - 1),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ async def shell(dev: Device) -> None:
|
|||||||
@click.argument("parameters", default=None, required=False)
|
@click.argument("parameters", default=None, required=False)
|
||||||
async def raw_command(ctx, module, command, parameters):
|
async def raw_command(ctx, module, command, parameters):
|
||||||
"""Run a raw command on the device."""
|
"""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)
|
return await ctx.forward(cmd_command)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -746,6 +746,8 @@ class Discover:
|
|||||||
device = device_class(config.host, config=config)
|
device = device_class(config.host, config=config)
|
||||||
sys_info = _extract_sys_info(info)
|
sys_info = _extract_sys_info(info)
|
||||||
device_type = sys_info.get("mic_type", sys_info.get("type"))
|
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 = (
|
login_version = (
|
||||||
sys_info.get("stream_version") if device_type == "IOT.IPCAMERA" else None
|
sys_info.get("stream_version") if device_type == "IOT.IPCAMERA" else None
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from warnings import warn
|
|||||||
from ..device import Device, DeviceInfo, WifiNetwork
|
from ..device import Device, DeviceInfo, WifiNetwork
|
||||||
from ..device_type import DeviceType
|
from ..device_type import DeviceType
|
||||||
from ..deviceconfig import DeviceConfig
|
from ..deviceconfig import DeviceConfig
|
||||||
from ..exceptions import KasaException
|
from ..exceptions import KasaException, UnsupportedDeviceError
|
||||||
from ..feature import Feature
|
from ..feature import Feature
|
||||||
from ..module import Module
|
from ..module import Module
|
||||||
from ..modulemapping import ModuleMapping, ModuleName
|
from ..modulemapping import ModuleMapping, ModuleName
|
||||||
@@ -763,6 +763,9 @@ class IotDevice(Device):
|
|||||||
|
|
||||||
# Get other info
|
# Get other info
|
||||||
device_family = sys_info.get("type", sys_info.get("mic_type"))
|
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)
|
device_type = IotDevice._get_device_type_from_sys_info(info)
|
||||||
fw_version_full = sys_info["sw_ver"]
|
fw_version_full = sys_info["sw_ver"]
|
||||||
if " " in fw_version_full:
|
if " " in fw_version_full:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ dependencies = [
|
|||||||
"cryptography>=1.9",
|
"cryptography>=1.9",
|
||||||
"aiohttp>=3",
|
"aiohttp>=3",
|
||||||
"tzdata>=2024.2 ; platform_system == 'Windows'",
|
"tzdata>=2024.2 ; platform_system == 'Windows'",
|
||||||
"mashumaro>=3.14",
|
"mashumaro>=3.20"
|
||||||
]
|
]
|
||||||
|
|
||||||
classifiers = [
|
classifiers = [
|
||||||
@@ -21,17 +21,11 @@ classifiers = [
|
|||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: 3.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
speedups = ["orjson>=3.9.1", "kasa-crypt>=0.2.0"]
|
speedups = ["orjson>=3.11.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",
|
|
||||||
]
|
|
||||||
shell = ["ptpython", "rich"]
|
shell = ["ptpython", "rich"]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
@@ -43,8 +37,8 @@ shell = ["ptpython", "rich"]
|
|||||||
[project.scripts]
|
[project.scripts]
|
||||||
kasa = "kasa.cli.__main__:cli"
|
kasa = "kasa.cli.__main__:cli"
|
||||||
|
|
||||||
[tool.uv]
|
[dependency-groups]
|
||||||
dev-dependencies = [
|
dev = [
|
||||||
"pytest",
|
"pytest",
|
||||||
"pytest-cov",
|
"pytest-cov",
|
||||||
"pytest-asyncio",
|
"pytest-asyncio",
|
||||||
@@ -64,7 +58,13 @@ dev-dependencies = [
|
|||||||
"ruff>=0.9.0",
|
"ruff>=0.9.0",
|
||||||
"uv>=0.11.26",
|
"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]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import aiohttp
|
|||||||
import pytest
|
import pytest
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric import padding as asymmetric_padding
|
from cryptography.hazmat.primitives.asymmetric import padding as asymmetric_padding
|
||||||
|
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
|
||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
from yarl import URL
|
from yarl import URL
|
||||||
|
|
||||||
@@ -501,6 +502,7 @@ class MockAesDevice:
|
|||||||
|
|
||||||
client_pub_key_data = base64.b64decode(client_pub_key.encode())
|
client_pub_key_data = base64.b64decode(client_pub_key.encode())
|
||||||
client_pub_key = serialization.load_der_public_key(client_pub_key_data, None)
|
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())
|
encrypted_key = client_pub_key.encrypt(KEY_IV, asymmetric_padding.PKCS1v15())
|
||||||
key_64 = base64.b64encode(encrypted_key).decode()
|
key_64 = base64.b64encode(encrypted_key).decode()
|
||||||
return self._mock_response(
|
return self._mock_response(
|
||||||
|
|||||||
Reference in New Issue
Block a user