mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-04-19 10:47:15 +00:00
Update Python to 3.13 (#5564)
* Bump Supervisor to Python 3.13 * Update ruff configuration to 0.9.1 Adjust pyproject.toml for ruff 0.9.1. Also make sure that latest version of ruff is used in pre-commit. * Set default configuration for pytest-asyncio * Run ruff check * Drop deprecated decorator no_type_check_decorator The upstream PR (https://github.com/python/cpython/issues/106309) says this never got really implemented by type checkers. * Bump devcontainer to latest release
This commit is contained in:
parent
fff3bfd01e
commit
b7412b0679
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Supervisor dev",
|
||||
"image": "ghcr.io/home-assistant/devcontainer:supervisor",
|
||||
"image": "ghcr.io/home-assistant/devcontainer:2-supervisor",
|
||||
"containerEnv": {
|
||||
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
||||
},
|
||||
@ -44,5 +44,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"mounts": ["type=volume,target=/var/lib/docker"]
|
||||
"mounts": [
|
||||
"type=volume,target=/var/lib/docker",
|
||||
"type=volume,target=/mnt/supervisor"
|
||||
]
|
||||
}
|
||||
|
2
.github/workflows/builder.yml
vendored
2
.github/workflows/builder.yml
vendored
@ -33,7 +33,7 @@ on:
|
||||
- setup.py
|
||||
|
||||
env:
|
||||
DEFAULT_PYTHON: "3.12"
|
||||
DEFAULT_PYTHON: "3.13"
|
||||
BUILD_NAME: supervisor
|
||||
BUILD_TYPE: supervisor
|
||||
|
||||
|
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -8,7 +8,7 @@ on:
|
||||
pull_request: ~
|
||||
|
||||
env:
|
||||
DEFAULT_PYTHON: "3.12"
|
||||
DEFAULT_PYTHON: "3.13"
|
||||
PRE_COMMIT_CACHE: ~/.cache/pre-commit
|
||||
|
||||
concurrency:
|
||||
|
@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.5.7
|
||||
rev: v0.9.1
|
||||
hooks:
|
||||
- id: ruff
|
||||
args:
|
||||
@ -8,7 +8,7 @@ repos:
|
||||
- id: ruff-format
|
||||
files: ^((supervisor|tests)/.+)?[^/]+\.py$
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.5.0
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: check-executables-have-shebangs
|
||||
stages: [manual]
|
||||
|
10
build.yaml
10
build.yaml
@ -1,10 +1,10 @@
|
||||
image: ghcr.io/home-assistant/{arch}-hassio-supervisor
|
||||
build_from:
|
||||
aarch64: ghcr.io/home-assistant/aarch64-base-python:3.12-alpine3.20
|
||||
armhf: ghcr.io/home-assistant/armhf-base-python:3.12-alpine3.20
|
||||
armv7: ghcr.io/home-assistant/armv7-base-python:3.12-alpine3.20
|
||||
amd64: ghcr.io/home-assistant/amd64-base-python:3.12-alpine3.20
|
||||
i386: ghcr.io/home-assistant/i386-base-python:3.12-alpine3.20
|
||||
aarch64: ghcr.io/home-assistant/aarch64-base-python:3.13-alpine3.21
|
||||
armhf: ghcr.io/home-assistant/armhf-base-python:3.13-alpine3.21
|
||||
armv7: ghcr.io/home-assistant/armv7-base-python:3.13-alpine3.21
|
||||
amd64: ghcr.io/home-assistant/amd64-base-python:3.13-alpine3.21
|
||||
i386: ghcr.io/home-assistant/i386-base-python:3.13-alpine3.21
|
||||
codenotary:
|
||||
signer: notary@home-assistant.io
|
||||
base_image: notary@home-assistant.io
|
||||
|
@ -12,7 +12,7 @@ authors = [
|
||||
{ name = "The Home Assistant Authors", email = "hello@home-assistant.io" },
|
||||
]
|
||||
keywords = ["docker", "home-assistant", "api"]
|
||||
requires-python = ">=3.12.0"
|
||||
requires-python = ">=3.13.0"
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://www.home-assistant.io/"
|
||||
@ -31,7 +31,7 @@ include-package-data = true
|
||||
include = ["supervisor*"]
|
||||
|
||||
[tool.pylint.MAIN]
|
||||
py-version = "3.12"
|
||||
py-version = "3.13"
|
||||
# Use a conservative default here; 2 should speed up most setups and not hurt
|
||||
# any too bad. Override on command line as appropriate.
|
||||
jobs = 2
|
||||
@ -147,7 +147,7 @@ disable = [
|
||||
# "pointless-statement", # B018, ruff catches new occurrences, needs more work
|
||||
"raise-missing-from", # TRY200
|
||||
# "redefined-builtin", # A001, ruff is way more stricter, needs work
|
||||
"try-except-raise", # TRY302
|
||||
"try-except-raise", # TRY203
|
||||
"unused-argument", # ARG001, we don't use it
|
||||
"unused-format-string-argument", #F507
|
||||
"unused-format-string-key", # F504
|
||||
@ -223,6 +223,7 @@ testpaths = ["tests"]
|
||||
norecursedirs = [".git"]
|
||||
log_format = "%(asctime)s.%(msecs)03d %(levelname)-8s %(threadName)s %(name)s:%(filename)s:%(lineno)s %(message)s"
|
||||
log_date_format = "%Y-%m-%d %H:%M:%S"
|
||||
asyncio_default_fixture_loop_scope = "function"
|
||||
asyncio_mode = "auto"
|
||||
filterwarnings = [
|
||||
"error",
|
||||
@ -289,7 +290,7 @@ lint.select = [
|
||||
"T20", # flake8-print
|
||||
"TID251", # Banned imports
|
||||
"TRY004", # Prefer TypeError exception for invalid type
|
||||
"TRY302", # Remove exception handler; error is immediately re-raised
|
||||
"TRY203", # Remove exception handler; error is immediately re-raised
|
||||
"UP", # pyupgrade
|
||||
"W", # pycodestyle
|
||||
]
|
||||
|
@ -3,7 +3,7 @@ coverage==7.6.10
|
||||
pre-commit==4.1.0
|
||||
pylint==3.3.3
|
||||
pytest-aiohttp==1.0.5
|
||||
pytest-asyncio==0.23.6
|
||||
pytest-asyncio==0.25.2
|
||||
pytest-cov==6.0.0
|
||||
pytest-timeout==2.3.1
|
||||
pytest==8.3.4
|
||||
|
@ -239,12 +239,12 @@ class APIHost(CoreSysAttributes):
|
||||
# return 2 lines at minimum.
|
||||
lines = max(2, lines)
|
||||
# entries=cursor[[:num_skip]:num_entries]
|
||||
range_header = f"entries=:-{lines-1}:{'' if follow else lines}"
|
||||
range_header = f"entries=:-{lines - 1}:{'' if follow else lines}"
|
||||
elif RANGE in request.headers:
|
||||
range_header = request.headers.get(RANGE)
|
||||
else:
|
||||
range_header = (
|
||||
f"entries=:-{DEFAULT_LINES-1}:{'' if follow else DEFAULT_LINES}"
|
||||
f"entries=:-{DEFAULT_LINES - 1}:{'' if follow else DEFAULT_LINES}"
|
||||
)
|
||||
|
||||
async with self.sys_host.logs.journald_logs(
|
||||
|
@ -61,7 +61,7 @@ def journal_verbose_formatter(entries: dict[str, str]) -> str:
|
||||
|
||||
async def journal_logs_reader(
|
||||
journal_logs: ClientResponse, log_formatter: LogFormatter = LogFormatter.PLAIN
|
||||
) -> AsyncGenerator[(str | None, str), None]:
|
||||
) -> AsyncGenerator[str | None, str]:
|
||||
"""Read logs from systemd journal line by line, formatted using the given formatter.
|
||||
|
||||
Returns a generator of (cursor, formatted_entry) tuples.
|
||||
|
@ -18,7 +18,7 @@ from supervisor.api.proxy import APIProxy
|
||||
from supervisor.const import ATTR_ACCESS_TOKEN
|
||||
|
||||
|
||||
def id_generator() -> Generator[int, None, None]:
|
||||
def id_generator() -> Generator[int]:
|
||||
"""Generate IDs for WS messages."""
|
||||
i = 0
|
||||
while True:
|
||||
|
@ -117,7 +117,7 @@ async def docker() -> DockerAPI:
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def dbus_session() -> Generator[str, None, None]:
|
||||
def dbus_session() -> Generator[str]:
|
||||
"""Start a dbus session.
|
||||
|
||||
Returns session address.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
from functools import wraps
|
||||
from typing import Any, no_type_check_decorator
|
||||
from typing import Any
|
||||
|
||||
from dbus_fast import Message
|
||||
from dbus_fast.aio.message_bus import MessageBus
|
||||
@ -51,7 +51,6 @@ def dbus_method(name: str = None, disabled: bool = False, track_obj_path: bool =
|
||||
"""
|
||||
orig_decorator = method(name=name, disabled=disabled)
|
||||
|
||||
@no_type_check_decorator
|
||||
def decorator(func):
|
||||
calls: list[list[Any]] = []
|
||||
|
||||
|
@ -50,9 +50,9 @@ def test_format_verbose_timestamp():
|
||||
"MESSAGE": "x",
|
||||
}
|
||||
formatted = journal_verbose_formatter(fields)
|
||||
assert formatted.startswith(
|
||||
"1970-01-01 00:00:00.001 "
|
||||
), f"Invalid log timestamp: {formatted}"
|
||||
assert formatted.startswith("1970-01-01 00:00:00.001 "), (
|
||||
f"Invalid log timestamp: {formatted}"
|
||||
)
|
||||
|
||||
|
||||
def test_format_verbose():
|
||||
@ -143,10 +143,7 @@ async def test_parsing_two_messages():
|
||||
"""Test reading multiple messages."""
|
||||
journal_logs, stream = _journal_logs_mock()
|
||||
stream.feed_data(
|
||||
b"MESSAGE=Hello, world!\n"
|
||||
b"ID=1\n\n"
|
||||
b"MESSAGE=Hello again, world!\n"
|
||||
b"ID=2\n\n"
|
||||
b"MESSAGE=Hello, world!\nID=1\n\nMESSAGE=Hello again, world!\nID=2\n\n"
|
||||
)
|
||||
stream.feed_eof()
|
||||
|
||||
@ -184,9 +181,7 @@ async def test_parsing_malformed_binary_message():
|
||||
"""Test that malformed binary message raises MalformedBinaryEntryError."""
|
||||
journal_logs, stream = _journal_logs_mock()
|
||||
stream.feed_data(
|
||||
b"ID=1\n"
|
||||
b"MESSAGE\n\x0d\x00\x00\x00\x00\x00\x00\x00Hello, world!"
|
||||
b"AFTER=after\n\n"
|
||||
b"ID=1\nMESSAGE\n\x0d\x00\x00\x00\x00\x00\x00\x00Hello, world!AFTER=after\n\n"
|
||||
)
|
||||
|
||||
with pytest.raises(MalformedBinaryEntryError):
|
||||
|
Loading…
x
Reference in New Issue
Block a user