mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-23 17:16:33 +00:00
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:
parent
7754424cb8
commit
96065ed704
@ -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",
|
||||||
|
21
.github/workflows/builder.yml
vendored
21
.github/workflows/builder.yml
vendored
@ -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
|
||||||
|
6
.github/workflows/ci.yaml
vendored
6
.github/workflows/ci.yaml
vendored
@ -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
|
||||||
|
@ -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]
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
10
build.yaml
10
build.yaml
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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."""
|
||||||
|
@ -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 = {}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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]
|
||||||
|
@ -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.
|
||||||
|
@ -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":
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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":
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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}"
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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 (
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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"):
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
@ -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."""
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user