Bump to python 3.10 and alpine 3.16 (#3791)

* Bump to python 3.10

* 3.10 is not a number

* Musllinux wheels link

* Revert attrs 22.1.0 -> 21.2.0 for wheel

* Revert cryptography for wheel & pylint fix

* Precommit and devcontainer to 3.10

* pyupgrade rewriting things

* revert

* Update builder.yml

* fix rust

* Update builder.yml

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
This commit is contained in:
Mike Degatano 2022-08-16 08:33:23 -04:00 committed by GitHub
parent 7754424cb8
commit 96065ed704
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 339 additions and 384 deletions

View File

@ -10,7 +10,7 @@
"visualstudioexptteam.vscodeintellicode", "visualstudioexptteam.vscodeintellicode",
"esbenp.prettier-vscode" "esbenp.prettier-vscode"
], ],
"mounts": [ "type=volume,target=/var/lib/docker" ], "mounts": ["type=volume,target=/var/lib/docker"],
"settings": { "settings": {
"terminal.integrated.profiles.linux": { "terminal.integrated.profiles.linux": {
"zsh": { "zsh": {
@ -26,7 +26,7 @@
"python.linting.pylintEnabled": true, "python.linting.pylintEnabled": true,
"python.linting.enabled": true, "python.linting.enabled": true,
"python.formatting.provider": "black", "python.formatting.provider": "black",
"python.formatting.blackArgs": ["--target-version", "py39"], "python.formatting.blackArgs": ["--target-version", "py310"],
"python.formatting.blackPath": "/usr/local/bin/black", "python.formatting.blackPath": "/usr/local/bin/black",
"python.linting.banditPath": "/usr/local/bin/bandit", "python.linting.banditPath": "/usr/local/bin/bandit",
"python.linting.flake8Path": "/usr/local/bin/flake8", "python.linting.flake8Path": "/usr/local/bin/flake8",

View File

@ -33,10 +33,9 @@ on:
- setup.py - setup.py
env: env:
DEFAULT_PYTHON: 3.9 DEFAULT_PYTHON: "3.10"
BUILD_NAME: supervisor BUILD_NAME: supervisor
BUILD_TYPE: supervisor BUILD_TYPE: supervisor
WHEELS_TAG: 3.9-alpine3.14
jobs: jobs:
init: init:
@ -88,18 +87,26 @@ jobs:
uses: actions/checkout@v3.0.2 uses: actions/checkout@v3.0.2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Write env-file
if: needs.init.outputs.requirements == 'true'
run: |
(
# Fix out of memory issues with rust
echo "CARGO_NET_GIT_FETCH_WITH_CLI=true"
) > .env_file
- name: Build wheels - name: Build wheels
if: needs.init.outputs.requirements == 'true' if: needs.init.outputs.requirements == 'true'
uses: home-assistant/wheels@2022.01.2 uses: home-assistant/wheels@2022.06.7
with: with:
tag: ${{ env.WHEELS_TAG }} abi: cp310
tag: musllinux_1_2
arch: ${{ matrix.arch }} arch: ${{ matrix.arch }}
wheels-host: wheels.hass.io
wheels-key: ${{ secrets.WHEELS_KEY }} wheels-key: ${{ secrets.WHEELS_KEY }}
wheels-user: wheels apk: "libffi-dev;openssl-dev"
apk: "build-base;libffi-dev;openssl-dev;cargo"
skip-binary: aiohttp skip-binary: aiohttp
env-file: true
requirements: "requirements.txt" requirements: "requirements.txt"
- name: Set version - name: Set version

View File

@ -8,7 +8,7 @@ on:
pull_request: ~ pull_request: ~
env: env:
DEFAULT_PYTHON: 3.9 DEFAULT_PYTHON: "3.10"
PRE_COMMIT_HOME: ~/.cache/pre-commit PRE_COMMIT_HOME: ~/.cache/pre-commit
DEFAULT_CAS: v1.0.2 DEFAULT_CAS: v1.0.2
@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
python-version: [3.9] python-version: ["3.10"]
name: Prepare Python ${{ matrix.python-version }} dependencies name: Prepare Python ${{ matrix.python-version }} dependencies
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub
@ -341,7 +341,7 @@ jobs:
needs: prepare needs: prepare
strategy: strategy:
matrix: matrix:
python-version: [3.9] python-version: ["3.10"]
name: Run tests Python ${{ matrix.python-version }} name: Run tests Python ${{ matrix.python-version }}
steps: steps:
- name: Check out code from GitHub - name: Check out code from GitHub

View File

@ -7,7 +7,7 @@ repos:
- --safe - --safe
- --quiet - --quiet
- --target-version - --target-version
- py39 - py310
files: ^((supervisor|tests)/.+)?[^/]+\.py$ files: ^((supervisor|tests)/.+)?[^/]+\.py$
- repo: https://gitlab.com/pycqa/flake8 - repo: https://gitlab.com/pycqa/flake8
rev: 3.8.3 rev: 3.8.3
@ -31,4 +31,4 @@ repos:
rev: v2.32.1 rev: v2.32.1
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py39-plus] args: [--py310-plus]

View File

@ -6,7 +6,6 @@ ENV \
SUPERVISOR_API=http://localhost SUPERVISOR_API=http://localhost
ARG \ ARG \
BUILD_ARCH \
CAS_VERSION CAS_VERSION
# Install base # Install base
@ -40,7 +39,7 @@ COPY requirements.txt .
RUN \ RUN \
export MAKEFLAGS="-j$(nproc)" \ export MAKEFLAGS="-j$(nproc)" \
&& pip3 install --no-cache-dir --no-index --only-binary=:all: --find-links \ && pip3 install --no-cache-dir --no-index --only-binary=:all: --find-links \
"https://wheels.home-assistant.io/alpine-$(cut -d '.' -f 1-2 < /etc/alpine-release)/${BUILD_ARCH}/" \ "https://wheels.home-assistant.io/musllinux/" \
-r ./requirements.txt \ -r ./requirements.txt \
&& rm -f requirements.txt && rm -f requirements.txt

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.9-alpine3.14 aarch64: ghcr.io/home-assistant/aarch64-base-python:3.10-alpine3.16
armhf: ghcr.io/home-assistant/armhf-base-python:3.9-alpine3.14 armhf: ghcr.io/home-assistant/armhf-base-python:3.10-alpine3.16
armv7: ghcr.io/home-assistant/armv7-base-python:3.9-alpine3.14 armv7: ghcr.io/home-assistant/armv7-base-python:3.10-alpine3.16
amd64: ghcr.io/home-assistant/amd64-base-python:3.9-alpine3.14 amd64: ghcr.io/home-assistant/amd64-base-python:3.10-alpine3.16
i386: ghcr.io/home-assistant/i386-base-python:3.9-alpine3.14 i386: ghcr.io/home-assistant/i386-base-python:3.10-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

@ -3,7 +3,7 @@ import asyncio
from contextlib import suppress from contextlib import suppress
import logging import logging
import tarfile import tarfile
from typing import Optional, Union from typing import Union
from ..const import AddonBoot, AddonStartup, AddonState from ..const import AddonBoot, AddonStartup, AddonState
from ..coresys import CoreSys, CoreSysAttributes from ..coresys import CoreSys, CoreSysAttributes
@ -53,7 +53,7 @@ class AddonManager(CoreSysAttributes):
"""Return a list of all installed add-ons.""" """Return a list of all installed add-ons."""
return list(self.local.values()) return list(self.local.values())
def get(self, addon_slug: str, local_only: bool = False) -> Optional[AnyAddon]: def get(self, addon_slug: str, local_only: bool = False) -> AnyAddon | None:
"""Return an add-on from slug. """Return an add-on from slug.
Prio: Prio:
@ -66,7 +66,7 @@ class AddonManager(CoreSysAttributes):
return self.store.get(addon_slug) return self.store.get(addon_slug)
return None return None
def from_token(self, token: str) -> Optional[Addon]: def from_token(self, token: str) -> Addon | None:
"""Return an add-on from Supervisor token.""" """Return an add-on from Supervisor token."""
for addon in self.installed: for addon in self.installed:
if token == addon.supervisor_token: if token == addon.supervisor_token:
@ -246,7 +246,7 @@ class AddonManager(CoreSysAttributes):
conditions=ADDON_UPDATE_CONDITIONS, conditions=ADDON_UPDATE_CONDITIONS,
on_condition=AddonsJobError, on_condition=AddonsJobError,
) )
async def update(self, slug: str, backup: Optional[bool] = False) -> None: async def update(self, slug: str, backup: bool | None = False) -> None:
"""Update add-on.""" """Update add-on."""
if slug not in self.local: if slug not in self.local:
raise AddonsError(f"Add-on {slug} is not installed", _LOGGER.error) raise AddonsError(f"Add-on {slug} is not installed", _LOGGER.error)

View File

@ -10,7 +10,7 @@ import secrets
import shutil import shutil
import tarfile import tarfile
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Any, Awaitable, Final, Optional from typing import Any, Awaitable, Final
import aiohttp import aiohttp
from deepmerge import Merger from deepmerge import Merger
@ -240,7 +240,7 @@ class Addon(AddonModel):
return self._available(self.data_store) return self._available(self.data_store)
@property @property
def version(self) -> Optional[str]: def version(self) -> str | None:
"""Return installed version.""" """Return installed version."""
return self.persist[ATTR_VERSION] return self.persist[ATTR_VERSION]
@ -264,7 +264,7 @@ class Addon(AddonModel):
) )
@options.setter @options.setter
def options(self, value: Optional[dict[str, Any]]) -> None: def options(self, value: dict[str, Any] | None) -> None:
"""Store user add-on options.""" """Store user add-on options."""
self.persist[ATTR_OPTIONS] = {} if value is None else deepcopy(value) self.persist[ATTR_OPTIONS] = {} if value is None else deepcopy(value)
@ -309,17 +309,17 @@ class Addon(AddonModel):
return self.persist[ATTR_UUID] return self.persist[ATTR_UUID]
@property @property
def supervisor_token(self) -> Optional[str]: def supervisor_token(self) -> str | None:
"""Return access token for Supervisor API.""" """Return access token for Supervisor API."""
return self.persist.get(ATTR_ACCESS_TOKEN) return self.persist.get(ATTR_ACCESS_TOKEN)
@property @property
def ingress_token(self) -> Optional[str]: def ingress_token(self) -> str | None:
"""Return access token for Supervisor API.""" """Return access token for Supervisor API."""
return self.persist.get(ATTR_INGRESS_TOKEN) return self.persist.get(ATTR_INGRESS_TOKEN)
@property @property
def ingress_entry(self) -> Optional[str]: def ingress_entry(self) -> str | None:
"""Return ingress external URL.""" """Return ingress external URL."""
if self.with_ingress: if self.with_ingress:
return f"/api/hassio_ingress/{self.ingress_token}" return f"/api/hassio_ingress/{self.ingress_token}"
@ -341,12 +341,12 @@ class Addon(AddonModel):
self.persist[ATTR_PROTECTED] = value self.persist[ATTR_PROTECTED] = value
@property @property
def ports(self) -> Optional[dict[str, Optional[int]]]: def ports(self) -> dict[str, int | None] | None:
"""Return ports of add-on.""" """Return ports of add-on."""
return self.persist.get(ATTR_NETWORK, super().ports) return self.persist.get(ATTR_NETWORK, super().ports)
@ports.setter @ports.setter
def ports(self, value: Optional[dict[str, Optional[int]]]) -> None: def ports(self, value: dict[str, int | None] | None) -> None:
"""Set custom ports of add-on.""" """Set custom ports of add-on."""
if value is None: if value is None:
self.persist.pop(ATTR_NETWORK, None) self.persist.pop(ATTR_NETWORK, None)
@ -361,7 +361,7 @@ class Addon(AddonModel):
self.persist[ATTR_NETWORK] = new_ports self.persist[ATTR_NETWORK] = new_ports
@property @property
def ingress_url(self) -> Optional[str]: def ingress_url(self) -> str | None:
"""Return URL to ingress url.""" """Return URL to ingress url."""
if not self.with_ingress: if not self.with_ingress:
return None return None
@ -372,7 +372,7 @@ class Addon(AddonModel):
return url return url
@property @property
def webui(self) -> Optional[str]: def webui(self) -> str | None:
"""Return URL to webui or None.""" """Return URL to webui or None."""
url = super().webui url = super().webui
if not url: if not url:
@ -400,7 +400,7 @@ class Addon(AddonModel):
return f"{proto}://[HOST]:{port}{s_suffix}" return f"{proto}://[HOST]:{port}{s_suffix}"
@property @property
def ingress_port(self) -> Optional[int]: def ingress_port(self) -> int | None:
"""Return Ingress port.""" """Return Ingress port."""
if not self.with_ingress: if not self.with_ingress:
return None return None
@ -411,7 +411,7 @@ class Addon(AddonModel):
return port return port
@property @property
def ingress_panel(self) -> Optional[bool]: def ingress_panel(self) -> bool | None:
"""Return True if the add-on access support ingress.""" """Return True if the add-on access support ingress."""
if not self.with_ingress: if not self.with_ingress:
return None return None
@ -424,19 +424,19 @@ class Addon(AddonModel):
self.persist[ATTR_INGRESS_PANEL] = value self.persist[ATTR_INGRESS_PANEL] = value
@property @property
def audio_output(self) -> Optional[str]: def audio_output(self) -> str | None:
"""Return a pulse profile for output or None.""" """Return a pulse profile for output or None."""
if not self.with_audio: if not self.with_audio:
return None return None
return self.persist.get(ATTR_AUDIO_OUTPUT) return self.persist.get(ATTR_AUDIO_OUTPUT)
@audio_output.setter @audio_output.setter
def audio_output(self, value: Optional[str]): def audio_output(self, value: str | None):
"""Set audio output profile settings.""" """Set audio output profile settings."""
self.persist[ATTR_AUDIO_OUTPUT] = value self.persist[ATTR_AUDIO_OUTPUT] = value
@property @property
def audio_input(self) -> Optional[str]: def audio_input(self) -> str | None:
"""Return pulse profile for input or None.""" """Return pulse profile for input or None."""
if not self.with_audio: if not self.with_audio:
return None return None
@ -444,12 +444,12 @@ class Addon(AddonModel):
return self.persist.get(ATTR_AUDIO_INPUT) return self.persist.get(ATTR_AUDIO_INPUT)
@audio_input.setter @audio_input.setter
def audio_input(self, value: Optional[str]) -> None: def audio_input(self, value: str | None) -> None:
"""Set audio input settings.""" """Set audio input settings."""
self.persist[ATTR_AUDIO_INPUT] = value self.persist[ATTR_AUDIO_INPUT] = value
@property @property
def image(self) -> Optional[str]: def image(self) -> str | None:
"""Return image name of add-on.""" """Return image name of add-on."""
return self.persist.get(ATTR_IMAGE) return self.persist.get(ATTR_IMAGE)

View File

@ -1,7 +1,7 @@
"""Init file for Supervisor add-ons.""" """Init file for Supervisor add-ons."""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from pathlib import Path from pathlib import Path
from typing import Any, Awaitable, Optional from typing import Any, Awaitable
from awesomeversion import AwesomeVersion, AwesomeVersionException from awesomeversion import AwesomeVersion, AwesomeVersionException
@ -123,7 +123,7 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_BOOT] return self.data[ATTR_BOOT]
@property @property
def auto_update(self) -> Optional[bool]: def auto_update(self) -> bool | None:
"""Return if auto update is enable.""" """Return if auto update is enable."""
return None return None
@ -148,22 +148,22 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_TIMEOUT] return self.data[ATTR_TIMEOUT]
@property @property
def uuid(self) -> Optional[str]: def uuid(self) -> str | None:
"""Return an API token for this add-on.""" """Return an API token for this add-on."""
return None return None
@property @property
def supervisor_token(self) -> Optional[str]: def supervisor_token(self) -> str | None:
"""Return access token for Supervisor API.""" """Return access token for Supervisor API."""
return None return None
@property @property
def ingress_token(self) -> Optional[str]: def ingress_token(self) -> str | None:
"""Return access token for Supervisor API.""" """Return access token for Supervisor API."""
return None return None
@property @property
def ingress_entry(self) -> Optional[str]: def ingress_entry(self) -> str | None:
"""Return ingress external URL.""" """Return ingress external URL."""
return None return None
@ -173,7 +173,7 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_DESCRIPTON] return self.data[ATTR_DESCRIPTON]
@property @property
def long_description(self) -> Optional[str]: def long_description(self) -> str | None:
"""Return README.md as long_description.""" """Return README.md as long_description."""
readme = Path(self.path_location, "README.md") readme = Path(self.path_location, "README.md")
@ -243,32 +243,32 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data.get(ATTR_DISCOVERY, []) return self.data.get(ATTR_DISCOVERY, [])
@property @property
def ports_description(self) -> Optional[dict[str, str]]: def ports_description(self) -> dict[str, str] | None:
"""Return descriptions of ports.""" """Return descriptions of ports."""
return self.data.get(ATTR_PORTS_DESCRIPTION) return self.data.get(ATTR_PORTS_DESCRIPTION)
@property @property
def ports(self) -> Optional[dict[str, Optional[int]]]: def ports(self) -> dict[str, int | None] | None:
"""Return ports of add-on.""" """Return ports of add-on."""
return self.data.get(ATTR_PORTS) return self.data.get(ATTR_PORTS)
@property @property
def ingress_url(self) -> Optional[str]: def ingress_url(self) -> str | None:
"""Return URL to ingress url.""" """Return URL to ingress url."""
return None return None
@property @property
def webui(self) -> Optional[str]: def webui(self) -> str | None:
"""Return URL to webui or None.""" """Return URL to webui or None."""
return self.data.get(ATTR_WEBUI) return self.data.get(ATTR_WEBUI)
@property @property
def watchdog(self) -> Optional[str]: def watchdog(self) -> str | None:
"""Return URL to for watchdog or None.""" """Return URL to for watchdog or None."""
return self.data.get(ATTR_WATCHDOG) return self.data.get(ATTR_WATCHDOG)
@property @property
def ingress_port(self) -> Optional[int]: def ingress_port(self) -> int | None:
"""Return Ingress port.""" """Return Ingress port."""
return None return None
@ -313,7 +313,7 @@ class AddonModel(CoreSysAttributes, ABC):
return [Path(node) for node in self.data.get(ATTR_DEVICES, [])] return [Path(node) for node in self.data.get(ATTR_DEVICES, [])]
@property @property
def environment(self) -> Optional[dict[str, str]]: def environment(self) -> dict[str, str] | None:
"""Return environment of add-on.""" """Return environment of add-on."""
return self.data.get(ATTR_ENVIRONMENT) return self.data.get(ATTR_ENVIRONMENT)
@ -362,12 +362,12 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data.get(ATTR_BACKUP_EXCLUDE, []) return self.data.get(ATTR_BACKUP_EXCLUDE, [])
@property @property
def backup_pre(self) -> Optional[str]: def backup_pre(self) -> str | None:
"""Return pre-backup command.""" """Return pre-backup command."""
return self.data.get(ATTR_BACKUP_PRE) return self.data.get(ATTR_BACKUP_PRE)
@property @property
def backup_post(self) -> Optional[str]: def backup_post(self) -> str | None:
"""Return post-backup command.""" """Return post-backup command."""
return self.data.get(ATTR_BACKUP_POST) return self.data.get(ATTR_BACKUP_POST)
@ -392,7 +392,7 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_INGRESS] return self.data[ATTR_INGRESS]
@property @property
def ingress_panel(self) -> Optional[bool]: def ingress_panel(self) -> bool | None:
"""Return True if the add-on access support ingress.""" """Return True if the add-on access support ingress."""
return None return None
@ -442,7 +442,7 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_DEVICETREE] return self.data[ATTR_DEVICETREE]
@property @property
def with_tmpfs(self) -> Optional[str]: def with_tmpfs(self) -> str | None:
"""Return if tmp is in memory of add-on.""" """Return if tmp is in memory of add-on."""
return self.data[ATTR_TMPFS] return self.data[ATTR_TMPFS]
@ -462,12 +462,12 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_VIDEO] return self.data[ATTR_VIDEO]
@property @property
def homeassistant_version(self) -> Optional[str]: def homeassistant_version(self) -> str | None:
"""Return min Home Assistant version they needed by Add-on.""" """Return min Home Assistant version they needed by Add-on."""
return self.data.get(ATTR_HOMEASSISTANT) return self.data.get(ATTR_HOMEASSISTANT)
@property @property
def url(self) -> Optional[str]: def url(self) -> str | None:
"""Return URL of add-on.""" """Return URL of add-on."""
return self.data.get(ATTR_URL) return self.data.get(ATTR_URL)
@ -510,7 +510,7 @@ class AddonModel(CoreSysAttributes, ABC):
return self.sys_arch.default return self.sys_arch.default
@property @property
def image(self) -> Optional[str]: def image(self) -> str | None:
"""Generate image name from data.""" """Generate image name from data."""
return self._image(self.data) return self._image(self.data)
@ -571,7 +571,7 @@ class AddonModel(CoreSysAttributes, ABC):
return AddonOptions(self.coresys, raw_schema, self.name, self.slug) return AddonOptions(self.coresys, raw_schema, self.name, self.slug)
@property @property
def schema_ui(self) -> Optional[list[dict[any, any]]]: def schema_ui(self) -> list[dict[any, any]] | None:
"""Create a UI schema for add-on options.""" """Create a UI schema for add-on options."""
raw_schema = self.data[ATTR_SCHEMA] raw_schema = self.data[ATTR_SCHEMA]
@ -590,7 +590,7 @@ class AddonModel(CoreSysAttributes, ABC):
return ATTR_CODENOTARY in self.data return ATTR_CODENOTARY in self.data
@property @property
def codenotary(self) -> Optional[str]: def codenotary(self) -> str | None:
"""Return Signer email address for CAS.""" """Return Signer email address for CAS."""
return self.data.get(ATTR_CODENOTARY) return self.data.get(ATTR_CODENOTARY)
@ -614,7 +614,7 @@ class AddonModel(CoreSysAttributes, ABC):
return False return False
# Home Assistant # Home Assistant
version: Optional[AwesomeVersion] = config.get(ATTR_HOMEASSISTANT) version: AwesomeVersion | None = config.get(ATTR_HOMEASSISTANT)
try: try:
return self.sys_homeassistant.version >= version return self.sys_homeassistant.version >= version
except (AwesomeVersionException, TypeError): except (AwesomeVersionException, TypeError):
@ -638,7 +638,7 @@ class AddonModel(CoreSysAttributes, ABC):
"""Uninstall this add-on.""" """Uninstall this add-on."""
return self.sys_addons.uninstall(self.slug) return self.sys_addons.uninstall(self.slug)
def update(self, backup: Optional[bool] = False) -> Awaitable[None]: def update(self, backup: bool | None = False) -> Awaitable[None]:
"""Update this add-on.""" """Update this add-on."""
return self.sys_addons.update(self.slug, backup=backup) return self.sys_addons.update(self.slug, backup=backup)

View File

@ -3,7 +3,7 @@ import hashlib
import logging import logging
from pathlib import Path from pathlib import Path
import re import re
from typing import Any, Union from typing import Any
import voluptuous as vol import voluptuous as vol
@ -293,7 +293,7 @@ class UiOptions(CoreSysAttributes):
multiple: bool = False, multiple: bool = False,
) -> None: ) -> None:
"""Validate a single element.""" """Validate a single element."""
ui_node: dict[str, Union[str, bool, float, list[str]]] = {"name": key} ui_node: dict[str, str | bool | float | list[str]] = {"name": key}
# If multiple # If multiple
if multiple: if multiple:

View File

@ -1,7 +1,7 @@
"""Init file for Supervisor RESTful API.""" """Init file for Supervisor RESTful API."""
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Any, Optional from typing import Any
from aiohttp import web from aiohttp import web
@ -63,7 +63,7 @@ class RestAPI(CoreSysAttributes):
# service stuff # service stuff
self._runner: web.AppRunner = web.AppRunner(self.webapp) self._runner: web.AppRunner = web.AppRunner(self.webapp)
self._site: Optional[web.TCPSite] = None self._site: web.TCPSite | None = None
async def load(self) -> None: async def load(self) -> None:
"""Register REST API Calls.""" """Register REST API Calls."""

View File

@ -2,7 +2,7 @@
import asyncio import asyncio
from ipaddress import ip_address from ipaddress import ip_address
import logging import logging
from typing import Any, Union from typing import Any
import aiohttp import aiohttp
from aiohttp import ClientTimeout, hdrs, web from aiohttp import ClientTimeout, hdrs, web
@ -86,7 +86,7 @@ class APIIngress(CoreSysAttributes):
@require_home_assistant @require_home_assistant
async def handler( async def handler(
self, request: web.Request self, request: web.Request
) -> Union[web.Response, web.StreamResponse, web.WebSocketResponse]: ) -> web.Response | web.StreamResponse | web.WebSocketResponse:
"""Route data to Supervisor ingress service.""" """Route data to Supervisor ingress service."""
# Check Ingress Session # Check Ingress Session
@ -157,7 +157,7 @@ class APIIngress(CoreSysAttributes):
async def _handle_request( async def _handle_request(
self, request: web.Request, addon: Addon, path: str self, request: web.Request, addon: Addon, path: str
) -> Union[web.Response, web.StreamResponse]: ) -> web.Response | web.StreamResponse:
"""Ingress route for request.""" """Ingress route for request."""
url = self._create_url(addon, path) url = self._create_url(addon, path)
source_header = _init_header(request, addon) source_header = _init_header(request, addon)
@ -216,9 +216,7 @@ class APIIngress(CoreSysAttributes):
return response return response
def _init_header( def _init_header(request: web.Request, addon: str) -> CIMultiDict | dict[str, str]:
request: web.Request, addon: str
) -> Union[CIMultiDict, dict[str, str]]:
"""Create initial header.""" """Create initial header."""
headers = {} headers = {}

View File

@ -1,6 +1,6 @@
"""Init file for Supervisor util for RESTful API.""" """Init file for Supervisor util for RESTful API."""
import json import json
from typing import Any, Optional from typing import Any
from aiohttp import web from aiohttp import web
from aiohttp.hdrs import AUTHORIZATION from aiohttp.hdrs import AUTHORIZATION
@ -25,7 +25,7 @@ from ..utils.log_format import format_message
from .const import CONTENT_TYPE_BINARY, HEADER_TOKEN, HEADER_TOKEN_OLD from .const import CONTENT_TYPE_BINARY, HEADER_TOKEN, HEADER_TOKEN_OLD
def excract_supervisor_token(request: web.Request) -> Optional[str]: def excract_supervisor_token(request: web.Request) -> str | None:
"""Extract Supervisor token from request.""" """Extract Supervisor token from request."""
if supervisor_token := request.headers.get(HEADER_TOKEN): if supervisor_token := request.headers.get(HEADER_TOKEN):
return supervisor_token return supervisor_token
@ -112,7 +112,7 @@ def api_process_raw(content):
def api_return_error( def api_return_error(
error: Optional[Exception] = None, message: Optional[str] = None error: Exception | None = None, message: str | None = None
) -> web.Response: ) -> web.Response:
"""Return an API error message.""" """Return an API error message."""
if error and not message: if error and not message:
@ -130,7 +130,7 @@ def api_return_error(
) )
def api_return_ok(data: Optional[dict[str, Any]] = None) -> web.Response: def api_return_ok(data: dict[str, Any] | None = None) -> web.Response:
"""Return an API ok answer.""" """Return an API ok answer."""
return web.json_response( return web.json_response(
{JSON_RESULT: RESULT_OK, JSON_DATA: data or {}}, {JSON_RESULT: RESULT_OK, JSON_DATA: data or {}},
@ -139,7 +139,7 @@ def api_return_ok(data: Optional[dict[str, Any]] = None) -> web.Response:
async def api_validate( async def api_validate(
schema: vol.Schema, request: web.Request, origin: Optional[list[str]] = None schema: vol.Schema, request: web.Request, origin: list[str] | None = None
) -> dict[str, Any]: ) -> dict[str, Any]:
"""Validate request data with schema.""" """Validate request data with schema."""
data: dict[str, Any] = await request.json(loads=json_loads) data: dict[str, Any] = await request.json(loads=json_loads)

View File

@ -2,7 +2,6 @@
import asyncio import asyncio
import hashlib import hashlib
import logging import logging
from typing import Optional
from .addons.addon import Addon from .addons.addon import Addon
from .const import ATTR_ADDON, ATTR_PASSWORD, ATTR_USERNAME, FILE_HASSIO_AUTH from .const import ATTR_ADDON, ATTR_PASSWORD, ATTR_USERNAME, FILE_HASSIO_AUTH
@ -24,7 +23,7 @@ class Auth(FileConfiguration, CoreSysAttributes):
self._running: dict[str, asyncio.Task] = {} self._running: dict[str, asyncio.Task] = {}
def _check_cache(self, username: str, password: str) -> Optional[bool]: def _check_cache(self, username: str, password: str) -> bool | None:
"""Check password in cache.""" """Check password in cache."""
username_h = self._rehash(username) username_h = self._rehash(username)
password_h = self._rehash(password, username) password_h = self._rehash(password, username)

View File

@ -5,7 +5,7 @@ import logging
from pathlib import Path from pathlib import Path
import tarfile import tarfile
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Any, Awaitable, Optional from typing import Any, Awaitable
from awesomeversion import AwesomeVersion, AwesomeVersionCompareException from awesomeversion import AwesomeVersion, AwesomeVersionCompareException
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
@ -57,8 +57,8 @@ class Backup(CoreSysAttributes):
self._tarfile: Path = tar_file self._tarfile: Path = tar_file
self._data: dict[str, Any] = {} self._data: dict[str, Any] = {}
self._tmp = None self._tmp = None
self._key: Optional[bytes] = None self._key: bytes | None = None
self._aes: Optional[Cipher] = None self._aes: Cipher | None = None
@property @property
def version(self) -> int: def version(self) -> int:

View File

@ -3,7 +3,6 @@ from datetime import datetime
import logging import logging
import os import os
from pathlib import Path, PurePath from pathlib import Path, PurePath
from typing import Optional
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -63,7 +62,7 @@ class CoreConfig(FileConfiguration):
super().__init__(FILE_HASSIO_CONFIG, SCHEMA_SUPERVISOR_CONFIG) super().__init__(FILE_HASSIO_CONFIG, SCHEMA_SUPERVISOR_CONFIG)
@property @property
def timezone(self) -> Optional[str]: def timezone(self) -> str | None:
"""Return system timezone.""" """Return system timezone."""
timezone = self._data.get(ATTR_TIMEZONE) timezone = self._data.get(ATTR_TIMEZONE)
if timezone != _UTC: if timezone != _UTC:
@ -89,7 +88,7 @@ class CoreConfig(FileConfiguration):
self._data[ATTR_VERSION] = value self._data[ATTR_VERSION] = value
@property @property
def image(self) -> Optional[str]: def image(self) -> str | None:
"""Return supervisor image.""" """Return supervisor image."""
return self._data.get(ATTR_IMAGE) return self._data.get(ATTR_IMAGE)
@ -129,7 +128,7 @@ class CoreConfig(FileConfiguration):
self._data[ATTR_DEBUG_BLOCK] = value self._data[ATTR_DEBUG_BLOCK] = value
@property @property
def diagnostics(self) -> Optional[bool]: def diagnostics(self) -> bool | None:
"""Return bool if diagnostics is set otherwise None.""" """Return bool if diagnostics is set otherwise None."""
return self._data[ATTR_DIAGNOSTICS] return self._data[ATTR_DIAGNOSTICS]

View File

@ -3,7 +3,7 @@ import asyncio
from contextlib import suppress from contextlib import suppress
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Awaitable, Optional from typing import Awaitable
import async_timeout import async_timeout
@ -31,7 +31,7 @@ class Core(CoreSysAttributes):
def __init__(self, coresys: CoreSys): def __init__(self, coresys: CoreSys):
"""Initialize Supervisor object.""" """Initialize Supervisor object."""
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self._state: Optional[CoreState] = None self._state: CoreState | None = None
self.exit_code: int = 0 self.exit_code: int = 0
@property @property

View File

@ -1,6 +1,6 @@
"""D-Bus interface for hostname.""" """D-Bus interface for hostname."""
import logging import logging
from typing import Any, Optional from typing import Any
from ..exceptions import DBusError, DBusInterfaceError from ..exceptions import DBusError, DBusInterfaceError
from ..utils.dbus import DBus from ..utils.dbus import DBus
@ -43,37 +43,37 @@ class Hostname(DBusInterface):
@property @property
@dbus_property @dbus_property
def hostname(self) -> Optional[str]: def hostname(self) -> str | None:
"""Return local hostname.""" """Return local hostname."""
return self.properties[DBUS_ATTR_STATIC_HOSTNAME] return self.properties[DBUS_ATTR_STATIC_HOSTNAME]
@property @property
@dbus_property @dbus_property
def chassis(self) -> Optional[str]: def chassis(self) -> str | None:
"""Return local chassis type.""" """Return local chassis type."""
return self.properties[DBUS_ATTR_CHASSIS] return self.properties[DBUS_ATTR_CHASSIS]
@property @property
@dbus_property @dbus_property
def deployment(self) -> Optional[str]: def deployment(self) -> str | None:
"""Return local deployment type.""" """Return local deployment type."""
return self.properties[DBUS_ATTR_DEPLOYMENT] return self.properties[DBUS_ATTR_DEPLOYMENT]
@property @property
@dbus_property @dbus_property
def kernel(self) -> Optional[str]: def kernel(self) -> str | None:
"""Return local kernel version.""" """Return local kernel version."""
return self.properties[DBUS_ATTR_KERNEL_RELEASE] return self.properties[DBUS_ATTR_KERNEL_RELEASE]
@property @property
@dbus_property @dbus_property
def operating_system(self) -> Optional[str]: def operating_system(self) -> str | None:
"""Return local operating system.""" """Return local operating system."""
return self.properties[DBUS_ATTR_OPERATING_SYSTEM_PRETTY_NAME] return self.properties[DBUS_ATTR_OPERATING_SYSTEM_PRETTY_NAME]
@property @property
@dbus_property @dbus_property
def cpe(self) -> Optional[str]: def cpe(self) -> str | None:
"""Return local CPE.""" """Return local CPE."""
return self.properties[DBUS_ATTR_STATIC_OPERATING_SYSTEM_CPE_NAME] return self.properties[DBUS_ATTR_STATIC_OPERATING_SYSTEM_CPE_NAME]

View File

@ -1,7 +1,7 @@
"""Interface class for D-Bus wrappers.""" """Interface class for D-Bus wrappers."""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from functools import wraps from functools import wraps
from typing import Any, Optional from typing import Any
from ..utils.dbus import DBus from ..utils.dbus import DBus
@ -22,8 +22,8 @@ def dbus_property(func):
class DBusInterface(ABC): class DBusInterface(ABC):
"""Handle D-Bus interface for hostname/system.""" """Handle D-Bus interface for hostname/system."""
dbus: Optional[DBus] = None dbus: DBus | None = None
name: Optional[str] = None name: str | None = None
@property @property
def is_connected(self): def is_connected(self):
@ -42,9 +42,9 @@ class DBusInterface(ABC):
class DBusInterfaceProxy(ABC): class DBusInterfaceProxy(ABC):
"""Handle D-Bus interface proxy.""" """Handle D-Bus interface proxy."""
dbus: Optional[DBus] = None dbus: DBus | None = None
object_path: Optional[str] = None object_path: str | None = None
properties: Optional[dict[str, Any]] = None properties: dict[str, Any] | None = None
@abstractmethod @abstractmethod
async def connect(self): async def connect(self):

View File

@ -1,6 +1,5 @@
"""NetworkConnection object4s for Network Manager.""" """NetworkConnection object4s for Network Manager."""
from ipaddress import IPv4Address, IPv4Interface, IPv6Address, IPv6Interface from ipaddress import IPv4Address, IPv4Interface, IPv6Address, IPv6Interface
from typing import Optional, Union
import attr import attr
@ -9,16 +8,16 @@ import attr
class IpConfiguration: class IpConfiguration:
"""NetworkSettingsIPConfig object for Network Manager.""" """NetworkSettingsIPConfig object for Network Manager."""
gateway: Optional[Union[IPv6Address, IPv6Address]] = attr.ib() gateway: IPv6Address | IPv6Address | None = attr.ib()
nameservers: list[Union[IPv6Address, IPv6Address]] = attr.ib() nameservers: list[IPv6Address | IPv6Address] = attr.ib()
address: list[Union[IPv4Interface, IPv6Interface]] = attr.ib() address: list[IPv4Interface | IPv6Interface] = attr.ib()
@attr.s(slots=True) @attr.s(slots=True)
class DNSConfiguration: class DNSConfiguration:
"""DNS configuration Object.""" """DNS configuration Object."""
nameservers: list[Union[IPv4Address, IPv6Address]] = attr.ib() nameservers: list[IPv4Address | IPv6Address] = attr.ib()
domains: list[str] = attr.ib() domains: list[str] = attr.ib()
interface: str = attr.ib() interface: str = attr.ib()
priority: int = attr.ib() priority: int = attr.ib()
@ -29,48 +28,48 @@ class DNSConfiguration:
class ConnectionProperties: class ConnectionProperties:
"""Connection Properties object for Network Manager.""" """Connection Properties object for Network Manager."""
id: Optional[str] = attr.ib() id: str | None = attr.ib()
uuid: Optional[str] = attr.ib() uuid: str | None = attr.ib()
type: Optional[str] = attr.ib() type: str | None = attr.ib()
interface_name: Optional[str] = attr.ib() interface_name: str | None = attr.ib()
@attr.s(slots=True) @attr.s(slots=True)
class WirelessProperties: class WirelessProperties:
"""Wireless Properties object for Network Manager.""" """Wireless Properties object for Network Manager."""
ssid: Optional[str] = attr.ib() ssid: str | None = attr.ib()
assigned_mac: Optional[str] = attr.ib() assigned_mac: str | None = attr.ib()
mode: Optional[str] = attr.ib() mode: str | None = attr.ib()
powersave: Optional[int] = attr.ib() powersave: int | None = attr.ib()
@attr.s(slots=True) @attr.s(slots=True)
class WirelessSecurityProperties: class WirelessSecurityProperties:
"""Wireless Security Properties object for Network Manager.""" """Wireless Security Properties object for Network Manager."""
auth_alg: Optional[str] = attr.ib() auth_alg: str | None = attr.ib()
key_mgmt: Optional[str] = attr.ib() key_mgmt: str | None = attr.ib()
psk: Optional[str] = attr.ib() psk: str | None = attr.ib()
@attr.s(slots=True) @attr.s(slots=True)
class EthernetProperties: class EthernetProperties:
"""Ethernet properties object for Network Manager.""" """Ethernet properties object for Network Manager."""
assigned_mac: Optional[str] = attr.ib() assigned_mac: str | None = attr.ib()
@attr.s(slots=True) @attr.s(slots=True)
class VlanProperties: class VlanProperties:
"""Ethernet properties object for Network Manager.""" """Ethernet properties object for Network Manager."""
id: Optional[int] = attr.ib() id: int | None = attr.ib()
parent: Optional[str] = attr.ib() parent: str | None = attr.ib()
@attr.s(slots=True) @attr.s(slots=True)
class IpProperties: class IpProperties:
"""IP properties object for Network Manager.""" """IP properties object for Network Manager."""
method: Optional[str] = attr.ib() method: str | None = attr.ib()

View File

@ -1,6 +1,5 @@
"""Connection object for Network Manager.""" """Connection object for Network Manager."""
from ipaddress import ip_address, ip_interface from ipaddress import ip_address, ip_interface
from typing import Optional
from ...const import ATTR_ADDRESS, ATTR_PREFIX from ...const import ATTR_ADDRESS, ATTR_PREFIX
from ...utils.dbus import DBus from ...utils.dbus import DBus
@ -39,8 +38,8 @@ class NetworkConnection(DBusInterfaceProxy):
self.object_path = object_path self.object_path = object_path
self.properties = {} self.properties = {}
self._ipv4: Optional[IpConfiguration] = None self._ipv4: IpConfiguration | None = None
self._ipv6: Optional[IpConfiguration] = None self._ipv6: IpConfiguration | None = None
@property @property
def id(self) -> str: def id(self) -> str:
@ -68,12 +67,12 @@ class NetworkConnection(DBusInterfaceProxy):
return self.properties[DBUS_ATTR_CONNECTION] return self.properties[DBUS_ATTR_CONNECTION]
@property @property
def ipv4(self) -> Optional[IpConfiguration]: def ipv4(self) -> IpConfiguration | None:
"""Return a ip4 configuration object for the connection.""" """Return a ip4 configuration object for the connection."""
return self._ipv4 return self._ipv4
@property @property
def ipv6(self) -> Optional[IpConfiguration]: def ipv6(self) -> IpConfiguration | None:
"""Return a ip6 configuration object for the connection.""" """Return a ip6 configuration object for the connection."""
return self._ipv6 return self._ipv6

View File

@ -1,7 +1,6 @@
"""D-Bus interface for hostname.""" """D-Bus interface for hostname."""
from ipaddress import ip_address from ipaddress import ip_address
import logging import logging
from typing import Optional
from ...const import ( from ...const import (
ATTR_DOMAINS, ATTR_DOMAINS,
@ -35,17 +34,17 @@ class NetworkManagerDNS(DBusInterface):
def __init__(self) -> None: def __init__(self) -> None:
"""Initialize Properties.""" """Initialize Properties."""
self._mode: Optional[str] = None self._mode: str | None = None
self._rc_manager: Optional[str] = None self._rc_manager: str | None = None
self._configuration: list[DNSConfiguration] = [] self._configuration: list[DNSConfiguration] = []
@property @property
def mode(self) -> Optional[str]: def mode(self) -> str | None:
"""Return Propertie mode.""" """Return Propertie mode."""
return self._mode return self._mode
@property @property
def rc_manager(self) -> Optional[str]: def rc_manager(self) -> str | None:
"""Return Propertie RcManager.""" """Return Propertie RcManager."""
return self._rc_manager return self._rc_manager

View File

@ -1,6 +1,4 @@
"""NetworkInterface object for Network Manager.""" """NetworkInterface object for Network Manager."""
from typing import Optional
from ...utils.dbus import DBus from ...utils.dbus import DBus
from ..const import ( from ..const import (
DBUS_ATTR_ACTIVE_CONNECTION, DBUS_ATTR_ACTIVE_CONNECTION,
@ -32,9 +30,9 @@ class NetworkInterface(DBusInterfaceProxy):
self.primary = False self.primary = False
self._connection: Optional[NetworkConnection] = None self._connection: NetworkConnection | None = None
self._settings: Optional[NetworkSetting] = None self._settings: NetworkSetting | None = None
self._wireless: Optional[NetworkWireless] = None self._wireless: NetworkWireless | None = None
self._nm_dbus: DBus = nm_dbus self._nm_dbus: DBus = nm_dbus
@property @property
@ -58,17 +56,17 @@ class NetworkInterface(DBusInterfaceProxy):
return self.properties[DBUS_ATTR_MANAGED] return self.properties[DBUS_ATTR_MANAGED]
@property @property
def connection(self) -> Optional[NetworkConnection]: def connection(self) -> NetworkConnection | None:
"""Return the connection used for this interface.""" """Return the connection used for this interface."""
return self._connection return self._connection
@property @property
def settings(self) -> Optional[NetworkSetting]: def settings(self) -> NetworkSetting | None:
"""Return the connection settings used for this interface.""" """Return the connection settings used for this interface."""
return self._settings return self._settings
@property @property
def wireless(self) -> Optional[NetworkWireless]: def wireless(self) -> NetworkWireless | None:
"""Return the wireless data for this interface.""" """Return the wireless data for this interface."""
return self._wireless return self._wireless

View File

@ -1,6 +1,6 @@
"""Connection object for Network Manager.""" """Connection object for Network Manager."""
import logging import logging
from typing import Any, Awaitable, Optional from typing import Any, Awaitable
from ....const import ATTR_METHOD, ATTR_MODE, ATTR_PSK, ATTR_SSID from ....const import ATTR_METHOD, ATTR_MODE, ATTR_PSK, ATTR_SSID
from ....utils.dbus import DBus from ....utils.dbus import DBus
@ -59,46 +59,46 @@ class NetworkSetting(DBusInterfaceProxy):
self.object_path = object_path self.object_path = object_path
self.properties = {} self.properties = {}
self._connection: Optional[ConnectionProperties] = None self._connection: ConnectionProperties | None = None
self._wireless: Optional[WirelessProperties] = None self._wireless: WirelessProperties | None = None
self._wireless_security: Optional[WirelessSecurityProperties] = None self._wireless_security: WirelessSecurityProperties | None = None
self._ethernet: Optional[EthernetProperties] = None self._ethernet: EthernetProperties | None = None
self._vlan: Optional[VlanProperties] = None self._vlan: VlanProperties | None = None
self._ipv4: Optional[IpProperties] = None self._ipv4: IpProperties | None = None
self._ipv6: Optional[IpProperties] = None self._ipv6: IpProperties | None = None
@property @property
def connection(self) -> Optional[ConnectionProperties]: def connection(self) -> ConnectionProperties | None:
"""Return connection properties if any.""" """Return connection properties if any."""
return self._connection return self._connection
@property @property
def wireless(self) -> Optional[WirelessProperties]: def wireless(self) -> WirelessProperties | None:
"""Return wireless properties if any.""" """Return wireless properties if any."""
return self._wireless return self._wireless
@property @property
def wireless_security(self) -> Optional[WirelessSecurityProperties]: def wireless_security(self) -> WirelessSecurityProperties | None:
"""Return wireless security properties if any.""" """Return wireless security properties if any."""
return self._wireless_security return self._wireless_security
@property @property
def ethernet(self) -> Optional[EthernetProperties]: def ethernet(self) -> EthernetProperties | None:
"""Return Ethernet properties if any.""" """Return Ethernet properties if any."""
return self._ethernet return self._ethernet
@property @property
def vlan(self) -> Optional[VlanProperties]: def vlan(self) -> VlanProperties | None:
"""Return Vlan properties if any.""" """Return Vlan properties if any."""
return self._vlan return self._vlan
@property @property
def ipv4(self) -> Optional[IpProperties]: def ipv4(self) -> IpProperties | None:
"""Return ipv4 properties if any.""" """Return ipv4 properties if any."""
return self._ipv4 return self._ipv4
@property @property
def ipv6(self) -> Optional[IpProperties]: def ipv6(self) -> IpProperties | None:
"""Return ipv6 properties if any.""" """Return ipv6 properties if any."""
return self._ipv6 return self._ipv6

View File

@ -1,5 +1,5 @@
"""Connection object for Network Manager.""" """Connection object for Network Manager."""
from typing import Any, Awaitable, Optional from typing import Any, Awaitable
from ...utils.dbus import DBus from ...utils.dbus import DBus
from ..const import ( from ..const import (
@ -24,10 +24,10 @@ class NetworkWireless(DBusInterfaceProxy):
self.object_path = object_path self.object_path = object_path
self.properties = {} self.properties = {}
self._active: Optional[NetworkWirelessAP] = None self._active: NetworkWirelessAP | None = None
@property @property
def active(self) -> Optional[NetworkWirelessAP]: def active(self) -> NetworkWirelessAP | None:
"""Return details about active connection.""" """Return details about active connection."""
return self._active return self._active

View File

@ -1,6 +1,5 @@
"""D-Bus interface for rauc.""" """D-Bus interface for rauc."""
import logging import logging
from typing import Optional
from ..exceptions import DBusError, DBusInterfaceError from ..exceptions import DBusError, DBusInterfaceError
from ..utils.dbus import DBus from ..utils.dbus import DBus
@ -29,11 +28,11 @@ class Rauc(DBusInterface):
def __init__(self): def __init__(self):
"""Initialize Properties.""" """Initialize Properties."""
self._operation: Optional[str] = None self._operation: str | None = None
self._last_error: Optional[str] = None self._last_error: str | None = None
self._compatible: Optional[str] = None self._compatible: str | None = None
self._variant: Optional[str] = None self._variant: str | None = None
self._boot_slot: Optional[str] = None self._boot_slot: str | None = None
async def connect(self): async def connect(self):
"""Connect to D-Bus.""" """Connect to D-Bus."""
@ -45,27 +44,27 @@ class Rauc(DBusInterface):
_LOGGER.warning("Host has no rauc support. OTA updates have been disabled.") _LOGGER.warning("Host has no rauc support. OTA updates have been disabled.")
@property @property
def operation(self) -> Optional[str]: def operation(self) -> str | None:
"""Return the current (global) operation.""" """Return the current (global) operation."""
return self._operation return self._operation
@property @property
def last_error(self) -> Optional[str]: def last_error(self) -> str | None:
"""Return the last message of the last error that occurred.""" """Return the last message of the last error that occurred."""
return self._last_error return self._last_error
@property @property
def compatible(self) -> Optional[str]: def compatible(self) -> str | None:
"""Return the system compatible string.""" """Return the system compatible string."""
return self._compatible return self._compatible
@property @property
def variant(self) -> Optional[str]: def variant(self) -> str | None:
"""Return the system variant string.""" """Return the system variant string."""
return self._variant return self._variant
@property @property
def boot_slot(self) -> Optional[str]: def boot_slot(self) -> str | None:
"""Return the used boot slot.""" """Return the used boot slot."""
return self._boot_slot return self._boot_slot

View File

@ -1,6 +1,5 @@
"""Audio docker object.""" """Audio docker object."""
import logging import logging
from typing import Optional
import docker import docker
@ -63,7 +62,7 @@ class DockerAudio(DockerInterface, CoreSysAttributes):
return [docker.types.Ulimit(name="rtprio", soft=10, hard=10)] return [docker.types.Ulimit(name="rtprio", soft=10, hard=10)]
@property @property
def cpu_rt_runtime(self) -> Optional[int]: def cpu_rt_runtime(self) -> int | None:
"""Limit CPU real-time runtime in microseconds.""" """Limit CPU real-time runtime in microseconds."""
if not self.sys_docker.info.support_cpu_realtime: if not self.sys_docker.info.support_cpu_realtime:
return None return None

View File

@ -1,7 +1,7 @@
"""Init file for Supervisor Docker object.""" """Init file for Supervisor Docker object."""
from ipaddress import IPv4Address from ipaddress import IPv4Address
import logging import logging
from typing import Awaitable, Optional from typing import Awaitable
from awesomeversion import AwesomeVersion, AwesomeVersionCompareException from awesomeversion import AwesomeVersion, AwesomeVersionCompareException
import docker import docker
@ -23,7 +23,7 @@ class DockerHomeAssistant(DockerInterface):
"""Docker Supervisor wrapper for Home Assistant.""" """Docker Supervisor wrapper for Home Assistant."""
@property @property
def machine(self) -> Optional[str]: def machine(self) -> str | None:
"""Return machine of Home Assistant Docker image.""" """Return machine of Home Assistant Docker image."""
if self._meta and LABEL_MACHINE in self._meta["Config"]["Labels"]: if self._meta and LABEL_MACHINE in self._meta["Config"]["Labels"]:
return self._meta["Config"]["Labels"][LABEL_MACHINE] return self._meta["Config"]["Labels"][LABEL_MACHINE]

View File

@ -4,7 +4,7 @@ from ipaddress import IPv4Address
import logging import logging
import os import os
from pathlib import Path from pathlib import Path
from typing import Any, Optional from typing import Any
import attr import attr
from awesomeversion import AwesomeVersion, AwesomeVersionCompareException from awesomeversion import AwesomeVersion, AwesomeVersionCompareException
@ -154,16 +154,16 @@ class DockerAPI:
image: str, image: str,
tag: str = "latest", tag: str = "latest",
dns: bool = True, dns: bool = True,
ipv4: Optional[IPv4Address] = None, ipv4: IPv4Address | None = None,
**kwargs: Any, **kwargs: Any,
) -> Container: ) -> Container:
"""Create a Docker container and run it. """Create a Docker container and run it.
Need run inside executor. Need run inside executor.
""" """
name: Optional[str] = kwargs.get("name") name: str | None = kwargs.get("name")
network_mode: Optional[str] = kwargs.get("network_mode") network_mode: str | None = kwargs.get("network_mode")
hostname: Optional[str] = kwargs.get("hostname") hostname: str | None = kwargs.get("hostname")
if "labels" not in kwargs: if "labels" not in kwargs:
kwargs["labels"] = {} kwargs["labels"] = {}
@ -242,7 +242,7 @@ class DockerAPI:
self, self,
image: str, image: str,
tag: str = "latest", tag: str = "latest",
command: Optional[str] = None, command: str | None = None,
**kwargs: Any, **kwargs: Any,
) -> CommandReturn: ) -> CommandReturn:
"""Create a temporary container and run command. """Create a temporary container and run command.

View File

@ -2,7 +2,6 @@
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
from threading import Thread from threading import Thread
from typing import Optional
from docker.models.containers import Container from docker.models.containers import Container
from docker.types.daemon import CancellableStream from docker.types.daemon import CancellableStream
@ -31,7 +30,7 @@ class DockerMonitor(CoreSysAttributes, Thread):
"""Initialize Docker monitor object.""" """Initialize Docker monitor object."""
super().__init__() super().__init__()
self.coresys = coresys self.coresys = coresys
self._events: Optional[CancellableStream] = None self._events: CancellableStream | None = None
self._unlabeled_managed_containers: list[str] = [] self._unlabeled_managed_containers: list[str] = []
def watch_container(self, container: Container): def watch_container(self, container: Container):
@ -64,7 +63,7 @@ class DockerMonitor(CoreSysAttributes, Thread):
LABEL_MANAGED in attributes LABEL_MANAGED in attributes
or attributes.get("name") in self._unlabeled_managed_containers or attributes.get("name") in self._unlabeled_managed_containers
): ):
container_state: Optional[ContainerState] = None container_state: ContainerState | None = None
action: str = event["Action"] action: str = event["Action"]
if action == "start": if action == "start":

View File

@ -2,7 +2,6 @@
from contextlib import suppress from contextlib import suppress
from ipaddress import IPv4Address from ipaddress import IPv4Address
import logging import logging
from typing import Optional
import docker import docker
import requests import requests
@ -99,8 +98,8 @@ class DockerNetwork:
def attach_container( def attach_container(
self, self,
container: docker.models.containers.Container, container: docker.models.containers.Container,
alias: Optional[list[str]] = None, alias: list[str] | None = None,
ipv4: Optional[IPv4Address] = None, ipv4: IPv4Address | None = None,
) -> None: ) -> None:
"""Attach container to Supervisor network. """Attach container to Supervisor network.

View File

@ -1,7 +1,5 @@
"""Core Exceptions.""" """Core Exceptions."""
from typing import Callable
from typing import Callable, Optional
class HassioError(Exception): class HassioError(Exception):
@ -9,8 +7,8 @@ class HassioError(Exception):
def __init__( def __init__(
self, self,
message: Optional[str] = None, message: str | None = None,
logger: Optional[Callable[..., None]] = None, logger: Callable[..., None] | None = None,
) -> None: ) -> None:
"""Raise & log.""" """Raise & log."""
if logger is not None and message is not None: if logger is not None and message is not None:

View File

@ -2,7 +2,6 @@
import logging import logging
from pathlib import Path from pathlib import Path
import shutil import shutil
from typing import Union
from ..coresys import CoreSys, CoreSysAttributes from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import HardwareNotFound from ..exceptions import HardwareNotFound
@ -48,17 +47,17 @@ class HwDisk(CoreSysAttributes):
return False return False
def get_disk_total_space(self, path: Union[str, Path]) -> float: def get_disk_total_space(self, path: str | Path) -> float:
"""Return total space (GiB) on disk for path.""" """Return total space (GiB) on disk for path."""
total, _, _ = shutil.disk_usage(path) total, _, _ = shutil.disk_usage(path)
return round(total / (1024.0**3), 1) return round(total / (1024.0**3), 1)
def get_disk_used_space(self, path: Union[str, Path]) -> float: def get_disk_used_space(self, path: str | Path) -> float:
"""Return used space (GiB) on disk for path.""" """Return used space (GiB) on disk for path."""
_, used, _ = shutil.disk_usage(path) _, used, _ = shutil.disk_usage(path)
return round(used / (1024.0**3), 1) return round(used / (1024.0**3), 1)
def get_disk_free_space(self, path: Union[str, Path]) -> float: def get_disk_free_space(self, path: str | Path) -> float:
"""Return free space (GiB) on disk for path.""" """Return free space (GiB) on disk for path."""
_, _, free = shutil.disk_usage(path) _, _, free = shutil.disk_usage(path)
return round(free / (1024.0**3), 1) return round(free / (1024.0**3), 1)
@ -112,7 +111,7 @@ class HwDisk(CoreSysAttributes):
# Return the pessimistic estimate (0x02 -> 10%-20%, return 20%) # Return the pessimistic estimate (0x02 -> 10%-20%, return 20%)
return life_time_value * 10.0 return life_time_value * 10.0
def get_disk_life_time(self, path: Union[str, Path]) -> float: def get_disk_life_time(self, path: str | Path) -> float:
"""Return life time estimate of the underlying SSD drive.""" """Return life time estimate of the underlying SSD drive."""
mount_source = self._get_mount_source(str(path)) mount_source = self._get_mount_source(str(path))
if mount_source == "overlay": if mount_source == "overlay":

View File

@ -3,7 +3,6 @@ from datetime import datetime
import logging import logging
from pathlib import Path from pathlib import Path
import re import re
from typing import Optional
import pyudev import pyudev
@ -42,7 +41,7 @@ class HwHelper(CoreSysAttributes):
return bool(self.sys_hardware.filter_devices(subsystem=UdevSubsystem.USB)) return bool(self.sys_hardware.filter_devices(subsystem=UdevSubsystem.USB))
@property @property
def last_boot(self) -> Optional[str]: def last_boot(self) -> str | None:
"""Return last boot time.""" """Return last boot time."""
try: try:
stats: str = _PROC_STAT.read_text(encoding="utf-8") stats: str = _PROC_STAT.read_text(encoding="utf-8")
@ -51,7 +50,7 @@ class HwHelper(CoreSysAttributes):
return None return None
# parse stat file # parse stat file
found: Optional[re.Match] = _RE_BOOT_TIME.search(stats) found: re.Match | None = _RE_BOOT_TIME.search(stats)
if not found: if not found:
_LOGGER.error("Can't found last boot time!") _LOGGER.error("Can't found last boot time!")
return None return None

View File

@ -1,7 +1,6 @@
"""Hardware Manager of Supervisor.""" """Hardware Manager of Supervisor."""
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Optional
import pyudev import pyudev
@ -65,7 +64,7 @@ class HardwareManager(CoreSysAttributes):
return device return device
raise HardwareNotFound() raise HardwareNotFound()
def filter_devices(self, subsystem: Optional[UdevSubsystem] = None) -> list[Device]: def filter_devices(self, subsystem: UdevSubsystem | None = None) -> list[Device]:
"""Return a filtered list.""" """Return a filtered list."""
devices = set() devices = set()
for device in self.devices: for device in self.devices:

View File

@ -3,7 +3,6 @@ import asyncio
import logging import logging
from pathlib import Path from pathlib import Path
from pprint import pformat from pprint import pformat
from typing import Optional
import pyudev import pyudev
@ -24,8 +23,8 @@ class HwMonitor(CoreSysAttributes):
"""Initialize Hardware Monitor object.""" """Initialize Hardware Monitor object."""
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.context = pyudev.Context() self.context = pyudev.Context()
self.monitor: Optional[pyudev.Monitor] = None self.monitor: pyudev.Monitor | None = None
self.observer: Optional[pyudev.MonitorObserver] = None self.observer: pyudev.MonitorObserver | None = None
async def load(self) -> None: async def load(self) -> None:
"""Start hardware monitor.""" """Start hardware monitor."""
@ -70,8 +69,8 @@ class HwMonitor(CoreSysAttributes):
): ):
return return
hw_action: Optional[HardwareAction] = None hw_action: HardwareAction | None = None
device: Optional[Device] = None device: Device | None = None
## ##
# Remove # Remove

View File

@ -3,7 +3,7 @@ import asyncio
from contextlib import asynccontextmanager, suppress from contextlib import asynccontextmanager, suppress
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
from typing import Any, AsyncContextManager, Optional from typing import Any, AsyncContextManager
import aiohttp import aiohttp
from aiohttp import hdrs from aiohttp import hdrs
@ -26,8 +26,8 @@ class HomeAssistantAPI(CoreSysAttributes):
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
# We don't persist access tokens. Instead we fetch new ones when needed # We don't persist access tokens. Instead we fetch new ones when needed
self.access_token: Optional[str] = None self.access_token: str | None = None
self._access_token_expires: Optional[datetime] = None self._access_token_expires: datetime | None = None
@Job(limit=JobExecutionLimit.SINGLE_WAIT) @Job(limit=JobExecutionLimit.SINGLE_WAIT)
async def ensure_access_token(self) -> None: async def ensure_access_token(self) -> None:
@ -65,12 +65,12 @@ class HomeAssistantAPI(CoreSysAttributes):
self, self,
method: str, method: str,
path: str, path: str,
json: Optional[dict[str, Any]] = None, json: dict[str, Any] | None = None,
content_type: Optional[str] = None, content_type: str | None = None,
data: Any = None, data: Any = None,
timeout: int = 30, timeout: int = 30,
params: Optional[dict[str, str]] = None, params: dict[str, str] | None = None,
headers: Optional[dict[str, str]] = None, headers: dict[str, str] | None = None,
) -> AsyncContextManager[aiohttp.ClientResponse]: ) -> AsyncContextManager[aiohttp.ClientResponse]:
"""Async context manager to make a request with right auth.""" """Async context manager to make a request with right auth."""
url = f"{self.sys_homeassistant.api_url}/{path}" url = f"{self.sys_homeassistant.api_url}/{path}"

View File

@ -5,7 +5,7 @@ import logging
import re import re
import secrets import secrets
import shutil import shutil
from typing import Awaitable, Optional from typing import Awaitable
import attr import attr
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -189,8 +189,8 @@ class HomeAssistantCore(CoreSysAttributes):
) )
async def update( async def update(
self, self,
version: Optional[AwesomeVersion] = None, version: AwesomeVersion | None = None,
backup: Optional[bool] = False, backup: bool | None = False,
) -> None: ) -> None:
"""Update HomeAssistant version.""" """Update HomeAssistant version."""
version = version or self.sys_homeassistant.latest_version version = version or self.sys_homeassistant.latest_version

View File

@ -6,7 +6,6 @@ from pathlib import Path
import shutil import shutil
import tarfile import tarfile
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Optional
from uuid import UUID from uuid import UUID
from awesomeversion import AwesomeVersion, AwesomeVersionException from awesomeversion import AwesomeVersion, AwesomeVersionException
@ -158,7 +157,7 @@ class HomeAssistant(FileConfiguration, CoreSysAttributes):
self._data[ATTR_WATCHDOG] = value self._data[ATTR_WATCHDOG] = value
@property @property
def latest_version(self) -> Optional[AwesomeVersion]: def latest_version(self) -> AwesomeVersion | None:
"""Return last available version of Home Assistant.""" """Return last available version of Home Assistant."""
return self.sys_updater.version_homeassistant return self.sys_updater.version_homeassistant
@ -170,12 +169,12 @@ class HomeAssistant(FileConfiguration, CoreSysAttributes):
return f"ghcr.io/home-assistant/{self.sys_machine}-homeassistant" return f"ghcr.io/home-assistant/{self.sys_machine}-homeassistant"
@image.setter @image.setter
def image(self, value: Optional[str]) -> None: def image(self, value: str | None) -> None:
"""Set image name of Home Assistant container.""" """Set image name of Home Assistant container."""
self._data[ATTR_IMAGE] = value self._data[ATTR_IMAGE] = value
@property @property
def version(self) -> Optional[AwesomeVersion]: def version(self) -> AwesomeVersion | None:
"""Return version of local version.""" """Return version of local version."""
return self._data.get(ATTR_VERSION) return self._data.get(ATTR_VERSION)
@ -200,7 +199,7 @@ class HomeAssistant(FileConfiguration, CoreSysAttributes):
return self._data[ATTR_UUID] return self._data[ATTR_UUID]
@property @property
def supervisor_token(self) -> Optional[str]: def supervisor_token(self) -> str | None:
"""Return an access token for the Supervisor API.""" """Return an access token for the Supervisor API."""
return self._data.get(ATTR_ACCESS_TOKEN) return self._data.get(ATTR_ACCESS_TOKEN)
@ -210,12 +209,12 @@ class HomeAssistant(FileConfiguration, CoreSysAttributes):
self._data[ATTR_ACCESS_TOKEN] = value self._data[ATTR_ACCESS_TOKEN] = value
@property @property
def refresh_token(self) -> Optional[str]: def refresh_token(self) -> str | None:
"""Return the refresh token to authenticate with Home Assistant.""" """Return the refresh token to authenticate with Home Assistant."""
return self._data.get(ATTR_REFRESH_TOKEN) return self._data.get(ATTR_REFRESH_TOKEN)
@refresh_token.setter @refresh_token.setter
def refresh_token(self, value: Optional[str]): def refresh_token(self, value: str | None):
"""Set Home Assistant refresh_token.""" """Set Home Assistant refresh_token."""
self._data[ATTR_REFRESH_TOKEN] = value self._data[ATTR_REFRESH_TOKEN] = value
@ -230,22 +229,22 @@ class HomeAssistant(FileConfiguration, CoreSysAttributes):
return Path(self.sys_config.path_extern_tmp, "homeassistant_pulse") return Path(self.sys_config.path_extern_tmp, "homeassistant_pulse")
@property @property
def audio_output(self) -> Optional[str]: def audio_output(self) -> str | None:
"""Return a pulse profile for output or None.""" """Return a pulse profile for output or None."""
return self._data[ATTR_AUDIO_OUTPUT] return self._data[ATTR_AUDIO_OUTPUT]
@audio_output.setter @audio_output.setter
def audio_output(self, value: Optional[str]): def audio_output(self, value: str | None):
"""Set audio output profile settings.""" """Set audio output profile settings."""
self._data[ATTR_AUDIO_OUTPUT] = value self._data[ATTR_AUDIO_OUTPUT] = value
@property @property
def audio_input(self) -> Optional[str]: def audio_input(self) -> str | None:
"""Return pulse profile for input or None.""" """Return pulse profile for input or None."""
return self._data[ATTR_AUDIO_INPUT] return self._data[ATTR_AUDIO_INPUT]
@audio_input.setter @audio_input.setter
def audio_input(self, value: Optional[str]): def audio_input(self, value: str | None):
"""Set audio input settings.""" """Set audio input settings."""
self._data[ATTR_AUDIO_INPUT] = value self._data[ATTR_AUDIO_INPUT] = value

View File

@ -2,7 +2,6 @@
from datetime import timedelta from datetime import timedelta
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Optional, Union
from ..coresys import CoreSys, CoreSysAttributes from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import YamlFileError from ..exceptions import YamlFileError
@ -19,14 +18,14 @@ class HomeAssistantSecrets(CoreSysAttributes):
def __init__(self, coresys: CoreSys): def __init__(self, coresys: CoreSys):
"""Initialize secret manager.""" """Initialize secret manager."""
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.secrets: dict[str, Union[bool, float, int, str]] = {} self.secrets: dict[str, bool | float | int | str] = {}
@property @property
def path_secrets(self) -> Path: def path_secrets(self) -> Path:
"""Return path to secret file.""" """Return path to secret file."""
return Path(self.sys_config.path_homeassistant, "secrets.yaml") return Path(self.sys_config.path_homeassistant, "secrets.yaml")
def get(self, secret: str) -> Optional[Union[bool, float, int, str]]: def get(self, secret: str) -> bool | float | int | str | None:
"""Get secret from store.""" """Get secret from store."""
_LOGGER.info("Request secret %s", secret) _LOGGER.info("Request secret %s", secret)
return self.secrets.get(secret) return self.secrets.get(secret)

View File

@ -2,7 +2,6 @@
import asyncio import asyncio
from datetime import datetime from datetime import datetime
import logging import logging
from typing import Optional
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..dbus.const import MulticastProtocolEnabled from ..dbus.const import MulticastProtocolEnabled
@ -19,86 +18,86 @@ class InfoCenter(CoreSysAttributes):
self.coresys = coresys self.coresys = coresys
@property @property
def hostname(self) -> Optional[str]: def hostname(self) -> str | None:
"""Return local hostname.""" """Return local hostname."""
return self.sys_dbus.hostname.hostname return self.sys_dbus.hostname.hostname
@property @property
def llmnr_hostname(self) -> Optional[str]: def llmnr_hostname(self) -> str | None:
"""Return local llmnr hostname.""" """Return local llmnr hostname."""
return self.sys_dbus.resolved.llmnr_hostname return self.sys_dbus.resolved.llmnr_hostname
@property @property
def broadcast_llmnr(self) -> Optional[bool]: def broadcast_llmnr(self) -> bool | None:
"""Host is broadcasting llmnr name.""" """Host is broadcasting llmnr name."""
if self.sys_dbus.resolved.llmnr: if self.sys_dbus.resolved.llmnr:
return self.sys_dbus.resolved.llmnr == MulticastProtocolEnabled.YES return self.sys_dbus.resolved.llmnr == MulticastProtocolEnabled.YES
return None return None
@property @property
def broadcast_mdns(self) -> Optional[bool]: def broadcast_mdns(self) -> bool | None:
"""Host is broadcasting mdns name.""" """Host is broadcasting mdns name."""
if self.sys_dbus.resolved.multicast_dns: if self.sys_dbus.resolved.multicast_dns:
return self.sys_dbus.resolved.multicast_dns == MulticastProtocolEnabled.YES return self.sys_dbus.resolved.multicast_dns == MulticastProtocolEnabled.YES
return None return None
@property @property
def chassis(self) -> Optional[str]: def chassis(self) -> str | None:
"""Return local chassis type.""" """Return local chassis type."""
return self.sys_dbus.hostname.chassis return self.sys_dbus.hostname.chassis
@property @property
def deployment(self) -> Optional[str]: def deployment(self) -> str | None:
"""Return local deployment type.""" """Return local deployment type."""
return self.sys_dbus.hostname.deployment return self.sys_dbus.hostname.deployment
@property @property
def kernel(self) -> Optional[str]: def kernel(self) -> str | None:
"""Return local kernel version.""" """Return local kernel version."""
return self.sys_dbus.hostname.kernel return self.sys_dbus.hostname.kernel
@property @property
def operating_system(self) -> Optional[str]: def operating_system(self) -> str | None:
"""Return local operating system.""" """Return local operating system."""
return self.sys_dbus.hostname.operating_system return self.sys_dbus.hostname.operating_system
@property @property
def cpe(self) -> Optional[str]: def cpe(self) -> str | None:
"""Return local CPE.""" """Return local CPE."""
return self.sys_dbus.hostname.cpe return self.sys_dbus.hostname.cpe
@property @property
def timezone(self) -> Optional[str]: def timezone(self) -> str | None:
"""Return host timezone.""" """Return host timezone."""
return self.sys_dbus.timedate.timezone return self.sys_dbus.timedate.timezone
@property @property
def dt_utc(self) -> Optional[datetime]: def dt_utc(self) -> datetime | None:
"""Return host UTC time.""" """Return host UTC time."""
return self.sys_dbus.timedate.dt_utc return self.sys_dbus.timedate.dt_utc
@property @property
def use_rtc(self) -> Optional[bool]: def use_rtc(self) -> bool | None:
"""Return true if host have an RTC.""" """Return true if host have an RTC."""
return self.sys_dbus.timedate.local_rtc return self.sys_dbus.timedate.local_rtc
@property @property
def use_ntp(self) -> Optional[bool]: def use_ntp(self) -> bool | None:
"""Return true if host using NTP.""" """Return true if host using NTP."""
return self.sys_dbus.timedate.ntp return self.sys_dbus.timedate.ntp
@property @property
def dt_synchronized(self) -> Optional[bool]: def dt_synchronized(self) -> bool | None:
"""Return true if host time is syncronized.""" """Return true if host time is syncronized."""
return self.sys_dbus.timedate.ntp_synchronized return self.sys_dbus.timedate.ntp_synchronized
@property @property
def startup_time(self) -> Optional[float]: def startup_time(self) -> float | None:
"""Return startup time in seconds.""" """Return startup time in seconds."""
return self.sys_dbus.systemd.startup_time return self.sys_dbus.systemd.startup_time
@property @property
def boot_timestamp(self) -> Optional[int]: def boot_timestamp(self) -> int | None:
"""Return the boot timestamp.""" """Return the boot timestamp."""
return self.sys_dbus.systemd.boot_timestamp return self.sys_dbus.systemd.boot_timestamp

View File

@ -2,7 +2,6 @@
from datetime import timedelta from datetime import timedelta
from enum import Enum from enum import Enum
import logging import logging
from typing import Optional
import attr import attr
from pulsectl import Pulse, PulseError, PulseIndexError, PulseOperationFailed from pulsectl import Pulse, PulseError, PulseIndexError, PulseOperationFailed
@ -47,7 +46,7 @@ class AudioStream:
volume: float = attr.ib() volume: float = attr.ib()
mute: bool = attr.ib() mute: bool = attr.ib()
default: bool = attr.ib() default: bool = attr.ib()
card: Optional[int] = attr.ib() card: int | None = attr.ib()
applications: list[AudioApplication] = attr.ib() applications: list[AudioApplication] = attr.ib()

View File

@ -3,7 +3,6 @@ from datetime import timedelta
import logging import logging
import random import random
import secrets import secrets
from typing import Optional
from .addons.addon import Addon from .addons.addon import Addon
from .const import ATTR_PORTS, ATTR_SESSION, FILE_HASSIO_INGRESS from .const import ATTR_PORTS, ATTR_SESSION, FILE_HASSIO_INGRESS
@ -25,7 +24,7 @@ class Ingress(FileConfiguration, CoreSysAttributes):
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.tokens: dict[str, str] = {} self.tokens: dict[str, str] = {}
def get(self, token: str) -> Optional[Addon]: def get(self, token: str) -> Addon | None:
"""Return addon they have this ingress token.""" """Return addon they have this ingress token."""
if token not in self.tokens: if token not in self.tokens:
return None return None

View File

@ -1,6 +1,5 @@
"""Supervisor job manager.""" """Supervisor job manager."""
import logging import logging
from typing import Optional
from ..coresys import CoreSys, CoreSysAttributes from ..coresys import CoreSys, CoreSysAttributes
from ..utils.common import FileConfiguration from ..utils.common import FileConfiguration
@ -18,7 +17,7 @@ class SupervisorJob(CoreSysAttributes):
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.name: str = name self.name: str = name
self._progress: int = 0 self._progress: int = 0
self._stage: Optional[str] = None self._stage: str | None = None
@property @property
def progress(self) -> int: def progress(self) -> int:
@ -26,13 +25,11 @@ class SupervisorJob(CoreSysAttributes):
return self._progress return self._progress
@property @property
def stage(self) -> Optional[str]: def stage(self) -> str | None:
"""Return the current stage.""" """Return the current stage."""
return self._stage return self._stage
def update( def update(self, progress: int | None = None, stage: str | None = None) -> None:
self, progress: Optional[int] = None, stage: Optional[str] = None
) -> None:
"""Update the job object.""" """Update the job object."""
if progress is not None: if progress is not None:
if progress >= round(100): if progress >= round(100):

View File

@ -3,7 +3,7 @@ import asyncio
from datetime import datetime, timedelta from datetime import datetime, timedelta
from functools import wraps from functools import wraps
import logging import logging
from typing import Any, Optional from typing import Any
import sentry_sdk import sentry_sdk
@ -22,13 +22,13 @@ class Job(CoreSysAttributes):
def __init__( def __init__(
self, self,
name: Optional[str] = None, name: str | None = None,
conditions: Optional[list[JobCondition]] = None, conditions: list[JobCondition] | None = None,
cleanup: bool = True, cleanup: bool = True,
on_condition: Optional[JobException] = None, on_condition: JobException | None = None,
limit: Optional[JobExecutionLimit] = None, limit: JobExecutionLimit | None = None,
throttle_period: Optional[timedelta] = None, throttle_period: timedelta | None = None,
throttle_max_calls: Optional[int] = None, throttle_max_calls: int | None = None,
): ):
"""Initialize the Job class.""" """Initialize the Job class."""
self.name = name self.name = name
@ -38,10 +38,10 @@ class Job(CoreSysAttributes):
self.limit = limit self.limit = limit
self.throttle_period = throttle_period self.throttle_period = throttle_period
self.throttle_max_calls = throttle_max_calls self.throttle_max_calls = throttle_max_calls
self._lock: Optional[asyncio.Semaphore] = None self._lock: asyncio.Semaphore | None = None
self._method = None self._method = None
self._last_call = datetime.min self._last_call = datetime.min
self._rate_limited_calls: Optional[list[datetime]] = None self._rate_limited_calls: list[datetime] | None = None
# Validate Options # Validate Options
if ( if (

View File

@ -2,7 +2,7 @@
import asyncio import asyncio
from datetime import date, datetime, time, timedelta from datetime import date, datetime, time, timedelta
import logging import logging
from typing import Awaitable, Callable, Optional, Union from typing import Awaitable, Callable
from uuid import UUID, uuid4 from uuid import UUID, uuid4
import async_timeout import async_timeout
@ -20,10 +20,10 @@ class _Task:
id: UUID = attr.ib() id: UUID = attr.ib()
coro_callback: Callable[..., Awaitable[None]] = attr.ib(eq=False) coro_callback: Callable[..., Awaitable[None]] = attr.ib(eq=False)
interval: Union[float, time] = attr.ib(eq=False) interval: float | time = attr.ib(eq=False)
repeat: bool = attr.ib(eq=False) repeat: bool = attr.ib(eq=False)
job: Optional[asyncio.tasks.Task] = attr.ib(eq=False) job: asyncio.tasks.Task | None = attr.ib(eq=False)
next: Optional[asyncio.TimerHandle] = attr.ib(eq=False) next: asyncio.TimerHandle | None = attr.ib(eq=False)
class Scheduler(CoreSysAttributes): class Scheduler(CoreSysAttributes):
@ -37,7 +37,7 @@ class Scheduler(CoreSysAttributes):
def register_task( def register_task(
self, self,
coro_callback: Callable[..., Awaitable[None]], coro_callback: Callable[..., Awaitable[None]],
interval: Union[float, time], interval: float | time,
repeat: bool = True, repeat: bool = True,
) -> UUID: ) -> UUID:
"""Schedule a coroutine. """Schedule a coroutine.

View File

@ -1,7 +1,6 @@
"""Home Assistant Operating-System DataDisk.""" """Home Assistant Operating-System DataDisk."""
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Optional
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -29,7 +28,7 @@ class DataDisk(CoreSysAttributes):
self.coresys = coresys self.coresys = coresys
@property @property
def disk_used(self) -> Optional[Path]: def disk_used(self) -> Path | None:
"""Return Path to used Disk for data.""" """Return Path to used Disk for data."""
return self.sys_dbus.agent.datadisk.current_device return self.sys_dbus.agent.datadisk.current_device

View File

@ -2,7 +2,7 @@
import asyncio import asyncio
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Awaitable, Optional from typing import Awaitable
import aiohttp import aiohttp
from awesomeversion import AwesomeVersion, AwesomeVersionException from awesomeversion import AwesomeVersion, AwesomeVersionException
@ -26,9 +26,9 @@ class OSManager(CoreSysAttributes):
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self._datadisk: DataDisk = DataDisk(coresys) self._datadisk: DataDisk = DataDisk(coresys)
self._available: bool = False self._available: bool = False
self._version: Optional[AwesomeVersion] = None self._version: AwesomeVersion | None = None
self._board: Optional[str] = None self._board: str | None = None
self._os_name: Optional[str] = None self._os_name: str | None = None
@property @property
def available(self) -> bool: def available(self) -> bool:
@ -36,12 +36,12 @@ class OSManager(CoreSysAttributes):
return self._available return self._available
@property @property
def version(self) -> Optional[AwesomeVersion]: def version(self) -> AwesomeVersion | None:
"""Return version of HassOS.""" """Return version of HassOS."""
return self._version return self._version
@property @property
def latest_version(self) -> Optional[AwesomeVersion]: def latest_version(self) -> AwesomeVersion | None:
"""Return version of HassOS.""" """Return version of HassOS."""
return self.sys_updater.version_hassos return self.sys_updater.version_hassos
@ -54,12 +54,12 @@ class OSManager(CoreSysAttributes):
return False return False
@property @property
def board(self) -> Optional[str]: def board(self) -> str | None:
"""Return board name.""" """Return board name."""
return self._board return self._board
@property @property
def os_name(self) -> Optional[str]: def os_name(self) -> str | None:
"""Return OS name.""" """Return OS name."""
return self._os_name return self._os_name
@ -178,7 +178,7 @@ class OSManager(CoreSysAttributes):
limit=JobExecutionLimit.ONCE, limit=JobExecutionLimit.ONCE,
on_condition=HassOSJobError, on_condition=HassOSJobError,
) )
async def update(self, version: Optional[AwesomeVersion] = None) -> None: async def update(self, version: AwesomeVersion | None = None) -> None:
"""Update HassOS system.""" """Update HassOS system."""
version = version or self.latest_version version = version or self.latest_version

View File

@ -7,7 +7,6 @@ from contextlib import suppress
import logging import logging
from pathlib import Path, PurePath from pathlib import Path, PurePath
import shutil import shutil
from typing import Optional
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
import jinja2 import jinja2
@ -38,8 +37,10 @@ from .validate import SCHEMA_AUDIO_CONFIG
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
# pylint: disable=no-member
PULSE_CLIENT_TMPL: Path = Path(__file__).parents[1].joinpath("data/pulse-client.tmpl") PULSE_CLIENT_TMPL: Path = Path(__file__).parents[1].joinpath("data/pulse-client.tmpl")
ASOUND_TMPL: Path = Path(__file__).parents[1].joinpath("data/asound.tmpl") ASOUND_TMPL: Path = Path(__file__).parents[1].joinpath("data/asound.tmpl")
# pylint: enable=no-member
class PluginAudio(PluginBase): class PluginAudio(PluginBase):
@ -51,7 +52,7 @@ class PluginAudio(PluginBase):
self.slug = "audio" self.slug = "audio"
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.instance: DockerAudio = DockerAudio(coresys) self.instance: DockerAudio = DockerAudio(coresys)
self.client_template: Optional[jinja2.Template] = None self.client_template: jinja2.Template | None = None
@property @property
def path_extern_pulse(self) -> PurePath: def path_extern_pulse(self) -> PurePath:
@ -69,7 +70,7 @@ class PluginAudio(PluginBase):
return Path(self.sys_config.path_audio, "pulse_audio.json") return Path(self.sys_config.path_audio, "pulse_audio.json")
@property @property
def latest_version(self) -> Optional[AwesomeVersion]: def latest_version(self) -> AwesomeVersion | None:
"""Return latest version of Audio.""" """Return latest version of Audio."""
return self.sys_updater.version_audio return self.sys_updater.version_audio
@ -117,7 +118,7 @@ class PluginAudio(PluginBase):
conditions=PLUGIN_UPDATE_CONDITIONS, conditions=PLUGIN_UPDATE_CONDITIONS,
on_condition=AudioJobError, on_condition=AudioJobError,
) )
async def update(self, version: Optional[str] = None) -> None: async def update(self, version: str | None = None) -> None:
"""Update Audio plugin.""" """Update Audio plugin."""
version = version or self.latest_version version = version or self.latest_version
old_image = self.image old_image = self.image

View File

@ -3,7 +3,7 @@ from abc import ABC, abstractmethod
import asyncio import asyncio
from contextlib import suppress from contextlib import suppress
import logging import logging
from typing import Awaitable, Optional from typing import Awaitable
from awesomeversion import AwesomeVersion, AwesomeVersionException from awesomeversion import AwesomeVersion, AwesomeVersionException
@ -26,7 +26,7 @@ class PluginBase(ABC, FileConfiguration, CoreSysAttributes):
instance: DockerInterface instance: DockerInterface
@property @property
def version(self) -> Optional[AwesomeVersion]: def version(self) -> AwesomeVersion | None:
"""Return current version of the plugin.""" """Return current version of the plugin."""
return self._data.get(ATTR_VERSION) return self._data.get(ATTR_VERSION)
@ -49,7 +49,7 @@ class PluginBase(ABC, FileConfiguration, CoreSysAttributes):
@property @property
@abstractmethod @abstractmethod
def latest_version(self) -> Optional[AwesomeVersion]: def latest_version(self) -> AwesomeVersion | None:
"""Return latest version of the plugin.""" """Return latest version of the plugin."""
@property @property
@ -189,7 +189,7 @@ class PluginBase(ABC, FileConfiguration, CoreSysAttributes):
"""Install system plugin.""" """Install system plugin."""
@abstractmethod @abstractmethod
async def update(self, version: Optional[str] = None) -> None: async def update(self, version: str | None = None) -> None:
"""Update system plugin.""" """Update system plugin."""
@abstractmethod @abstractmethod

View File

@ -6,7 +6,7 @@ import asyncio
from contextlib import suppress from contextlib import suppress
import logging import logging
import secrets import secrets
from typing import Awaitable, Optional from typing import Awaitable
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -41,7 +41,7 @@ class PluginCli(PluginBase):
self.instance: DockerCli = DockerCli(coresys) self.instance: DockerCli = DockerCli(coresys)
@property @property
def latest_version(self) -> Optional[AwesomeVersion]: def latest_version(self) -> AwesomeVersion | None:
"""Return version of latest cli.""" """Return version of latest cli."""
return self.sys_updater.version_cli return self.sys_updater.version_cli
@ -77,7 +77,7 @@ class PluginCli(PluginBase):
conditions=PLUGIN_UPDATE_CONDITIONS, conditions=PLUGIN_UPDATE_CONDITIONS,
on_condition=CliJobError, on_condition=CliJobError,
) )
async def update(self, version: Optional[AwesomeVersion] = None) -> None: async def update(self, version: AwesomeVersion | None = None) -> None:
"""Update local HA cli.""" """Update local HA cli."""
version = version or self.latest_version version = version or self.latest_version
old_image = self.image old_image = self.image

View File

@ -7,7 +7,6 @@ from contextlib import suppress
from ipaddress import IPv4Address from ipaddress import IPv4Address
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Optional
import attr import attr
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -45,8 +44,10 @@ from .validate import SCHEMA_DNS_CONFIG
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
# pylint: disable=no-member
HOSTS_TMPL: Path = Path(__file__).parents[1].joinpath("data/hosts.tmpl") HOSTS_TMPL: Path = Path(__file__).parents[1].joinpath("data/hosts.tmpl")
RESOLV_TMPL: Path = Path(__file__).parents[1].joinpath("data/resolv.tmpl") RESOLV_TMPL: Path = Path(__file__).parents[1].joinpath("data/resolv.tmpl")
# pylint: enable=no-member
HOST_RESOLV: Path = Path("/etc/resolv.conf") HOST_RESOLV: Path = Path("/etc/resolv.conf")
@ -67,8 +68,8 @@ class PluginDns(PluginBase):
self.slug = "dns" self.slug = "dns"
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.instance: DockerDNS = DockerDNS(coresys) self.instance: DockerDNS = DockerDNS(coresys)
self.resolv_template: Optional[jinja2.Template] = None self.resolv_template: jinja2.Template | None = None
self.hosts_template: Optional[jinja2.Template] = None self.hosts_template: jinja2.Template | None = None
self._hosts: list[HostEntry] = [] self._hosts: list[HostEntry] = []
self._loop: bool = False self._loop: bool = False
@ -106,7 +107,7 @@ class PluginDns(PluginBase):
self._data[ATTR_SERVERS] = value self._data[ATTR_SERVERS] = value
@property @property
def latest_version(self) -> Optional[AwesomeVersion]: def latest_version(self) -> AwesomeVersion | None:
"""Return latest version of CoreDNS.""" """Return latest version of CoreDNS."""
return self.sys_updater.version_dns return self.sys_updater.version_dns
@ -184,7 +185,7 @@ class PluginDns(PluginBase):
conditions=PLUGIN_UPDATE_CONDITIONS, conditions=PLUGIN_UPDATE_CONDITIONS,
on_condition=CoreDNSJobError, on_condition=CoreDNSJobError,
) )
async def update(self, version: Optional[AwesomeVersion] = None) -> None: async def update(self, version: AwesomeVersion | None = None) -> None:
"""Update CoreDNS plugin.""" """Update CoreDNS plugin."""
version = version or self.latest_version version = version or self.latest_version
old_image = self.image old_image = self.image
@ -390,7 +391,7 @@ class PluginDns(PluginBase):
if write: if write:
self.write_hosts() self.write_hosts()
def _search_host(self, names: list[str]) -> Optional[HostEntry]: def _search_host(self, names: list[str]) -> HostEntry | None:
"""Search a host entry.""" """Search a host entry."""
for entry in self._hosts: for entry in self._hosts:
for name in names: for name in names:

View File

@ -5,7 +5,6 @@ Code: https://github.com/home-assistant/plugin-multicast
import asyncio import asyncio
from contextlib import suppress from contextlib import suppress
import logging import logging
from typing import Optional
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -44,7 +43,7 @@ class PluginMulticast(PluginBase):
self.instance: DockerMulticast = DockerMulticast(coresys) self.instance: DockerMulticast = DockerMulticast(coresys)
@property @property
def latest_version(self) -> Optional[AwesomeVersion]: def latest_version(self) -> AwesomeVersion | None:
"""Return latest version of Multicast.""" """Return latest version of Multicast."""
return self.sys_updater.version_multicast return self.sys_updater.version_multicast
@ -74,7 +73,7 @@ class PluginMulticast(PluginBase):
conditions=PLUGIN_UPDATE_CONDITIONS, conditions=PLUGIN_UPDATE_CONDITIONS,
on_condition=MulticastJobError, on_condition=MulticastJobError,
) )
async def update(self, version: Optional[AwesomeVersion] = None) -> None: async def update(self, version: AwesomeVersion | None = None) -> None:
"""Update Multicast plugin.""" """Update Multicast plugin."""
version = version or self.latest_version version = version or self.latest_version
old_image = self.image old_image = self.image

View File

@ -6,7 +6,6 @@ import asyncio
from contextlib import suppress from contextlib import suppress
import logging import logging
import secrets import secrets
from typing import Optional
import aiohttp import aiohttp
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -47,7 +46,7 @@ class PluginObserver(PluginBase):
self.instance: DockerObserver = DockerObserver(coresys) self.instance: DockerObserver = DockerObserver(coresys)
@property @property
def latest_version(self) -> Optional[AwesomeVersion]: def latest_version(self) -> AwesomeVersion | None:
"""Return version of latest observer.""" """Return version of latest observer."""
return self.sys_updater.version_observer return self.sys_updater.version_observer
@ -82,7 +81,7 @@ class PluginObserver(PluginBase):
conditions=PLUGIN_UPDATE_CONDITIONS, conditions=PLUGIN_UPDATE_CONDITIONS,
on_condition=ObserverJobError, on_condition=ObserverJobError,
) )
async def update(self, version: Optional[AwesomeVersion] = None) -> None: async def update(self, version: AwesomeVersion | None = None) -> None:
"""Update local HA observer.""" """Update local HA observer."""
version = version or self.latest_version version = version or self.latest_version
old_image = self.image old_image = self.image

View File

@ -1,7 +1,6 @@
"""Helpers to check core security.""" """Helpers to check core security."""
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Optional
from ...const import AddonState, CoreState from ...const import AddonState, CoreState
from ...coresys import CoreSys from ...coresys import CoreSys
@ -64,7 +63,7 @@ class CheckAddonPwned(CheckBase):
pass pass
@Job(conditions=[JobCondition.INTERNET_SYSTEM]) @Job(conditions=[JobCondition.INTERNET_SYSTEM])
async def approve_check(self, reference: Optional[str] = None) -> bool: async def approve_check(self, reference: str | None = None) -> bool:
"""Approve check if it is affected by issue.""" """Approve check if it is affected by issue."""
addon = self.sys_addons.get(reference) addon = self.sys_addons.get(reference)

View File

@ -1,7 +1,6 @@
"""Baseclass for system checks.""" """Baseclass for system checks."""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
import logging import logging
from typing import Optional
from ...const import ATTR_ENABLED, CoreState from ...const import ATTR_ENABLED, CoreState
from ...coresys import CoreSys, CoreSysAttributes from ...coresys import CoreSys, CoreSysAttributes
@ -60,7 +59,7 @@ class CheckBase(ABC, CoreSysAttributes):
"""Run check if not affected by issue.""" """Run check if not affected by issue."""
@abstractmethod @abstractmethod
async def approve_check(self, reference: Optional[str] = None) -> bool: async def approve_check(self, reference: str | None = None) -> bool:
"""Approve check if it is affected by issue.""" """Approve check if it is affected by issue."""
@property @property

View File

@ -1,7 +1,6 @@
"""Helpers to check core security.""" """Helpers to check core security."""
from enum import Enum from enum import Enum
from pathlib import Path from pathlib import Path
from typing import Optional
from awesomeversion import AwesomeVersion, AwesomeVersionException from awesomeversion import AwesomeVersion, AwesomeVersionException
@ -42,7 +41,7 @@ class CheckCoreSecurity(CheckBase):
except (AwesomeVersionException, OSError): except (AwesomeVersionException, OSError):
return return
async def approve_check(self, reference: Optional[str] = None) -> bool: async def approve_check(self, reference: str | None = None) -> bool:
"""Approve check if it is affected by issue.""" """Approve check if it is affected by issue."""
try: try:
if self.sys_homeassistant.version >= AwesomeVersion("2021.1.5"): if self.sys_homeassistant.version >= AwesomeVersion("2021.1.5"):

View File

@ -1,7 +1,6 @@
"""Helpers to check DNS servers for failure.""" """Helpers to check DNS servers for failure."""
import asyncio import asyncio
from datetime import timedelta from datetime import timedelta
from typing import Optional
from aiodns import DNSResolver from aiodns import DNSResolver
from aiodns.error import DNSError from aiodns.error import DNSError
@ -43,7 +42,7 @@ class CheckDNSServerFailures(CheckBase):
self.sys_capture_exception(results[i]) self.sys_capture_exception(results[i])
@Job(conditions=[JobCondition.INTERNET_SYSTEM]) @Job(conditions=[JobCondition.INTERNET_SYSTEM])
async def approve_check(self, reference: Optional[str] = None) -> bool: async def approve_check(self, reference: str | None = None) -> bool:
"""Approve check if it is affected by issue.""" """Approve check if it is affected by issue."""
if reference not in self.dns_servers: if reference not in self.dns_servers:
return False return False

View File

@ -1,7 +1,6 @@
"""Helpers to check DNS servers for IPv6 errors.""" """Helpers to check DNS servers for IPv6 errors."""
import asyncio import asyncio
from datetime import timedelta from datetime import timedelta
from typing import Optional
from aiodns import DNSResolver from aiodns import DNSResolver
from aiodns.error import DNSError from aiodns.error import DNSError
@ -48,7 +47,7 @@ class CheckDNSServerIPv6Errors(CheckBase):
self.sys_capture_exception(results[i]) self.sys_capture_exception(results[i])
@Job(conditions=[JobCondition.INTERNET_SYSTEM]) @Job(conditions=[JobCondition.INTERNET_SYSTEM])
async def approve_check(self, reference: Optional[str] = None) -> bool: async def approve_check(self, reference: str | None = None) -> bool:
"""Approve check if it is affected by issue.""" """Approve check if it is affected by issue."""
if reference not in self.dns_servers: if reference not in self.dns_servers:
return False return False

View File

@ -1,6 +1,4 @@
"""Helpers to check and fix issues with free space.""" """Helpers to check and fix issues with free space."""
from typing import Optional
from ...backups.const import BackupType from ...backups.const import BackupType
from ...const import CoreState from ...const import CoreState
from ...coresys import CoreSys from ...coresys import CoreSys
@ -50,7 +48,7 @@ class CheckFreeSpace(CheckBase):
IssueType.FREE_SPACE, ContextType.SYSTEM, suggestions=suggestions IssueType.FREE_SPACE, ContextType.SYSTEM, suggestions=suggestions
) )
async def approve_check(self, reference: Optional[str] = None) -> bool: async def approve_check(self, reference: str | None = None) -> bool:
"""Approve check if it is affected by issue.""" """Approve check if it is affected by issue."""
if self.sys_host.info.free_space > MINIMUM_FREE_SPACE_THRESHOLD: if self.sys_host.info.free_space > MINIMUM_FREE_SPACE_THRESHOLD:
return False return False

View File

@ -1,6 +1,5 @@
"""Helpers to check supervisor trust.""" """Helpers to check supervisor trust."""
import logging import logging
from typing import Optional
from ...const import CoreState from ...const import CoreState
from ...coresys import CoreSys from ...coresys import CoreSys
@ -35,7 +34,7 @@ class CheckSupervisorTrust(CheckBase):
except CodeNotaryError: except CodeNotaryError:
pass pass
async def approve_check(self, reference: Optional[str] = None) -> bool: async def approve_check(self, reference: str | None = None) -> bool:
"""Approve check if it is affected by issue.""" """Approve check if it is affected by issue."""
try: try:
await self.sys_supervisor.check_trust() await self.sys_supervisor.check_trust()

View File

@ -1,5 +1,4 @@
"""Data objects.""" """Data objects."""
from typing import Optional
from uuid import UUID, uuid4 from uuid import UUID, uuid4
import attr import attr
@ -13,7 +12,7 @@ class Issue:
type: IssueType = attr.ib() type: IssueType = attr.ib()
context: ContextType = attr.ib() context: ContextType = attr.ib()
reference: Optional[str] = attr.ib(default=None) reference: str | None = attr.ib(default=None)
uuid: UUID = attr.ib(factory=lambda: uuid4().hex, eq=False, init=False) uuid: UUID = attr.ib(factory=lambda: uuid4().hex, eq=False, init=False)
@ -23,5 +22,5 @@ class Suggestion:
type: SuggestionType = attr.ib() type: SuggestionType = attr.ib()
context: ContextType = attr.ib() context: ContextType = attr.ib()
reference: Optional[str] = attr.ib(default=None) reference: str | None = attr.ib(default=None)
uuid: UUID = attr.ib(factory=lambda: uuid4().hex, eq=False, init=False) uuid: UUID = attr.ib(factory=lambda: uuid4().hex, eq=False, init=False)

View File

@ -1,7 +1,6 @@
"""Baseclass for system fixup.""" """Baseclass for system fixup."""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
import logging import logging
from typing import Optional
from ...coresys import CoreSys, CoreSysAttributes from ...coresys import CoreSys, CoreSysAttributes
from ...exceptions import ResolutionFixupError from ...exceptions import ResolutionFixupError
@ -21,7 +20,7 @@ class FixupBase(ABC, CoreSysAttributes):
async def __call__(self) -> None: async def __call__(self) -> None:
"""Execute the evaluation.""" """Execute the evaluation."""
# Get suggestion to fix # Get suggestion to fix
fixing_suggestion: Optional[Suggestion] = None fixing_suggestion: Suggestion | None = None
for suggestion in self.sys_resolution.suggestions: for suggestion in self.sys_resolution.suggestions:
if suggestion.type != self.suggestion or suggestion.context != self.context: if suggestion.type != self.suggestion or suggestion.context != self.context:
continue continue
@ -49,7 +48,7 @@ class FixupBase(ABC, CoreSysAttributes):
self.sys_resolution.dismiss_issue(issue) self.sys_resolution.dismiss_issue(issue)
@abstractmethod @abstractmethod
async def process_fixup(self, reference: Optional[str] = None) -> None: async def process_fixup(self, reference: str | None = None) -> None:
"""Run processing of fixup.""" """Run processing of fixup."""
@property @property

View File

@ -1,6 +1,5 @@
"""Helpers to check and fix issues with free space.""" """Helpers to check and fix issues with free space."""
import logging import logging
from typing import Optional
from ...coresys import CoreSys from ...coresys import CoreSys
from ...exceptions import ( from ...exceptions import (
@ -29,7 +28,7 @@ class FixupStoreExecuteReload(FixupBase):
conditions=[JobCondition.INTERNET_SYSTEM, JobCondition.FREE_SPACE], conditions=[JobCondition.INTERNET_SYSTEM, JobCondition.FREE_SPACE],
on_condition=ResolutionFixupJobError, on_condition=ResolutionFixupJobError,
) )
async def process_fixup(self, reference: Optional[str] = None) -> None: async def process_fixup(self, reference: str | None = None) -> None:
"""Initialize the fixup class.""" """Initialize the fixup class."""
_LOGGER.info("Reload Store: %s", reference) _LOGGER.info("Reload Store: %s", reference)
try: try:

View File

@ -1,6 +1,5 @@
"""Helpers to check and fix issues with free space.""" """Helpers to check and fix issues with free space."""
import logging import logging
from typing import Optional
from ...coresys import CoreSys from ...coresys import CoreSys
from ...exceptions import ResolutionFixupError, StoreError, StoreNotFound from ...exceptions import ResolutionFixupError, StoreError, StoreNotFound
@ -18,7 +17,7 @@ def setup(coresys: CoreSys) -> FixupBase:
class FixupStoreExecuteRemove(FixupBase): class FixupStoreExecuteRemove(FixupBase):
"""Storage class for fixup.""" """Storage class for fixup."""
async def process_fixup(self, reference: Optional[str] = None) -> None: async def process_fixup(self, reference: str | None = None) -> None:
"""Initialize the fixup class.""" """Initialize the fixup class."""
_LOGGER.info("Remove invalid Store: %s", reference) _LOGGER.info("Remove invalid Store: %s", reference)
try: try:

View File

@ -1,6 +1,5 @@
"""Helpers to check and fix issues with free space.""" """Helpers to check and fix issues with free space."""
import logging import logging
from typing import Optional
from ...coresys import CoreSys from ...coresys import CoreSys
from ...exceptions import ( from ...exceptions import (
@ -30,7 +29,7 @@ class FixupStoreExecuteReset(FixupBase):
conditions=[JobCondition.INTERNET_SYSTEM, JobCondition.FREE_SPACE], conditions=[JobCondition.INTERNET_SYSTEM, JobCondition.FREE_SPACE],
on_condition=ResolutionFixupJobError, on_condition=ResolutionFixupJobError,
) )
async def process_fixup(self, reference: Optional[str] = None) -> None: async def process_fixup(self, reference: str | None = None) -> None:
"""Initialize the fixup class.""" """Initialize the fixup class."""
_LOGGER.info("Reset corrupt Store: %s", reference) _LOGGER.info("Reset corrupt Store: %s", reference)
try: try:

View File

@ -1,6 +1,5 @@
"""Helpers to check and fix issues with free space.""" """Helpers to check and fix issues with free space."""
import logging import logging
from typing import Optional
from ...backups.const import BackupType from ...backups.const import BackupType
from ...coresys import CoreSys from ...coresys import CoreSys
@ -18,7 +17,7 @@ def setup(coresys: CoreSys) -> FixupBase:
class FixupSystemClearFullBackup(FixupBase): class FixupSystemClearFullBackup(FixupBase):
"""Storage class for fixup.""" """Storage class for fixup."""
async def process_fixup(self, reference: Optional[str] = None) -> None: async def process_fixup(self, reference: str | None = None) -> None:
"""Initialize the fixup class.""" """Initialize the fixup class."""
full_backups = [ full_backups = [
x for x in self.sys_backups.list_backups if x.sys_type == BackupType.FULL x for x in self.sys_backups.list_backups if x.sys_type == BackupType.FULL

View File

@ -1,6 +1,5 @@
"""Helpers to check and fix issues with free space.""" """Helpers to check and fix issues with free space."""
import logging import logging
from typing import Optional
from ...coresys import CoreSys from ...coresys import CoreSys
from ..const import ContextType, SuggestionType from ..const import ContextType, SuggestionType
@ -17,7 +16,7 @@ def setup(coresys: CoreSys) -> FixupBase:
class FixupSystemCreateFullBackup(FixupBase): class FixupSystemCreateFullBackup(FixupBase):
"""Storage class for fixup.""" """Storage class for fixup."""
async def process_fixup(self, reference: Optional[str] = None) -> None: async def process_fixup(self, reference: str | None = None) -> None:
"""Initialize the fixup class.""" """Initialize the fixup class."""
_LOGGER.info("Creating a full backup") _LOGGER.info("Creating a full backup")
await self.sys_backups.do_backup_full() await self.sys_backups.do_backup_full()

View File

@ -1,7 +1,6 @@
"""Helpers to check and fix issues with free space.""" """Helpers to check and fix issues with free space."""
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Optional
from ...coresys import CoreSys from ...coresys import CoreSys
from ...exceptions import ResolutionFixupError, ResolutionFixupJobError from ...exceptions import ResolutionFixupError, ResolutionFixupJobError
@ -28,7 +27,7 @@ class FixupSystemExecuteIntegrity(FixupBase):
limit=JobExecutionLimit.THROTTLE, limit=JobExecutionLimit.THROTTLE,
throttle_period=timedelta(hours=8), throttle_period=timedelta(hours=8),
) )
async def process_fixup(self, reference: Optional[str] = None) -> None: async def process_fixup(self, reference: str | None = None) -> None:
"""Initialize the fixup class.""" """Initialize the fixup class."""
result = await self.sys_security.integrity_check() result = await self.sys_security.integrity_check()

View File

@ -1,6 +1,6 @@
"""Supervisor resolution center.""" """Supervisor resolution center."""
import logging import logging
from typing import Any, Optional from typing import Any
from ..coresys import CoreSys, CoreSysAttributes from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import ResolutionError, ResolutionNotFound from ..exceptions import ResolutionError, ResolutionNotFound
@ -142,8 +142,8 @@ class ResolutionManager(FileConfiguration, CoreSysAttributes):
self, self,
issue: IssueType, issue: IssueType,
context: ContextType, context: ContextType,
reference: Optional[str] = None, reference: str | None = None,
suggestions: Optional[list[SuggestionType]] = None, suggestions: list[SuggestionType] | None = None,
) -> None: ) -> None:
"""Create issues and suggestion.""" """Create issues and suggestion."""
self.issues = Issue(issue, context, reference) self.issues = Issue(issue, context, reference)

View File

@ -1,6 +1,4 @@
"""Handle internal services discovery.""" """Handle internal services discovery."""
from typing import Optional
from ..coresys import CoreSys, CoreSysAttributes from ..coresys import CoreSys, CoreSysAttributes
from .const import SERVICE_MQTT, SERVICE_MYSQL from .const import SERVICE_MQTT, SERVICE_MYSQL
from .data import ServicesData from .data import ServicesData
@ -25,7 +23,7 @@ class ServiceManager(CoreSysAttributes):
"""Return a list of services.""" """Return a list of services."""
return list(self.services_obj.values()) return list(self.services_obj.values())
def get(self, slug: str) -> Optional[ServiceInterface]: def get(self, slug: str) -> ServiceInterface | None:
"""Return service object from slug.""" """Return service object from slug."""
return self.services_obj.get(slug) return self.services_obj.get(slug)

View File

@ -1,6 +1,6 @@
"""Interface for single service.""" """Interface for single service."""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Any, Optional from typing import Any
import voluptuous as vol import voluptuous as vol
@ -54,7 +54,7 @@ class ServiceInterface(CoreSysAttributes, ABC):
"""Save changes.""" """Save changes."""
self.sys_services.data.save_data() self.sys_services.data.save_data()
def get_service_data(self) -> Optional[dict[str, Any]]: def get_service_data(self) -> dict[str, Any] | None:
"""Return the requested service data.""" """Return the requested service data."""
if self.enabled: if self.enabled:
return self._data return self._data

View File

@ -1,7 +1,7 @@
"""Init file for Supervisor add-on data.""" """Init file for Supervisor add-on data."""
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Any, Awaitable, Optional from typing import Any, Awaitable
import voluptuous as vol import voluptuous as vol
from voluptuous.humanize import humanize_error from voluptuous.humanize import humanize_error
@ -89,7 +89,7 @@ class StoreData(CoreSysAttributes):
self.repositories[slug] = repository_info self.repositories[slug] = repository_info
self._read_addons_folder(path, slug) self._read_addons_folder(path, slug)
def _find_addons(self, path: Path, repository: dict) -> Optional[list[Path]]: def _find_addons(self, path: Path, repository: dict) -> list[Path] | None:
"""Find add-ons in the path.""" """Find add-ons in the path."""
try: try:
# Generate a list without artefact, safe for corruptions # Generate a list without artefact, safe for corruptions

View File

@ -3,7 +3,6 @@ import asyncio
import functools as ft import functools as ft
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Optional
import git import git
@ -27,7 +26,7 @@ class GitRepo(CoreSysAttributes):
def __init__(self, coresys: CoreSys, path: Path, url: str): def __init__(self, coresys: CoreSys, path: Path, url: str):
"""Initialize Git base wrapper.""" """Initialize Git base wrapper."""
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.repo: Optional[git.Repo] = None self.repo: git.Repo | None = None
self.path: Path = path self.path: Path = path
self.lock: asyncio.Lock = asyncio.Lock() self.lock: asyncio.Lock = asyncio.Lock()

View File

@ -1,7 +1,6 @@
"""Represent a Supervisor repository.""" """Represent a Supervisor repository."""
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Optional
import voluptuous as vol import voluptuous as vol
@ -24,7 +23,7 @@ class Repository(CoreSysAttributes):
def __init__(self, coresys: CoreSys, repository: str): def __init__(self, coresys: CoreSys, repository: str):
"""Initialize repository object.""" """Initialize repository object."""
self.coresys: CoreSys = coresys self.coresys: CoreSys = coresys
self.git: Optional[GitRepo] = None self.git: GitRepo | None = None
self.source: str = repository self.source: str = repository
if repository == StoreType.LOCAL: if repository == StoreType.LOCAL:

View File

@ -5,7 +5,7 @@ from ipaddress import IPv4Address
import logging import logging
from pathlib import Path from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Awaitable, Optional from typing import Awaitable
import aiohttp import aiohttp
from aiohttp.client_exceptions import ClientError from aiohttp.client_exceptions import ClientError
@ -158,7 +158,7 @@ class Supervisor(CoreSysAttributes):
"Can't update AppArmor profile!", _LOGGER.error "Can't update AppArmor profile!", _LOGGER.error
) from err ) from err
async def update(self, version: Optional[AwesomeVersion] = None) -> None: async def update(self, version: AwesomeVersion | None = None) -> None:
"""Update Supervisor version.""" """Update Supervisor version."""
version = version or self.latest_version version = version or self.latest_version

View File

@ -4,7 +4,6 @@ from contextlib import suppress
from datetime import timedelta from datetime import timedelta
import json import json
import logging import logging
from typing import Optional
import aiohttp import aiohttp
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -60,47 +59,47 @@ class Updater(FileConfiguration, CoreSysAttributes):
await self.fetch_data() await self.fetch_data()
@property @property
def version_homeassistant(self) -> Optional[AwesomeVersion]: def version_homeassistant(self) -> AwesomeVersion | None:
"""Return latest version of Home Assistant.""" """Return latest version of Home Assistant."""
return self._data.get(ATTR_HOMEASSISTANT) return self._data.get(ATTR_HOMEASSISTANT)
@property @property
def version_supervisor(self) -> Optional[AwesomeVersion]: def version_supervisor(self) -> AwesomeVersion | None:
"""Return latest version of Supervisor.""" """Return latest version of Supervisor."""
return self._data.get(ATTR_SUPERVISOR) return self._data.get(ATTR_SUPERVISOR)
@property @property
def version_hassos(self) -> Optional[AwesomeVersion]: def version_hassos(self) -> AwesomeVersion | None:
"""Return latest version of HassOS.""" """Return latest version of HassOS."""
return self._data.get(ATTR_HASSOS) return self._data.get(ATTR_HASSOS)
@property @property
def version_cli(self) -> Optional[AwesomeVersion]: def version_cli(self) -> AwesomeVersion | None:
"""Return latest version of CLI.""" """Return latest version of CLI."""
return self._data.get(ATTR_CLI) return self._data.get(ATTR_CLI)
@property @property
def version_dns(self) -> Optional[AwesomeVersion]: def version_dns(self) -> AwesomeVersion | None:
"""Return latest version of DNS.""" """Return latest version of DNS."""
return self._data.get(ATTR_DNS) return self._data.get(ATTR_DNS)
@property @property
def version_audio(self) -> Optional[AwesomeVersion]: def version_audio(self) -> AwesomeVersion | None:
"""Return latest version of Audio.""" """Return latest version of Audio."""
return self._data.get(ATTR_AUDIO) return self._data.get(ATTR_AUDIO)
@property @property
def version_observer(self) -> Optional[AwesomeVersion]: def version_observer(self) -> AwesomeVersion | None:
"""Return latest version of Observer.""" """Return latest version of Observer."""
return self._data.get(ATTR_OBSERVER) return self._data.get(ATTR_OBSERVER)
@property @property
def version_multicast(self) -> Optional[AwesomeVersion]: def version_multicast(self) -> AwesomeVersion | None:
"""Return latest version of Multicast.""" """Return latest version of Multicast."""
return self._data.get(ATTR_MULTICAST) return self._data.get(ATTR_MULTICAST)
@property @property
def image_homeassistant(self) -> Optional[str]: def image_homeassistant(self) -> str | None:
"""Return image of Home Assistant docker.""" """Return image of Home Assistant docker."""
if ATTR_HOMEASSISTANT not in self._data[ATTR_IMAGE]: if ATTR_HOMEASSISTANT not in self._data[ATTR_IMAGE]:
return None return None
@ -109,7 +108,7 @@ class Updater(FileConfiguration, CoreSysAttributes):
) )
@property @property
def image_supervisor(self) -> Optional[str]: def image_supervisor(self) -> str | None:
"""Return image of Supervisor docker.""" """Return image of Supervisor docker."""
if ATTR_SUPERVISOR not in self._data[ATTR_IMAGE]: if ATTR_SUPERVISOR not in self._data[ATTR_IMAGE]:
return None return None
@ -118,28 +117,28 @@ class Updater(FileConfiguration, CoreSysAttributes):
) )
@property @property
def image_cli(self) -> Optional[str]: def image_cli(self) -> str | None:
"""Return image of CLI docker.""" """Return image of CLI docker."""
if ATTR_CLI not in self._data[ATTR_IMAGE]: if ATTR_CLI not in self._data[ATTR_IMAGE]:
return None return None
return self._data[ATTR_IMAGE][ATTR_CLI].format(arch=self.sys_arch.supervisor) return self._data[ATTR_IMAGE][ATTR_CLI].format(arch=self.sys_arch.supervisor)
@property @property
def image_dns(self) -> Optional[str]: def image_dns(self) -> str | None:
"""Return image of DNS docker.""" """Return image of DNS docker."""
if ATTR_DNS not in self._data[ATTR_IMAGE]: if ATTR_DNS not in self._data[ATTR_IMAGE]:
return None return None
return self._data[ATTR_IMAGE][ATTR_DNS].format(arch=self.sys_arch.supervisor) return self._data[ATTR_IMAGE][ATTR_DNS].format(arch=self.sys_arch.supervisor)
@property @property
def image_audio(self) -> Optional[str]: def image_audio(self) -> str | None:
"""Return image of Audio docker.""" """Return image of Audio docker."""
if ATTR_AUDIO not in self._data[ATTR_IMAGE]: if ATTR_AUDIO not in self._data[ATTR_IMAGE]:
return None return None
return self._data[ATTR_IMAGE][ATTR_AUDIO].format(arch=self.sys_arch.supervisor) return self._data[ATTR_IMAGE][ATTR_AUDIO].format(arch=self.sys_arch.supervisor)
@property @property
def image_observer(self) -> Optional[str]: def image_observer(self) -> str | None:
"""Return image of Observer docker.""" """Return image of Observer docker."""
if ATTR_OBSERVER not in self._data[ATTR_IMAGE]: if ATTR_OBSERVER not in self._data[ATTR_IMAGE]:
return None return None
@ -148,7 +147,7 @@ class Updater(FileConfiguration, CoreSysAttributes):
) )
@property @property
def image_multicast(self) -> Optional[str]: def image_multicast(self) -> str | None:
"""Return image of Multicast docker.""" """Return image of Multicast docker."""
if ATTR_MULTICAST not in self._data[ATTR_IMAGE]: if ATTR_MULTICAST not in self._data[ATTR_IMAGE]:
return None return None
@ -157,7 +156,7 @@ class Updater(FileConfiguration, CoreSysAttributes):
) )
@property @property
def ota_url(self) -> Optional[str]: def ota_url(self) -> str | None:
"""Return OTA url for OS.""" """Return OTA url for OS."""
return self._data.get(ATTR_OTA) return self._data.get(ATTR_OTA)

View File

@ -2,7 +2,7 @@
from contextlib import suppress from contextlib import suppress
from datetime import datetime, timedelta, timezone, tzinfo from datetime import datetime, timedelta, timezone, tzinfo
import re import re
from typing import Any, Optional from typing import Any
import zoneinfo import zoneinfo
import ciso8601 import ciso8601
@ -43,7 +43,7 @@ def parse_datetime(dt_str):
kws["microsecond"] = kws["microsecond"].ljust(6, "0") kws["microsecond"] = kws["microsecond"].ljust(6, "0")
tzinfo_str = kws.pop("tzinfo") tzinfo_str = kws.pop("tzinfo")
tzinfo_val: Optional[tzinfo] = None tzinfo_val: tzinfo | None = None
if tzinfo_str == "Z": if tzinfo_str == "Z":
tzinfo_val = UTC tzinfo_val = UTC
elif tzinfo_str is not None: elif tzinfo_str is not None:
@ -70,7 +70,7 @@ def utc_from_timestamp(timestamp: float) -> datetime:
return datetime.utcfromtimestamp(timestamp).replace(tzinfo=UTC) return datetime.utcfromtimestamp(timestamp).replace(tzinfo=UTC)
def get_time_zone(time_zone_str: str) -> Optional[tzinfo]: def get_time_zone(time_zone_str: str) -> tzinfo | None:
"""Get time zone from string. Return None if unable to determine.""" """Get time zone from string. Return None if unable to determine."""
try: try:
return zoneinfo.ZoneInfo(time_zone_str) return zoneinfo.ZoneInfo(time_zone_str)

View File

@ -1,7 +1,6 @@
"""Validate functions.""" """Validate functions."""
import ipaddress import ipaddress
import re import re
from typing import Optional, Union
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
import voluptuous as vol import voluptuous as vol
@ -57,8 +56,8 @@ token = vol.Match(r"^[0-9a-f]{32,256}$")
def version_tag( def version_tag(
value: Union[str, None, int, float, AwesomeVersion] value: str | None | int | float | AwesomeVersion,
) -> Optional[AwesomeVersion]: ) -> AwesomeVersion | None:
"""Validate main version handling.""" """Validate main version handling."""
if value is None: if value is None:
return None return None

View File

@ -1,7 +1,7 @@
"""Test docker events monitor.""" """Test docker events monitor."""
import asyncio import asyncio
from typing import Any, Optional from typing import Any
from unittest.mock import MagicMock, PropertyMock, patch from unittest.mock import MagicMock, PropertyMock, patch
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -84,7 +84,7 @@ from supervisor.docker.monitor import DockerContainerStateEvent
], ],
) )
async def test_events( async def test_events(
coresys: CoreSys, event: dict[str, Any], expected: Optional[ContainerState] coresys: CoreSys, event: dict[str, Any], expected: ContainerState | None
): ):
"""Test events created from docker events.""" """Test events created from docker events."""
event["Actor"]["Attributes"]["name"] = "some_container" event["Actor"]["Attributes"]["name"] = "some_container"

View File

@ -2,7 +2,6 @@
# pylint: disable=protected-access,import-error # pylint: disable=protected-access,import-error
import asyncio import asyncio
from datetime import timedelta from datetime import timedelta
from typing import Optional
from unittest.mock import PropertyMock, patch from unittest.mock import PropertyMock, patch
import pytest import pytest
@ -305,7 +304,7 @@ async def test_execution_limit_throttle_wait(
@pytest.mark.parametrize("error", [None, PluginJobError]) @pytest.mark.parametrize("error", [None, PluginJobError])
async def test_execution_limit_throttle_rate_limit( async def test_execution_limit_throttle_rate_limit(
coresys: CoreSys, loop: asyncio.BaseEventLoop, error: Optional[JobException] coresys: CoreSys, loop: asyncio.BaseEventLoop, error: JobException | None
): ):
"""Test the throttle wait job execution limit.""" """Test the throttle wait job execution limit."""