import base64
import logging
import os
-from typing import TYPE_CHECKING, Any, cast
+from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast, overload
from uuid import uuid4
import aiofiles
BASE_KEYS = ("enabled", "name", "available", "default_name", "provider", "type")
+# TypeVar for config value type inference
+_ConfigValueT = TypeVar("_ConfigValueT", bound=ConfigValueType)
+
isfile = wrap(os.path.isfile)
remove = wrap(os.remove)
rename = wrap(os.rename)
msg = f"No config found for provider id {instance_id}"
raise KeyError(msg)
+ @overload
+ async def get_provider_config_value(
+ self, instance_id: str, key: str, *, return_type: type[_ConfigValueT] = ...
+ ) -> _ConfigValueT: ...
+
+ @overload
+ async def get_provider_config_value(
+ self, instance_id: str, key: str, *, return_type: None = ...
+ ) -> ConfigValueType: ...
+
@api_command("config/providers/get_value")
- async def get_provider_config_value(self, instance_id: str, key: str) -> ConfigValueType:
- """Return single configentry value for a provider."""
+ async def get_provider_config_value(
+ self,
+ instance_id: str,
+ key: str,
+ *,
+ return_type: type[_ConfigValueT | ConfigValueType] | None = None,
+ ) -> _ConfigValueT | ConfigValueType:
+ """
+ Return single configentry value for a provider.
+
+ :param instance_id: The provider instance ID.
+ :param key: The config key to retrieve.
+ :param return_type: Optional type hint for type inference (e.g., str, int, bool).
+ Note: This parameter is used purely for static type checking and does not
+ perform runtime type validation. Callers are responsible for ensuring the
+ specified type matches the actual config value type.
+ """
cache_key = f"prov_conf_value_{instance_id}.{key}"
if (cached_value := self._value_cache.get(cache_key)) is not None:
return cached_value
return await player.get_config_entries(action=action, values=values)
+ @overload
+ async def get_player_config_value(
+ self,
+ player_id: str,
+ key: str,
+ unpack_splitted_values: Literal[True],
+ *,
+ return_type: type[_ConfigValueT] | None = ...,
+ ) -> tuple[str, ...] | list[tuple[str, ...]]: ...
+
+ @overload
+ async def get_player_config_value(
+ self,
+ player_id: str,
+ key: str,
+ unpack_splitted_values: Literal[False] = False,
+ *,
+ return_type: type[_ConfigValueT] = ...,
+ ) -> _ConfigValueT: ...
+
+ @overload
+ async def get_player_config_value(
+ self,
+ player_id: str,
+ key: str,
+ unpack_splitted_values: Literal[False] = False,
+ *,
+ return_type: None = ...,
+ ) -> ConfigValueType: ...
+
@api_command("config/players/get_value")
async def get_player_config_value(
self,
player_id: str,
key: str,
unpack_splitted_values: bool = False,
- ) -> ConfigValueType | tuple[str, ...] | list[tuple[str, ...]]:
- """Return single configentry value for a player."""
+ return_type: type[_ConfigValueT | ConfigValueType] | None = None,
+ ) -> _ConfigValueT | ConfigValueType | tuple[str, ...] | list[tuple[str, ...]]:
+ """
+ Return single configentry value for a player.
+
+ :param player_id: The player ID.
+ :param key: The config key to retrieve.
+ :param unpack_splitted_values: Whether to unpack multi-value config entries.
+ :param return_type: Optional type hint for type inference (e.g., str, int, bool).
+ Note: This parameter is used purely for static type checking and does not
+ perform runtime type validation. Callers are responsible for ensuring the
+ specified type matches the actual config value type.
+ """
conf = await self.get_player_config(player_id)
if unpack_splitted_values:
return conf.values[key].get_splitted_values()
else conf.values[key].default_value
)
+ if TYPE_CHECKING:
+ # Overload for when default is provided - return type matches default type
+ @overload
+ def get_raw_player_config_value(
+ self, player_id: str, key: str, default: _ConfigValueT
+ ) -> _ConfigValueT: ...
+
+ # Overload for when no default is provided - return ConfigValueType | None
+ @overload
+ def get_raw_player_config_value(
+ self, player_id: str, key: str, default: None = None
+ ) -> ConfigValueType | None: ...
+
def get_raw_player_config_value(
self, player_id: str, key: str, default: ConfigValueType = None
) -> ConfigValueType:
config_entries = await self.get_core_config_entries(domain)
return cast("CoreConfig", CoreConfig.parse(config_entries, raw_conf))
+ @overload
+ async def get_core_config_value(
+ self, domain: str, key: str, *, return_type: type[_ConfigValueT] = ...
+ ) -> _ConfigValueT: ...
+
+ @overload
+ async def get_core_config_value(
+ self, domain: str, key: str, *, return_type: None = ...
+ ) -> ConfigValueType: ...
+
@api_command("config/core/get_value")
- async def get_core_config_value(self, domain: str, key: str) -> ConfigValueType:
- """Return single configentry value for a core controller."""
+ async def get_core_config_value(
+ self,
+ domain: str,
+ key: str,
+ *,
+ return_type: type[_ConfigValueT | ConfigValueType] | None = None,
+ ) -> _ConfigValueT | ConfigValueType:
+ """
+ Return single configentry value for a core controller.
+
+ :param domain: The core controller domain.
+ :param key: The config key to retrieve.
+ :param return_type: Optional type hint for type inference (e.g., str, int, bool).
+ Note: This parameter is used purely for static type checking and does not
+ perform runtime type validation. Callers are responsible for ensuring the
+ specified type matches the actual config value type.
+ """
conf = await self.get_core_config(domain)
return (
conf.values[key].value
# return full config, just in case
return await self.get_core_config(domain)
+ if TYPE_CHECKING:
+ # Overload for when default is provided - return type matches default type
+ @overload
+ def get_raw_core_config_value(
+ self, core_module: str, key: str, default: _ConfigValueT
+ ) -> _ConfigValueT: ...
+
+ # Overload for when no default is provided - return ConfigValueType | None
+ @overload
+ def get_raw_core_config_value(
+ self, core_module: str, key: str, default: None = None
+ ) -> ConfigValueType | None: ...
+
def get_raw_core_config_value(
self, core_module: str, key: str, default: ConfigValueType = None
) -> ConfigValueType:
),
)
+ if TYPE_CHECKING:
+ # Overload for when default is provided - return type matches default type
+ @overload
+ def get_raw_provider_config_value(
+ self, provider_instance: str, key: str, default: _ConfigValueT
+ ) -> _ConfigValueT: ...
+
+ # Overload for when no default is provided - return ConfigValueType | None
+ @overload
+ def get_raw_provider_config_value(
+ self, provider_instance: str, key: str, default: None = None
+ ) -> ConfigValueType | None: ...
+
def get_raw_provider_config_value(
self, provider_instance: str, key: str, default: ConfigValueType = None
) -> ConfigValueType: