Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions pyoverkiz/_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

import functools
import re
from collections.abc import Callable
from typing import Any
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from collections.abc import Callable

_CAMEL_RE = re.compile(r"([A-Z]+)([A-Z][a-z])|([a-z\d])([A-Z])")

Expand Down
3 changes: 2 additions & 1 deletion pyoverkiz/action_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

import asyncio
import contextlib
from collections.abc import Callable, Coroutine, Generator
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any

from pyoverkiz.models import Action

if TYPE_CHECKING:
from collections.abc import Callable, Coroutine, Generator

from pyoverkiz.enums import ExecutionMode


Expand Down
6 changes: 4 additions & 2 deletions pyoverkiz/auth/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
from __future__ import annotations

import datetime
from collections.abc import Mapping
from dataclasses import dataclass, field
from typing import Any, Protocol
from typing import TYPE_CHECKING, Any, Protocol

if TYPE_CHECKING:
from collections.abc import Mapping


@dataclass(slots=True)
Expand Down
14 changes: 9 additions & 5 deletions pyoverkiz/auth/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

from __future__ import annotations

import ssl

from aiohttp import ClientSession
from typing import TYPE_CHECKING

from pyoverkiz.auth.credentials import (
Credentials,
Expand All @@ -24,15 +22,21 @@
SomfyAuthStrategy,
)
from pyoverkiz.enums import APIType, Server
from pyoverkiz.models import ServerConfig

if TYPE_CHECKING:
from ssl import SSLContext

from aiohttp import ClientSession

from pyoverkiz.models import ServerConfig


def build_auth_strategy(
*,
server_config: ServerConfig,
credentials: Credentials,
session: ClientSession,
ssl_context: ssl.SSLContext | bool,
ssl_context: SSLContext | bool,
) -> AuthStrategy:
"""Build the correct auth strategy for the given server and credentials."""
server: Server | None = server_config.server
Expand Down
32 changes: 17 additions & 15 deletions pyoverkiz/auth/strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,26 @@
import base64
import binascii
import json
import ssl
from collections.abc import Mapping
from http import HTTPStatus
from typing import TYPE_CHECKING, Any, cast

if TYPE_CHECKING:
from collections.abc import Mapping
from ssl import SSLContext

from botocore.client import BaseClient

from pyoverkiz.auth.credentials import (
LocalTokenCredentials,
RexelOAuthCodeCredentials,
TokenCredentials,
UsernamePasswordCredentials,
)
from pyoverkiz.models import ServerConfig

from aiohttp import ClientSession, FormData

from pyoverkiz.auth.base import AuthContext, AuthStrategy
from pyoverkiz.auth.credentials import (
LocalTokenCredentials,
RexelOAuthCodeCredentials,
TokenCredentials,
UsernamePasswordCredentials,
)
from pyoverkiz.const import (
COZYTOUCH_ATLANTIC_API,
COZYTOUCH_CLIENT_ID,
Expand All @@ -48,7 +51,6 @@
SomfyBadCredentialsError,
SomfyServiceError,
)
from pyoverkiz.models import ServerConfig

MIN_JWT_SEGMENTS = 2

Expand All @@ -60,7 +62,7 @@ def __init__(
self,
session: ClientSession,
server: ServerConfig,
ssl_context: ssl.SSLContext | bool,
ssl_context: SSLContext | bool,
) -> None:
"""Store shared auth context for Overkiz API interactions."""
self.session = session
Expand Down Expand Up @@ -92,7 +94,7 @@ def __init__(
credentials: UsernamePasswordCredentials,
session: ClientSession,
server: ServerConfig,
ssl_context: ssl.SSLContext | bool,
ssl_context: SSLContext | bool,
) -> None:
"""Create a session-login strategy bound to the given credentials."""
super().__init__(session, server, ssl_context)
Expand Down Expand Up @@ -135,7 +137,7 @@ def __init__(
credentials: UsernamePasswordCredentials,
session: ClientSession,
server: ServerConfig,
ssl_context: ssl.SSLContext | bool,
ssl_context: SSLContext | bool,
) -> None:
"""Create a Somfy OAuth2 strategy with a fresh auth context."""
super().__init__(session, server, ssl_context)
Expand Down Expand Up @@ -298,7 +300,7 @@ def __init__(
credentials: LocalTokenCredentials,
session: ClientSession,
server: ServerConfig,
ssl_context: ssl.SSLContext | bool,
ssl_context: SSLContext | bool,
) -> None:
"""Create a local-token strategy bound to the given credentials."""
super().__init__(session, server, ssl_context)
Expand All @@ -322,7 +324,7 @@ def __init__(
credentials: RexelOAuthCodeCredentials,
session: ClientSession,
server: ServerConfig,
ssl_context: ssl.SSLContext | bool,
ssl_context: SSLContext | bool,
) -> None:
"""Create a Rexel OAuth2 strategy with a fresh auth context."""
super().__init__(session, server, ssl_context)
Expand Down Expand Up @@ -406,7 +408,7 @@ def __init__(
credentials: TokenCredentials,
session: ClientSession,
server: ServerConfig,
ssl_context: ssl.SSLContext | bool,
ssl_context: SSLContext | bool,
) -> None:
"""Create a bearer-token strategy bound to the given credentials."""
super().__init__(session, server, ssl_context)
Expand Down
12 changes: 8 additions & 4 deletions pyoverkiz/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import urllib.parse
from http import HTTPStatus
from pathlib import Path
from types import TracebackType
from typing import Any, Self, cast
from typing import TYPE_CHECKING, Any, Self, cast

import backoff
from aiohttp import (
Expand All @@ -17,7 +16,6 @@
ClientSession,
ServerDisconnectedError,
)
from backoff.types import Details

from pyoverkiz._case import decamelize
from pyoverkiz.action_queue import ActionQueue, ActionQueueSettings
Expand Down Expand Up @@ -56,7 +54,13 @@
from pyoverkiz.obfuscate import obfuscate_sensitive_data
from pyoverkiz.response_handler import check_response
from pyoverkiz.serializers import prepare_payload
from pyoverkiz.types import JSON

if TYPE_CHECKING:
from types import TracebackType

from backoff.types import Details

from pyoverkiz.types import JSON

_LOGGER = logging.getLogger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion pyoverkiz/enums/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ def _missing_(cls, value: object) -> Self: # type: ignore[override]
message = cls.__missing_message__
logging.getLogger(cls.__module__).warning(message, value, cls)
# Type checker cannot infer UNKNOWN exists on Self, but all subclasses define it
return cast(Self, cls.UNKNOWN) # type: ignore[attr-defined]
return cast(Self, cls.UNKNOWN) # type: ignore[attr-defined] # ty: ignore[unresolved-attribute]
10 changes: 6 additions & 4 deletions pyoverkiz/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

import json
import re
from collections.abc import Iterator
from typing import Any, cast
from typing import TYPE_CHECKING, Any, cast

from attr import define, field

Expand All @@ -24,12 +23,15 @@
UpdateBoxStatus,
UpdateCriticityLevel,
)
from pyoverkiz.enums.command import OverkizCommand, OverkizCommandParam
from pyoverkiz.enums.command import OverkizCommand, OverkizCommandParam # noqa: TC001
from pyoverkiz.enums.protocol import Protocol
from pyoverkiz.enums.server import APIType, Server
from pyoverkiz.enums.server import APIType, Server # noqa: TC001
Comment on lines +26 to +28
from pyoverkiz.obfuscate import obfuscate_email, obfuscate_id, obfuscate_string
from pyoverkiz.types import DATA_TYPE_TO_PYTHON, StateType

if TYPE_CHECKING:
from collections.abc import Iterator

# ---------------------------------------------------------------------------
# State & command primitives
# ---------------------------------------------------------------------------
Expand Down
5 changes: 3 additions & 2 deletions pyoverkiz/obfuscate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from __future__ import annotations

import re
from typing import Any
from typing import TYPE_CHECKING, Any

from pyoverkiz.types import JSON
if TYPE_CHECKING:
from pyoverkiz.types import JSON


def obfuscate_id(id: str | None) -> str:
Expand Down
6 changes: 4 additions & 2 deletions pyoverkiz/response_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

from http import HTTPStatus
from json import JSONDecodeError

from aiohttp import ClientResponse
from typing import TYPE_CHECKING

from pyoverkiz.exceptions import (
AccessDeniedToGatewayError,
Expand Down Expand Up @@ -40,6 +39,9 @@
UnsupportedOperationError,
)

if TYPE_CHECKING:
from aiohttp import ClientResponse

# Primary dispatch: (errorCode, message_substring) -> error class.
# Checked in order; first match wins. Use errorCode as the primary key to
# reduce brittleness across cloud vs. local API variants.
Expand Down
6 changes: 4 additions & 2 deletions pyoverkiz/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
from __future__ import annotations

import json
from collections.abc import Callable
from typing import Any
from typing import TYPE_CHECKING, Any

from pyoverkiz.enums import DataType

if TYPE_CHECKING:
from collections.abc import Callable

StateType = str | int | float | bool | dict[str, Any] | list[Any] | None


Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ select = [
"A",
# pylint
"PL",
# flake8-type-checking
"TC",
]
ignore = [
"E501", # Line too long
Expand All @@ -133,6 +135,7 @@ ignore = [
"PLR0913", # Too many arguments — expected for API model constructors
"PLC0415", # Import not at top level — intentional lazy imports
"PLR0911", # Too many return statements — acceptable in factory functions
"TC006", # Quoting cast() types hurts IDE autocomplete for no real benefit
Comment thread
iMicknl marked this conversation as resolved.
]

[tool.ruff.lint.per-file-ignores]
Expand Down
12 changes: 7 additions & 5 deletions utils/generate_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
import re
import subprocess
from pathlib import Path
from typing import cast
from typing import TYPE_CHECKING

from pyoverkiz.auth.credentials import UsernamePasswordCredentials
from pyoverkiz.client import OverkizClient
from pyoverkiz.enums import Server
from pyoverkiz.exceptions import OverkizError
from pyoverkiz.models import UIProfileDefinition, ValuePrototype

if TYPE_CHECKING:
from pyoverkiz.models import UIProfileDefinition, ValuePrototype

# Hardcoded protocols that may not be available on all servers
# Each tuple contains: name, prefix, id, label
Expand Down Expand Up @@ -129,8 +131,8 @@ async def generate_ui_enums(server: Server) -> None:
) as client:
await client.login()

ui_classes = cast(list[str], await client.get_reference_ui_classes())
ui_widgets = cast(list[str], await client.get_reference_ui_widgets())
ui_classes = await client.get_reference_ui_classes()
ui_widgets = await client.get_reference_ui_widgets()

# Convert camelCase to SCREAMING_SNAKE_CASE for enum names
def to_enum_name(value: str) -> str:
Expand Down Expand Up @@ -210,7 +212,7 @@ def to_enum_name(value: str) -> str:
lines.append("") # End with newline

# Fetch and add UI classifiers
ui_classifiers = cast(list[str], await client.get_reference_ui_classifiers())
ui_classifiers = await client.get_reference_ui_classifiers()

lines.append("")
lines.append("@unique")
Expand Down
Loading