Update to python 3.11 (#4296)

This commit is contained in:
Mike Degatano 2023-05-22 13:12:34 -04:00 committed by GitHub
parent 61a7e6a87d
commit 5ced4e2f3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 132 additions and 31 deletions

View File

@ -33,12 +33,12 @@ on:
- setup.py - setup.py
env: env:
DEFAULT_PYTHON: "3.10" DEFAULT_PYTHON: "3.11"
BUILD_NAME: supervisor BUILD_NAME: supervisor
BUILD_TYPE: supervisor BUILD_TYPE: supervisor
concurrency: concurrency:
group: '${{ github.workflow }}-${{ github.ref }}' group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
@ -104,7 +104,7 @@ jobs:
if: needs.init.outputs.requirements == 'true' if: needs.init.outputs.requirements == 'true'
uses: home-assistant/wheels@2023.04.0 uses: home-assistant/wheels@2023.04.0
with: with:
abi: cp310 abi: cp311
tag: musllinux_1_2 tag: musllinux_1_2
arch: ${{ matrix.arch }} arch: ${{ matrix.arch }}
wheels-key: ${{ secrets.WHEELS_KEY }} wheels-key: ${{ secrets.WHEELS_KEY }}

View File

@ -8,7 +8,7 @@ on:
pull_request: ~ pull_request: ~
env: env:
DEFAULT_PYTHON: "3.10" DEFAULT_PYTHON: "3.11"
PRE_COMMIT_HOME: ~/.cache/pre-commit PRE_COMMIT_HOME: ~/.cache/pre-commit
DEFAULT_CAS: v1.0.2 DEFAULT_CAS: v1.0.2

View File

@ -1,11 +1,11 @@
image: homeassistant/{arch}-hassio-supervisor image: homeassistant/{arch}-hassio-supervisor
shadow_repository: ghcr.io/home-assistant shadow_repository: ghcr.io/home-assistant
build_from: build_from:
aarch64: ghcr.io/home-assistant/aarch64-base-python:3.10-alpine3.16 aarch64: ghcr.io/home-assistant/aarch64-base-python:3.11-alpine3.16
armhf: ghcr.io/home-assistant/armhf-base-python:3.10-alpine3.16 armhf: ghcr.io/home-assistant/armhf-base-python:3.11-alpine3.16
armv7: ghcr.io/home-assistant/armv7-base-python:3.10-alpine3.16 armv7: ghcr.io/home-assistant/armv7-base-python:3.11-alpine3.16
amd64: ghcr.io/home-assistant/amd64-base-python:3.10-alpine3.16 amd64: ghcr.io/home-assistant/amd64-base-python:3.11-alpine3.16
i386: ghcr.io/home-assistant/i386-base-python:3.10-alpine3.16 i386: ghcr.io/home-assistant/i386-base-python:3.11-alpine3.16
codenotary: codenotary:
signer: notary@home-assistant.io signer: notary@home-assistant.io
base_image: notary@home-assistant.io base_image: notary@home-assistant.io

View File

@ -5,7 +5,6 @@ atomicwrites-homeassistant==1.4.1
attrs==23.1.0 attrs==23.1.0
awesomeversion==23.5.0 awesomeversion==23.5.0
brotli==1.0.9 brotli==1.0.9
cchardet==2.1.7
ciso8601==2.3.0 ciso8601==2.3.0
colorlog==6.7.0 colorlog==6.7.0
cpe==1.2.1 cpe==1.2.1
@ -14,6 +13,7 @@ debugpy==1.6.7
deepmerge==1.1.0 deepmerge==1.1.0
dirhash==0.2.1 dirhash==0.2.1
docker==6.1.2 docker==6.1.2
faust-cchardet==2.1.18
gitpython==3.1.31 gitpython==3.1.31
jinja2==3.1.2 jinja2==3.1.2
pulsectl==23.5.1 pulsectl==23.5.1

View File

@ -79,7 +79,7 @@ class AddonManager(CoreSysAttributes):
tasks = [] tasks = []
for slug in self.data.system: for slug in self.data.system:
addon = self.local[slug] = Addon(self.coresys, slug) addon = self.local[slug] = Addon(self.coresys, slug)
tasks.append(addon.load()) tasks.append(self.sys_create_task(addon.load()))
# Run initial tasks # Run initial tasks
_LOGGER.info("Found %d installed add-ons", len(tasks)) _LOGGER.info("Found %d installed add-ons", len(tasks))

View File

@ -148,8 +148,8 @@ class APIIngress(CoreSysAttributes):
# Proxy requests # Proxy requests
await asyncio.wait( await asyncio.wait(
[ [
_websocket_forward(ws_server, ws_client), self.sys_create_task(_websocket_forward(ws_server, ws_client)),
_websocket_forward(ws_client, ws_server), self.sys_create_task(_websocket_forward(ws_client, ws_server)),
], ],
return_when=asyncio.FIRST_COMPLETED, return_when=asyncio.FIRST_COMPLETED,
) )

View File

@ -117,7 +117,7 @@ class BackupManager(FileConfiguration, CoreSysAttributes):
self._backups[backup.slug] = backup self._backups[backup.slug] = backup
tasks = [ tasks = [
_load_backup(tar_file) self.sys_create_task(_load_backup(tar_file))
for path in self.backup_locations for path in self.backup_locations
for tar_file in path.glob("*.tar") for tar_file in path.glob("*.tar")
] ]

View File

@ -285,9 +285,12 @@ class Core(CoreSysAttributes):
async with async_timeout.timeout(10): async with async_timeout.timeout(10):
await asyncio.wait( await asyncio.wait(
[ [
self.sys_api.stop(), self.sys_create_task(coro)
self.sys_scheduler.shutdown(), for coro in (
self.sys_docker.unload(), self.sys_api.stop(),
self.sys_scheduler.shutdown(),
self.sys_docker.unload(),
)
] ]
) )
except asyncio.TimeoutError: except asyncio.TimeoutError:
@ -298,10 +301,13 @@ class Core(CoreSysAttributes):
async with async_timeout.timeout(10): async with async_timeout.timeout(10):
await asyncio.wait( await asyncio.wait(
[ [
self.sys_websession.close(), self.sys_create_task(coro)
self.sys_ingress.unload(), for coro in (
self.sys_hardware.unload(), self.sys_websession.close(),
self.sys_dbus.unload(), self.sys_ingress.unload(),
self.sys_hardware.unload(),
self.sys_dbus.unload(),
)
] ]
) )
except asyncio.TimeoutError: except asyncio.TimeoutError:

View File

@ -258,7 +258,12 @@ class HomeAssistant(FileConfiguration, CoreSysAttributes):
async def load(self) -> None: async def load(self) -> None:
"""Prepare Home Assistant object.""" """Prepare Home Assistant object."""
await asyncio.wait([self.secrets.load(), self.core.load()]) await asyncio.wait(
[
self.sys_create_task(self.secrets.load()),
self.sys_create_task(self.core.load()),
]
)
# Register for events # Register for events
self.sys_bus.register_event(BusEvent.HARDWARE_NEW_DEVICE, self._hardware_events) self.sys_bus.register_event(BusEvent.HARDWARE_NEW_DEVICE, self._hardware_events)

View File

@ -109,11 +109,18 @@ class MountManager(FileConfiguration, CoreSysAttributes):
# Bind all media mounts to directories in media # Bind all media mounts to directories in media
if self.media_mounts: if self.media_mounts:
await asyncio.wait([self._bind_media(mount) for mount in self.media_mounts]) await asyncio.wait(
[
self.sys_create_task(self._bind_media(mount))
for mount in self.media_mounts
]
)
async def reload(self) -> None: async def reload(self) -> None:
"""Update mounts info via dbus and reload failed mounts.""" """Update mounts info via dbus and reload failed mounts."""
await asyncio.wait([mount.update() for mount in self.mounts]) await asyncio.wait(
[self.sys_create_task(mount.update()) for mount in self.mounts]
)
# Try to reload any newly failed mounts and report issues if failure persists # Try to reload any newly failed mounts and report issues if failure persists
new_failures = [ new_failures = [

View File

@ -107,7 +107,9 @@ class PluginManager(CoreSysAttributes):
async def repair(self) -> None: async def repair(self) -> None:
"""Repair Supervisor plugins.""" """Repair Supervisor plugins."""
await asyncio.wait([plugin.repair() for plugin in self.all_plugins]) await asyncio.wait(
[self.sys_create_task(plugin.repair()) for plugin in self.all_plugins]
)
async def shutdown(self) -> None: async def shutdown(self) -> None:
"""Shutdown Supervisor plugin.""" """Shutdown Supervisor plugin."""

View File

@ -83,7 +83,7 @@ class StoreManager(CoreSysAttributes, FileConfiguration):
@Job(conditions=[JobCondition.SUPERVISOR_UPDATED], on_condition=StoreJobError) @Job(conditions=[JobCondition.SUPERVISOR_UPDATED], on_condition=StoreJobError)
async def reload(self) -> None: async def reload(self) -> None:
"""Update add-ons from repository and reload list.""" """Update add-ons from repository and reload list."""
tasks = [repository.update() for repository in self.all] tasks = [self.sys_create_task(repository.update()) for repository in self.all]
if tasks: if tasks:
await asyncio.wait(tasks) await asyncio.wait(tasks)

View File

@ -191,7 +191,7 @@ class Updater(FileConfiguration, CoreSysAttributes):
Is a coroutine. Is a coroutine.
""" """
url = URL_HASSIO_VERSION.format(channel=self.channel) url = URL_HASSIO_VERSION.format(channel=self.channel.value)
machine = self.sys_machine or "default" machine = self.sys_machine or "default"
# Get data # Get data

View File

@ -69,14 +69,14 @@ async def cas_validate(
async with async_timeout.timeout(15): async with async_timeout.timeout(15):
data, error = await proc.communicate() data, error = await proc.communicate()
except OSError as err:
raise CodeNotaryError(
f"CodeNotary fatal error: {err!s}", _LOGGER.critical
) from err
except asyncio.TimeoutError: except asyncio.TimeoutError:
raise CodeNotaryBackendError( raise CodeNotaryBackendError(
"Timeout while processing CodeNotary", _LOGGER.warning "Timeout while processing CodeNotary", _LOGGER.warning
) from None ) from None
except OSError as err:
raise CodeNotaryError(
f"CodeNotary fatal error: {err!s}", _LOGGER.critical
) from err
# Check if Notarized # Check if Notarized
if proc.returncode != 0 and not data: if proc.returncode != 0 and not data:

View File

@ -18,6 +18,7 @@ from supervisor.exceptions import (
DockerAPIError, DockerAPIError,
DockerNotFound, DockerNotFound,
) )
from supervisor.plugins.dns import PluginDns
from supervisor.utils import check_exception_chain from supervisor.utils import check_exception_chain
from tests.common import load_json_fixture from tests.common import load_json_fixture
@ -164,3 +165,20 @@ async def test_addon_uninstall_removes_discovery(
assert coresys.addons.installed == [] assert coresys.addons.installed == []
assert coresys.discovery.list_messages == [] assert coresys.discovery.list_messages == []
async def test_load(
coresys: CoreSys, install_addon_ssh: Addon, caplog: pytest.LogCaptureFixture
):
"""Test addon manager load."""
caplog.clear()
with patch.object(DockerInterface, "attach") as attach, patch.object(
PluginDns, "write_hosts"
) as write_hosts:
await coresys.addons.load()
attach.assert_called_once_with(version=AwesomeVersion("9.2.1"))
write_hosts.assert_called_once()
assert "Found 1 installed add-ons" in caplog.text

View File

@ -0,0 +1,20 @@
"""Test Homeassistant module."""
from pathlib import Path
from unittest.mock import patch
from supervisor.coresys import CoreSys
from supervisor.docker.interface import DockerInterface
async def test_load(coresys: CoreSys, tmp_supervisor_data: Path):
"""Test homeassistant module load."""
with open(tmp_supervisor_data / "homeassistant" / "secrets.yaml", "w") as secrets:
secrets.write("hello: world\n")
with patch.object(DockerInterface, "attach") as attach:
await coresys.homeassistant.load()
attach.assert_called_once()
assert coresys.homeassistant.secrets.secrets == {"hello": "world"}

View File

@ -0,0 +1,31 @@
"""Test plugin manager."""
from unittest.mock import patch
from supervisor.coresys import CoreSys
from supervisor.docker.interface import DockerInterface
def mock_awaitable_bool(value: bool):
"""Return a mock of an awaitable bool."""
async def _mock_bool(*args, **kwargs) -> bool:
return value
return _mock_bool
async def test_repair(coresys: CoreSys):
"""Test repair."""
with patch.object(DockerInterface, "install") as install:
# If instance exists, repair does nothing
with patch.object(DockerInterface, "exists", new=mock_awaitable_bool(True)):
await coresys.plugins.repair()
install.assert_not_called()
# If not, repair installs the image
with patch.object(DockerInterface, "exists", new=mock_awaitable_bool(False)):
await coresys.plugins.repair()
assert install.call_count == len(coresys.plugins.all_plugins)

View File

@ -15,6 +15,7 @@ from supervisor.exceptions import AddonsNotSupportedError, StoreJobError
from supervisor.homeassistant.module import HomeAssistant from supervisor.homeassistant.module import HomeAssistant
from supervisor.store import StoreManager from supervisor.store import StoreManager
from supervisor.store.addon import AddonStore from supervisor.store.addon import AddonStore
from supervisor.store.git import GitRepo
from supervisor.store.repository import Repository from supervisor.store.repository import Repository
from tests.common import load_yaml_fixture from tests.common import load_yaml_fixture
@ -231,3 +232,14 @@ async def test_install_unavailable_addon(
await coresys.addons.install("local_ssh") await coresys.addons.install("local_ssh")
assert log in caplog.text assert log in caplog.text
async def test_reload(coresys: CoreSys):
"""Test store reload."""
await coresys.store.load()
assert len(coresys.store.all) == 4
with patch.object(GitRepo, "pull") as git_pull:
await coresys.store.reload()
assert git_pull.call_count == 3