mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 15:31:52 -05:00
Use probatio directly in core, auth, helpers and util (#182107)
This commit is contained in:
@@ -4,8 +4,8 @@ import logging
|
||||
import types
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
import probatio
|
||||
from probatio.humanize import humanize_error
|
||||
|
||||
from homeassistant import data_entry_flow, requirements
|
||||
from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE
|
||||
@@ -18,14 +18,14 @@ from homeassistant.util.hass_dict import HassKey
|
||||
|
||||
MULTI_FACTOR_AUTH_MODULES: Registry[str, type[MultiFactorAuthModule]] = Registry()
|
||||
|
||||
MULTI_FACTOR_AUTH_MODULE_SCHEMA = vol.Schema(
|
||||
MULTI_FACTOR_AUTH_MODULE_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Required(CONF_TYPE): str,
|
||||
vol.Optional(CONF_NAME): str,
|
||||
probatio.Required(CONF_TYPE): str,
|
||||
probatio.Optional(CONF_NAME): str,
|
||||
# Specify ID if you have two mfa auth module for same type.
|
||||
vol.Optional(CONF_ID): str,
|
||||
probatio.Optional(CONF_ID): str,
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
DATA_REQS: HassKey[set[str]] = HassKey("mfa_auth_module_reqs_processed")
|
||||
@@ -65,8 +65,8 @@ class MultiFactorAuthModule:
|
||||
# Implement by extending class
|
||||
|
||||
@property
|
||||
def input_schema(self) -> vol.Schema:
|
||||
"""Return a voluptuous schema to define mfa auth module's input."""
|
||||
def input_schema(self) -> probatio.Schema:
|
||||
"""Return a schema to define mfa auth module's input."""
|
||||
raise NotImplementedError
|
||||
|
||||
async def async_setup_flow(self, user_id: str) -> SetupFlow[Any]:
|
||||
@@ -101,7 +101,7 @@ class SetupFlow[_MultiFactorAuthModuleT: MultiFactorAuthModule = MultiFactorAuth
|
||||
def __init__(
|
||||
self,
|
||||
auth_module: _MultiFactorAuthModuleT,
|
||||
setup_schema: vol.Schema,
|
||||
setup_schema: probatio.Schema,
|
||||
user_id: str,
|
||||
) -> None:
|
||||
"""Initialize the setup flow."""
|
||||
@@ -137,7 +137,7 @@ async def auth_mfa_module_from_config(
|
||||
|
||||
try:
|
||||
config = module.CONFIG_SCHEMA(config)
|
||||
except vol.Invalid as err:
|
||||
except probatio.Invalid as err:
|
||||
_LOGGER.error(
|
||||
"Invalid configuration for multi-factor module %s: %s",
|
||||
module_name,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from typing import Any, override
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
@@ -15,11 +15,13 @@ from . import (
|
||||
|
||||
CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required("data"): [
|
||||
vol.Schema({vol.Required("user_id"): str, vol.Required("pin"): str})
|
||||
probatio.Required("data"): [
|
||||
probatio.Schema(
|
||||
{probatio.Required("user_id"): str, probatio.Required("pin"): str}
|
||||
)
|
||||
]
|
||||
},
|
||||
extra=vol.PREVENT_EXTRA,
|
||||
extra=probatio.PREVENT_EXTRA,
|
||||
)
|
||||
|
||||
|
||||
@@ -36,14 +38,14 @@ class InsecureExampleModule(MultiFactorAuthModule):
|
||||
|
||||
@property
|
||||
@override
|
||||
def input_schema(self) -> vol.Schema:
|
||||
def input_schema(self) -> probatio.Schema:
|
||||
"""Validate login flow input data."""
|
||||
return vol.Schema({vol.Required("pin"): str})
|
||||
return probatio.Schema({probatio.Required("pin"): str})
|
||||
|
||||
@property
|
||||
def setup_schema(self) -> vol.Schema:
|
||||
def setup_schema(self) -> probatio.Schema:
|
||||
"""Validate async_setup_user input data."""
|
||||
return vol.Schema({vol.Required("pin"): str})
|
||||
return probatio.Schema({probatio.Required("pin"): str})
|
||||
|
||||
@override
|
||||
async def async_setup_flow(self, user_id: str) -> SetupFlow:
|
||||
|
||||
@@ -8,7 +8,7 @@ import logging
|
||||
from typing import Any, cast, override
|
||||
|
||||
import attr
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import CONF_EXCLUDE, CONF_INCLUDE
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -30,11 +30,13 @@ CONF_MESSAGE = "message"
|
||||
|
||||
CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_INCLUDE): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_EXCLUDE): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_MESSAGE, default="{} is your Home Assistant login code"): str,
|
||||
probatio.Optional(CONF_INCLUDE): probatio.All(cv.ensure_list, [cv.string]),
|
||||
probatio.Optional(CONF_EXCLUDE): probatio.All(cv.ensure_list, [cv.string]),
|
||||
probatio.Optional(
|
||||
CONF_MESSAGE, default="{} is your Home Assistant login code"
|
||||
): str,
|
||||
},
|
||||
extra=vol.PREVENT_EXTRA,
|
||||
extra=probatio.PREVENT_EXTRA,
|
||||
)
|
||||
|
||||
STORAGE_VERSION = 1
|
||||
@@ -108,9 +110,9 @@ class NotifyAuthModule(MultiFactorAuthModule):
|
||||
|
||||
@property
|
||||
@override
|
||||
def input_schema(self) -> vol.Schema:
|
||||
def input_schema(self) -> probatio.Schema:
|
||||
"""Validate login flow input data."""
|
||||
return vol.Schema({vol.Required(INPUT_FIELD_CODE): str})
|
||||
return probatio.Schema({probatio.Required(INPUT_FIELD_CODE): str})
|
||||
|
||||
async def _async_load(self) -> None:
|
||||
"""Load stored data."""
|
||||
@@ -277,7 +279,7 @@ class NotifySetupFlow(SetupFlow[NotifyAuthModule]):
|
||||
def __init__(
|
||||
self,
|
||||
auth_module: NotifyAuthModule,
|
||||
setup_schema: vol.Schema,
|
||||
setup_schema: probatio.Schema,
|
||||
user_id: str,
|
||||
available_notify_services: list[str],
|
||||
) -> None:
|
||||
@@ -308,10 +310,12 @@ class NotifySetupFlow(SetupFlow[NotifyAuthModule]):
|
||||
if not self._available_notify_services:
|
||||
return self.async_abort(reason="no_available_service")
|
||||
|
||||
schema = vol.Schema(
|
||||
schema = probatio.Schema(
|
||||
{
|
||||
vol.Required("notify_service"): vol.In(self._available_notify_services),
|
||||
vol.Optional("target"): str,
|
||||
probatio.Required("notify_service"): probatio.In(
|
||||
self._available_notify_services
|
||||
),
|
||||
probatio.Optional("target"): str,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import asyncio
|
||||
from io import BytesIO
|
||||
from typing import Any, cast, override
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.auth.models import User
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -20,7 +20,7 @@ from . import (
|
||||
|
||||
REQUIREMENTS = ["pyotp==2.9.0", "PyQRCode==1.2.1"]
|
||||
|
||||
CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({}, extra=vol.PREVENT_EXTRA)
|
||||
CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({}, extra=probatio.PREVENT_EXTRA)
|
||||
|
||||
STORAGE_VERSION = 1
|
||||
STORAGE_KEY = "auth_module.totp"
|
||||
@@ -88,9 +88,9 @@ class TotpAuthModule(MultiFactorAuthModule):
|
||||
|
||||
@property
|
||||
@override
|
||||
def input_schema(self) -> vol.Schema:
|
||||
def input_schema(self) -> probatio.Schema:
|
||||
"""Validate login flow input data."""
|
||||
return vol.Schema({vol.Required(INPUT_FIELD_CODE): str})
|
||||
return probatio.Schema({probatio.Required(INPUT_FIELD_CODE): str})
|
||||
|
||||
async def _async_load(self) -> None:
|
||||
"""Load stored data."""
|
||||
@@ -163,7 +163,7 @@ class TotpAuthModule(MultiFactorAuthModule):
|
||||
await self._async_load()
|
||||
|
||||
# user_input has been validate in caller
|
||||
# set INPUT_FIELD_CODE as vol.Required is not user friendly
|
||||
# set INPUT_FIELD_CODE as probatio.Required is not user friendly
|
||||
return await self.hass.async_add_executor_job(
|
||||
self._validate_2fa, user_id, user_input.get(INPUT_FIELD_CODE, "")
|
||||
)
|
||||
@@ -189,7 +189,7 @@ class TotpSetupFlow(SetupFlow[TotpAuthModule]):
|
||||
_image: str
|
||||
|
||||
def __init__(
|
||||
self, auth_module: TotpAuthModule, setup_schema: vol.Schema, user: User
|
||||
self, auth_module: TotpAuthModule, setup_schema: probatio.Schema, user: User
|
||||
) -> None:
|
||||
"""Initialize the setup flow."""
|
||||
super().__init__(auth_module, setup_schema, user.id)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from collections.abc import Callable, Iterable
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from .const import CAT_ENTITIES
|
||||
from .entities import ENTITY_POLICY_SCHEMA, compile_entities
|
||||
@@ -15,7 +15,7 @@ from .util import test_all
|
||||
if TYPE_CHECKING:
|
||||
from ..models import User
|
||||
|
||||
POLICY_SCHEMA = vol.Schema({vol.Optional(CAT_ENTITIES): ENTITY_POLICY_SCHEMA})
|
||||
POLICY_SCHEMA = probatio.Schema({probatio.Optional(CAT_ENTITIES): ENTITY_POLICY_SCHEMA})
|
||||
|
||||
__all__ = [
|
||||
"POLICY_SCHEMA",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from collections import OrderedDict
|
||||
from collections.abc import Callable
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
@@ -12,13 +12,13 @@ from .models import PermissionLookup
|
||||
from .types import CategoryType, SubCategoryDict, ValueType
|
||||
from .util import SubCatLookupType, compile_policy, lookup_all
|
||||
|
||||
SINGLE_ENTITY_SCHEMA = vol.Any(
|
||||
SINGLE_ENTITY_SCHEMA = probatio.Any(
|
||||
True,
|
||||
vol.Schema(
|
||||
probatio.Schema(
|
||||
{
|
||||
vol.Optional(POLICY_READ): True,
|
||||
vol.Optional(POLICY_CONTROL): True,
|
||||
vol.Optional(POLICY_EDIT): True,
|
||||
probatio.Optional(POLICY_READ): True,
|
||||
probatio.Optional(POLICY_CONTROL): True,
|
||||
probatio.Optional(POLICY_EDIT): True,
|
||||
}
|
||||
),
|
||||
)
|
||||
@@ -28,17 +28,17 @@ ENTITY_AREAS = "area_ids"
|
||||
ENTITY_DEVICE_IDS = "device_ids"
|
||||
ENTITY_ENTITY_IDS = "entity_ids"
|
||||
|
||||
ENTITY_VALUES_SCHEMA = vol.Any(True, vol.Schema({str: SINGLE_ENTITY_SCHEMA}))
|
||||
ENTITY_VALUES_SCHEMA = probatio.Any(True, probatio.Schema({str: SINGLE_ENTITY_SCHEMA}))
|
||||
|
||||
ENTITY_POLICY_SCHEMA = vol.Any(
|
||||
ENTITY_POLICY_SCHEMA = probatio.Any(
|
||||
True,
|
||||
vol.Schema(
|
||||
probatio.Schema(
|
||||
{
|
||||
vol.Optional(SUBCAT_ALL): SINGLE_ENTITY_SCHEMA,
|
||||
vol.Optional(ENTITY_AREAS): ENTITY_VALUES_SCHEMA,
|
||||
vol.Optional(ENTITY_DEVICE_IDS): ENTITY_VALUES_SCHEMA,
|
||||
vol.Optional(ENTITY_DOMAINS): ENTITY_VALUES_SCHEMA,
|
||||
vol.Optional(ENTITY_ENTITY_IDS): ENTITY_VALUES_SCHEMA,
|
||||
probatio.Optional(SUBCAT_ALL): SINGLE_ENTITY_SCHEMA,
|
||||
probatio.Optional(ENTITY_AREAS): ENTITY_VALUES_SCHEMA,
|
||||
probatio.Optional(ENTITY_DEVICE_IDS): ENTITY_VALUES_SCHEMA,
|
||||
probatio.Optional(ENTITY_DOMAINS): ENTITY_VALUES_SCHEMA,
|
||||
probatio.Optional(ENTITY_ENTITY_IDS): ENTITY_VALUES_SCHEMA,
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
@@ -5,8 +5,8 @@ import logging
|
||||
import types
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
import probatio
|
||||
from probatio.humanize import humanize_error
|
||||
|
||||
from homeassistant import requirements
|
||||
from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE
|
||||
@@ -34,14 +34,14 @@ DATA_REQS: HassKey[set[str]] = HassKey("auth_prov_reqs_processed")
|
||||
|
||||
AUTH_PROVIDERS: Registry[str, type[AuthProvider]] = Registry()
|
||||
|
||||
AUTH_PROVIDER_SCHEMA = vol.Schema(
|
||||
AUTH_PROVIDER_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Required(CONF_TYPE): str,
|
||||
vol.Optional(CONF_NAME): str,
|
||||
probatio.Required(CONF_TYPE): str,
|
||||
probatio.Optional(CONF_NAME): str,
|
||||
# Specify ID if you have two auth providers for same type.
|
||||
vol.Optional(CONF_ID): str,
|
||||
probatio.Optional(CONF_ID): str,
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ async def auth_provider_from_config(
|
||||
|
||||
try:
|
||||
config = module.CONFIG_SCHEMA(config)
|
||||
except vol.Invalid as err:
|
||||
except probatio.Invalid as err:
|
||||
_LOGGER.error(
|
||||
"Invalid configuration for auth provider %s: %s",
|
||||
provider_name,
|
||||
@@ -237,8 +237,8 @@ class LoginFlow[_AuthProviderT: AuthProvider = AuthProvider](
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="select_mfa_module",
|
||||
data_schema=vol.Schema(
|
||||
{"multi_factor_auth_module": vol.In(self.available_mfa_modules)}
|
||||
data_schema=probatio.Schema(
|
||||
{"multi_factor_auth_module": probatio.In(self.available_mfa_modules)}
|
||||
),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ import logging
|
||||
import os
|
||||
from typing import Any, override
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import CONF_COMMAND
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
@@ -19,13 +19,15 @@ CONF_META = "meta"
|
||||
|
||||
CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_COMMAND): vol.All(
|
||||
probatio.Required(CONF_COMMAND): probatio.All(
|
||||
str, os.path.normpath, msg="must be an absolute path"
|
||||
),
|
||||
vol.Optional(CONF_ARGS, default=None): vol.Any(vol.DefaultTo(list), [str]),
|
||||
vol.Optional(CONF_META, default=False): bool,
|
||||
probatio.Optional(CONF_ARGS, default=None): probatio.Any(
|
||||
probatio.DefaultTo(list), [str]
|
||||
),
|
||||
probatio.Optional(CONF_META, default=False): bool,
|
||||
},
|
||||
extra=vol.PREVENT_EXTRA,
|
||||
extra=probatio.PREVENT_EXTRA,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -161,10 +163,10 @@ class CommandLineLoginFlow(LoginFlow[CommandLineAuthProvider]):
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init",
|
||||
data_schema=vol.Schema(
|
||||
data_schema=probatio.Schema(
|
||||
{
|
||||
vol.Required("username"): str,
|
||||
vol.Required("password"): str,
|
||||
probatio.Required("username"): str,
|
||||
probatio.Required("password"): str,
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
|
||||
@@ -6,7 +6,7 @@ from collections.abc import Mapping
|
||||
from typing import Any, cast, override
|
||||
|
||||
import bcrypt
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import CONF_ID
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -23,12 +23,12 @@ STORAGE_KEY = "auth_provider.homeassistant"
|
||||
def _disallow_id(conf: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Disallow ID in config."""
|
||||
if CONF_ID in conf:
|
||||
raise vol.Invalid("ID is not allowed for the homeassistant auth provider.")
|
||||
raise probatio.Invalid("ID is not allowed for the homeassistant auth provider.")
|
||||
|
||||
return conf
|
||||
|
||||
|
||||
CONFIG_SCHEMA = vol.All(AUTH_PROVIDER_SCHEMA, _disallow_id)
|
||||
CONFIG_SCHEMA = probatio.All(AUTH_PROVIDER_SCHEMA, _disallow_id)
|
||||
|
||||
|
||||
@callback
|
||||
@@ -376,10 +376,10 @@ class HassLoginFlow(LoginFlow[HassAuthProvider]):
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init",
|
||||
data_schema=vol.Schema(
|
||||
data_schema=probatio.Schema(
|
||||
{
|
||||
vol.Required("username"): str,
|
||||
vol.Required("password"): str,
|
||||
probatio.Required("username"): str,
|
||||
probatio.Required("password"): str,
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
|
||||
@@ -4,7 +4,7 @@ from collections.abc import Mapping
|
||||
import hmac
|
||||
from typing import override
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
@@ -12,17 +12,17 @@ from homeassistant.exceptions import HomeAssistantError
|
||||
from ..models import AuthFlowContext, AuthFlowResult, Credentials, UserMeta
|
||||
from . import AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, AuthProvider, LoginFlow
|
||||
|
||||
USER_SCHEMA = vol.Schema(
|
||||
USER_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Required("username"): str,
|
||||
vol.Required("password"): str,
|
||||
vol.Optional("name"): str,
|
||||
probatio.Required("username"): str,
|
||||
probatio.Required("password"): str,
|
||||
probatio.Optional("name"): str,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend(
|
||||
{vol.Required("users"): [USER_SCHEMA]}, extra=vol.PREVENT_EXTRA
|
||||
{probatio.Required("users"): [USER_SCHEMA]}, extra=probatio.PREVENT_EXTRA
|
||||
)
|
||||
|
||||
|
||||
@@ -120,10 +120,10 @@ class ExampleLoginFlow(LoginFlow[ExampleAuthProvider]):
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init",
|
||||
data_schema=vol.Schema(
|
||||
data_schema=probatio.Schema(
|
||||
{
|
||||
vol.Required("username"): str,
|
||||
vol.Required("password"): str,
|
||||
probatio.Required("username"): str,
|
||||
probatio.Required("password"): str,
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
|
||||
@@ -15,7 +15,7 @@ from ipaddress import (
|
||||
)
|
||||
from typing import Any, cast, override
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
@@ -42,24 +42,26 @@ CONF_ALLOW_BYPASS_LOGIN = "allow_bypass_login"
|
||||
|
||||
CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_TRUSTED_NETWORKS): vol.All(cv.ensure_list, [ip_network]),
|
||||
vol.Optional(CONF_TRUSTED_USERS, default={}): vol.Schema(
|
||||
probatio.Required(CONF_TRUSTED_NETWORKS): probatio.All(
|
||||
cv.ensure_list, [ip_network]
|
||||
),
|
||||
probatio.Optional(CONF_TRUSTED_USERS, default={}): probatio.Schema(
|
||||
# we only validate the format of user_id or group_id
|
||||
{
|
||||
ip_network: vol.All(
|
||||
ip_network: probatio.All(
|
||||
cv.ensure_list,
|
||||
[
|
||||
vol.Or(
|
||||
probatio.Or(
|
||||
cv.uuid4_hex,
|
||||
vol.Schema({vol.Required(CONF_GROUP): str}),
|
||||
probatio.Schema({probatio.Required(CONF_GROUP): str}),
|
||||
)
|
||||
],
|
||||
)
|
||||
}
|
||||
),
|
||||
vol.Optional(CONF_ALLOW_BYPASS_LOGIN, default=False): cv.boolean,
|
||||
probatio.Optional(CONF_ALLOW_BYPASS_LOGIN, default=False): cv.boolean,
|
||||
},
|
||||
extra=vol.PREVENT_EXTRA,
|
||||
extra=probatio.PREVENT_EXTRA,
|
||||
)
|
||||
|
||||
|
||||
@@ -256,7 +258,7 @@ class TrustedNetworksLoginFlow(LoginFlow[TrustedNetworksAuthProvider]):
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init",
|
||||
data_schema=vol.Schema(
|
||||
{vol.Required("user"): vol.In(self._available_users)}
|
||||
data_schema=probatio.Schema(
|
||||
{probatio.Required("user"): probatio.In(self._available_users)}
|
||||
),
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ from typing import TYPE_CHECKING, Any, override
|
||||
# _frozen_importlib._DeadlockError: deadlock detected by
|
||||
# _ModuleLock('cryptography.hazmat.backends.openssl.backend')
|
||||
import cryptography.hazmat.backends.openssl.backend # noqa: F401
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
import yarl
|
||||
|
||||
from . import (
|
||||
@@ -555,7 +555,7 @@ async def async_from_config_dict(
|
||||
|
||||
try:
|
||||
await async_process_ha_core_config(hass, core_config)
|
||||
except vol.Invalid as config_err:
|
||||
except probatio.Invalid as config_err:
|
||||
conf_util.async_log_schema_error(config_err, core.DOMAIN, core_config, hass)
|
||||
async_notify_setup_error(hass, core.DOMAIN)
|
||||
return None
|
||||
@@ -692,7 +692,7 @@ def _log_file_disabled_reason() -> str | None:
|
||||
try:
|
||||
if cv.boolean(disable_log_file):
|
||||
return LOG_FILE_DISABLED_REASON_ENVIRONMENT
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
_LOGGER.warning(
|
||||
"Ignoring invalid %s value: %s. Expected a boolean value: "
|
||||
"1/0, true/false, yes/no, on/off, or enable/disable",
|
||||
|
||||
+28
-29
@@ -16,9 +16,8 @@ from types import ModuleType
|
||||
from typing import TYPE_CHECKING, Any, Literal, overload
|
||||
|
||||
from awesomeversion import AwesomeVersion
|
||||
from probatio import Undefined
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import MAX_VALIDATION_ERROR_ITEM_LENGTH
|
||||
import probatio
|
||||
from probatio.humanize import MAX_VALIDATION_ERROR_ITEM_LENGTH
|
||||
from yaml.error import MarkedYAMLError
|
||||
|
||||
from .const import CONF_PACKAGES, CONF_PLATFORM, __version__
|
||||
@@ -233,7 +232,7 @@ async def async_hass_config_yaml(hass: HomeAssistant) -> dict:
|
||||
for key in config:
|
||||
try:
|
||||
cv.domain_key(key)
|
||||
except vol.Invalid as exc:
|
||||
except probatio.Invalid as exc:
|
||||
suffix = ""
|
||||
if annotation := find_annotation(config, exc.path):
|
||||
suffix = f" at {_relpath(hass, annotation[0])}, line {annotation[1]}"
|
||||
@@ -245,7 +244,7 @@ async def async_hass_config_yaml(hass: HomeAssistant) -> dict:
|
||||
core_config = config.get(HOMEASSISTANT_DOMAIN, {})
|
||||
try:
|
||||
await merge_packages_config(hass, config, core_config.get(CONF_PACKAGES, {}))
|
||||
except vol.Invalid as exc:
|
||||
except probatio.Invalid as exc:
|
||||
suffix = ""
|
||||
if annotation := find_annotation(
|
||||
config, [HOMEASSISTANT_DOMAIN, CONF_PACKAGES, *exc.path]
|
||||
@@ -342,7 +341,7 @@ def process_ha_config_upgrade(hass: HomeAssistant) -> None:
|
||||
|
||||
@callback
|
||||
def async_log_schema_error(
|
||||
exc: vol.Invalid,
|
||||
exc: probatio.Invalid,
|
||||
domain: str,
|
||||
config: dict,
|
||||
hass: HomeAssistant,
|
||||
@@ -355,14 +354,14 @@ def async_log_schema_error(
|
||||
|
||||
@callback
|
||||
def async_log_config_validator_error(
|
||||
exc: vol.Invalid | HomeAssistantError,
|
||||
exc: probatio.Invalid | HomeAssistantError,
|
||||
domain: str,
|
||||
config: dict,
|
||||
hass: HomeAssistant,
|
||||
link: str | None = None,
|
||||
) -> None:
|
||||
"""Log an error from a custom config validator."""
|
||||
if isinstance(exc, vol.Invalid):
|
||||
if isinstance(exc, probatio.Invalid):
|
||||
async_log_schema_error(exc, domain, config, hass, link)
|
||||
return
|
||||
|
||||
@@ -448,16 +447,16 @@ def _relpath(hass: HomeAssistant, path: str) -> str:
|
||||
|
||||
def stringify_invalid(
|
||||
hass: HomeAssistant,
|
||||
exc: vol.Invalid,
|
||||
exc: probatio.Invalid,
|
||||
domain: str,
|
||||
config: dict,
|
||||
link: str | None,
|
||||
max_sub_error_length: int,
|
||||
) -> str:
|
||||
"""Stringify voluptuous.Invalid.
|
||||
"""Stringify probatio.Invalid.
|
||||
|
||||
This is an alternative to the custom __str__ implemented in
|
||||
voluptuous.error.Invalid. The modifications are:
|
||||
probatio.error.Invalid. The modifications are:
|
||||
- Format the path delimited by -> instead of @data[]
|
||||
- Prefix with domain, file and line of the error
|
||||
- Suffix with a link to the documentation
|
||||
@@ -490,7 +489,7 @@ def stringify_invalid(
|
||||
f"{message_suffix}"
|
||||
)
|
||||
# This function is an alternative to the stringification done by
|
||||
# vol.Invalid.__str__, so we need to call Exception.__str__ here
|
||||
# probatio.Invalid.__str__, so we need to call Exception.__str__ here
|
||||
# instead of str(exc)
|
||||
output = Exception.__str__(exc)
|
||||
if error_type := exc.error_type:
|
||||
@@ -508,7 +507,7 @@ def stringify_invalid(
|
||||
|
||||
def humanize_error(
|
||||
hass: HomeAssistant,
|
||||
validation_error: vol.Invalid,
|
||||
validation_error: probatio.Invalid,
|
||||
domain: str,
|
||||
config: dict,
|
||||
link: str | None,
|
||||
@@ -516,10 +515,10 @@ def humanize_error(
|
||||
) -> str:
|
||||
"""Provide a more helpful + complete validation error message.
|
||||
|
||||
This is a modified version of voluptuous.error.Invalid.__str__,
|
||||
This is a modified version of probatio.error.Invalid.__str__,
|
||||
the modifications make some minor changes to the formatting.
|
||||
"""
|
||||
if isinstance(validation_error, vol.MultipleInvalid):
|
||||
if isinstance(validation_error, probatio.MultipleInvalid):
|
||||
return "\n".join(
|
||||
sorted(
|
||||
humanize_error(
|
||||
@@ -564,7 +563,7 @@ def format_homeassistant_error(
|
||||
@callback
|
||||
def format_schema_error(
|
||||
hass: HomeAssistant,
|
||||
exc: vol.Invalid,
|
||||
exc: probatio.Invalid,
|
||||
domain: str,
|
||||
config: dict,
|
||||
link: str | None = None,
|
||||
@@ -588,12 +587,12 @@ def _log_pkg_error(
|
||||
|
||||
def _identify_config_schema(module: ComponentProtocol) -> str | None:
|
||||
"""Extract the schema and identify list or dict based."""
|
||||
if not isinstance(module.CONFIG_SCHEMA, vol.Schema):
|
||||
if not isinstance(module.CONFIG_SCHEMA, probatio.Schema):
|
||||
return None # type: ignore[unreachable]
|
||||
|
||||
schema = module.CONFIG_SCHEMA.schema
|
||||
|
||||
if isinstance(schema, vol.All):
|
||||
if isinstance(schema, probatio.All):
|
||||
for subschema in schema.validators:
|
||||
if isinstance(subschema, dict):
|
||||
schema = subschema
|
||||
@@ -609,7 +608,7 @@ def _identify_config_schema(module: ComponentProtocol) -> str | None:
|
||||
_LOGGER.exception("Unexpected error identifying config schema")
|
||||
return None
|
||||
|
||||
if hasattr(key, "default") and not isinstance(key.default, Undefined):
|
||||
if hasattr(key, "default") and not isinstance(key.default, probatio.Undefined):
|
||||
default_value = module.CONFIG_SCHEMA({module.DOMAIN: key.default()})[
|
||||
module.DOMAIN
|
||||
]
|
||||
@@ -671,7 +670,7 @@ async def merge_packages_config(
|
||||
"""Merge packages into the top-level configuration.
|
||||
|
||||
Ignores packages that cannot be setup. Mutates config. Raises
|
||||
vol.Invalid if whole package config is invalid.
|
||||
probatio.Invalid if whole package config is invalid.
|
||||
"""
|
||||
|
||||
_PACKAGES_CONFIG_SCHEMA(packages)
|
||||
@@ -680,7 +679,7 @@ async def merge_packages_config(
|
||||
for pack_name, pack_conf in packages.items():
|
||||
try:
|
||||
_validate_package_definition(pack_name, pack_conf)
|
||||
except vol.Invalid as exc:
|
||||
except probatio.Invalid as exc:
|
||||
_log_pkg_error(
|
||||
hass,
|
||||
pack_name,
|
||||
@@ -697,7 +696,7 @@ async def merge_packages_config(
|
||||
continue
|
||||
try:
|
||||
domain = cv.domain_key(comp_name)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
_log_pkg_error(
|
||||
hass, pack_name, comp_name, config, f"Invalid domain '{comp_name}'"
|
||||
)
|
||||
@@ -819,7 +818,7 @@ def _get_log_message_and_stack_print_pref(
|
||||
# If no pre defined log_message is set, we generate an enriched error
|
||||
# message, so we can notify about it during setup
|
||||
show_stack_trace = False
|
||||
if isinstance(exception, vol.Invalid):
|
||||
if isinstance(exception, probatio.Invalid):
|
||||
log_message = format_schema_error(
|
||||
hass, exception, platform_path, platform_config, link
|
||||
)
|
||||
@@ -1025,7 +1024,7 @@ def extract_platform_integrations(
|
||||
for key, domain_config in config.items():
|
||||
try:
|
||||
domain = cv.domain_key(key)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
continue
|
||||
if domain not in domains:
|
||||
continue
|
||||
@@ -1050,7 +1049,7 @@ def extract_domain_configs(config: ConfigType, domain: str) -> Sequence[str]:
|
||||
"""
|
||||
domain_configs = []
|
||||
for key in config:
|
||||
with suppress(vol.Invalid):
|
||||
with suppress(probatio.Invalid):
|
||||
if cv.domain_key(key) != domain:
|
||||
continue
|
||||
domain_configs.append(key)
|
||||
@@ -1096,7 +1095,7 @@ async def _async_load_and_validate_platform_integration(
|
||||
# Validate platform specific schema
|
||||
try:
|
||||
return platform.PLATFORM_SCHEMA(p_integration.config) # type: ignore[no-any-return]
|
||||
except vol.Invalid as exc:
|
||||
except probatio.Invalid as exc:
|
||||
exc_info = ConfigExceptionInfo(
|
||||
exc,
|
||||
ConfigErrorTranslationKey.PLATFORM_CONFIG_VALIDATION_ERR,
|
||||
@@ -1179,7 +1178,7 @@ async def async_process_component_config(
|
||||
return IntegrationConfigInfo(
|
||||
await config_validator.async_validate_config(hass, config), []
|
||||
)
|
||||
except (vol.Invalid, HomeAssistantError) as exc:
|
||||
except (probatio.Invalid, HomeAssistantError) as exc:
|
||||
exc_info = ConfigExceptionInfo(
|
||||
exc,
|
||||
ConfigErrorTranslationKey.CONFIG_VALIDATION_ERR,
|
||||
@@ -1206,7 +1205,7 @@ async def async_process_component_config(
|
||||
return IntegrationConfigInfo(
|
||||
await cv.async_validate(hass, component.CONFIG_SCHEMA, config), []
|
||||
)
|
||||
except vol.Invalid as exc:
|
||||
except probatio.Invalid as exc:
|
||||
exc_info = ConfigExceptionInfo(
|
||||
exc,
|
||||
ConfigErrorTranslationKey.CONFIG_VALIDATION_ERR,
|
||||
@@ -1243,7 +1242,7 @@ async def async_process_component_config(
|
||||
p_validated = await cv.async_validate(
|
||||
hass, component_platform_schema, p_config
|
||||
)
|
||||
except vol.Invalid as exc:
|
||||
except probatio.Invalid as exc:
|
||||
exc_info = ConfigExceptionInfo(
|
||||
exc,
|
||||
ConfigErrorTranslationKey.PLATFORM_CONFIG_VALIDATION_ERR,
|
||||
|
||||
@@ -24,8 +24,8 @@ from types import MappingProxyType
|
||||
from typing import TYPE_CHECKING, Any, Self, TypedDict, cast, override
|
||||
|
||||
from async_interrupt import interrupt
|
||||
import probatio
|
||||
from propcache.api import cached_property
|
||||
import voluptuous as vol
|
||||
|
||||
from . import data_entry_flow, loader
|
||||
from .const import (
|
||||
@@ -3618,7 +3618,7 @@ class ConfigFlow(ConfigEntryBaseFlow):
|
||||
self,
|
||||
*,
|
||||
step_id: str | None = None,
|
||||
data_schema: vol.Schema | None = None,
|
||||
data_schema: probatio.Schema | None = None,
|
||||
errors: dict[str, str] | None = None,
|
||||
description_placeholders: Mapping[str, str] | None = None,
|
||||
last_step: bool | None = None,
|
||||
|
||||
@@ -41,8 +41,8 @@ from typing import (
|
||||
override,
|
||||
)
|
||||
|
||||
import probatio
|
||||
from propcache.api import cached_property, under_cached_property
|
||||
import voluptuous as vol
|
||||
|
||||
from . import util
|
||||
from .const import (
|
||||
@@ -2692,7 +2692,7 @@ class ServiceRegistry:
|
||||
[ServiceCall],
|
||||
Coroutine[Any, Any, ServiceResponse] | ServiceResponse | None,
|
||||
],
|
||||
schema: vol.Schema | None = None,
|
||||
schema: probatio.Schema | None = None,
|
||||
supports_response: SupportsResponse = SupportsResponse.NONE,
|
||||
) -> None:
|
||||
"""Register a service.
|
||||
@@ -2924,7 +2924,7 @@ class ServiceRegistry:
|
||||
if handler.schema:
|
||||
try:
|
||||
processed_data: dict[str, Any] = handler.schema(service_data)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
_LOGGER.debug(
|
||||
"Invalid data for service call %s.%s: %s",
|
||||
domain,
|
||||
|
||||
@@ -10,7 +10,7 @@ import pathlib
|
||||
from typing import TYPE_CHECKING, Any, Final, override
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
from webrtc_models import RTCConfiguration, RTCIceServer
|
||||
import yarl
|
||||
|
||||
@@ -112,7 +112,7 @@ def _no_duplicate_auth_provider(
|
||||
for config in configs:
|
||||
key = (config[CONF_TYPE], config.get(CONF_ID))
|
||||
if key in config_keys:
|
||||
raise vol.Invalid(
|
||||
raise probatio.Invalid(
|
||||
f"Duplicate auth provider {config[CONF_TYPE]} found. "
|
||||
"Please add unique IDs "
|
||||
"if you want to have the same auth provider twice"
|
||||
@@ -135,7 +135,7 @@ def _no_duplicate_auth_mfa_module(
|
||||
for config in configs:
|
||||
key = config.get(CONF_ID, config[CONF_TYPE])
|
||||
if key in config_keys:
|
||||
raise vol.Invalid(
|
||||
raise probatio.Invalid(
|
||||
f"Duplicate mfa module {config[CONF_TYPE]} found. "
|
||||
"Please add unique IDs "
|
||||
"if you want to have the same mfa module twice"
|
||||
@@ -158,29 +158,31 @@ def _filter_bad_internal_external_urls(conf: dict) -> dict:
|
||||
|
||||
|
||||
# Schema for all packages element
|
||||
_PACKAGES_CONFIG_SCHEMA = vol.Schema({cv.string: vol.Any(dict, list)})
|
||||
_PACKAGES_CONFIG_SCHEMA = probatio.Schema({cv.string: probatio.Any(dict, list)})
|
||||
|
||||
# Schema for individual package definition
|
||||
_PACKAGE_DEFINITION_SCHEMA = vol.Schema({cv.string: vol.Any(dict, list, None)})
|
||||
|
||||
_CUSTOMIZE_DICT_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(ATTR_FRIENDLY_NAME): cv.string,
|
||||
vol.Optional(ATTR_HIDDEN): cv.boolean,
|
||||
vol.Optional(ATTR_ASSUMED_STATE): cv.boolean,
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
_PACKAGE_DEFINITION_SCHEMA = probatio.Schema(
|
||||
{cv.string: probatio.Any(dict, list, None)}
|
||||
)
|
||||
|
||||
_CUSTOMIZE_CONFIG_SCHEMA = vol.Schema(
|
||||
_CUSTOMIZE_DICT_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_CUSTOMIZE, default={}): vol.Schema(
|
||||
probatio.Optional(ATTR_FRIENDLY_NAME): cv.string,
|
||||
probatio.Optional(ATTR_HIDDEN): cv.boolean,
|
||||
probatio.Optional(ATTR_ASSUMED_STATE): cv.boolean,
|
||||
},
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
_CUSTOMIZE_CONFIG_SCHEMA = probatio.Schema(
|
||||
{
|
||||
probatio.Optional(CONF_CUSTOMIZE, default={}): probatio.Schema(
|
||||
{cv.entity_id: _CUSTOMIZE_DICT_SCHEMA}
|
||||
),
|
||||
vol.Optional(CONF_CUSTOMIZE_DOMAIN, default={}): vol.Schema(
|
||||
probatio.Optional(CONF_CUSTOMIZE_DOMAIN, default={}): probatio.Schema(
|
||||
{cv.string: _CUSTOMIZE_DICT_SCHEMA}
|
||||
),
|
||||
vol.Optional(CONF_CUSTOMIZE_GLOB, default={}): vol.Schema(
|
||||
probatio.Optional(CONF_CUSTOMIZE_GLOB, default={}): probatio.Schema(
|
||||
{cv.string: _CUSTOMIZE_DICT_SCHEMA}
|
||||
),
|
||||
}
|
||||
@@ -243,8 +245,8 @@ def _raise_issue_if_no_country(hass: HomeAssistant, country: str | None) -> None
|
||||
def _validate_currency(data: Any) -> Any:
|
||||
try:
|
||||
return cv.currency(data)
|
||||
except vol.InInvalid:
|
||||
with suppress(vol.InInvalid):
|
||||
except probatio.InInvalid:
|
||||
with suppress(probatio.InInvalid):
|
||||
return cv.historic_currency(data)
|
||||
raise
|
||||
|
||||
@@ -255,43 +257,43 @@ def validate_stun_or_turn_url(value: Any) -> str:
|
||||
url = urlparse(url_in)
|
||||
|
||||
if url.scheme not in ("stun", "stuns", "turn", "turns"):
|
||||
raise vol.Invalid("invalid url")
|
||||
raise probatio.Invalid("invalid url")
|
||||
return url_in
|
||||
|
||||
|
||||
CORE_CONFIG_SCHEMA = vol.All(
|
||||
CORE_CONFIG_SCHEMA = probatio.All(
|
||||
_CUSTOMIZE_CONFIG_SCHEMA.extend(
|
||||
{
|
||||
CONF_NAME: vol.Coerce(str),
|
||||
CONF_NAME: probatio.Coerce(str),
|
||||
CONF_LATITUDE: cv.latitude,
|
||||
CONF_LONGITUDE: cv.longitude,
|
||||
CONF_ELEVATION: vol.Coerce(int),
|
||||
CONF_ELEVATION: probatio.Coerce(int),
|
||||
CONF_RADIUS: cv.positive_int,
|
||||
vol.Remove(CONF_TEMPERATURE_UNIT): cv.temperature_unit,
|
||||
CONF_UNIT_SYSTEM: vol.Any(
|
||||
probatio.Remove(CONF_TEMPERATURE_UNIT): cv.temperature_unit,
|
||||
CONF_UNIT_SYSTEM: probatio.Any(
|
||||
_CONF_UNIT_SYSTEM_METRIC,
|
||||
_CONF_UNIT_SYSTEM_US_CUSTOMARY,
|
||||
_CONF_UNIT_SYSTEM_IMPERIAL,
|
||||
),
|
||||
CONF_TIME_ZONE: cv.time_zone,
|
||||
vol.Optional(CONF_INTERNAL_URL): cv.url,
|
||||
vol.Optional(CONF_EXTERNAL_URL): cv.url,
|
||||
vol.Optional(CONF_ALLOWLIST_EXTERNAL_DIRS): vol.All(
|
||||
cv.ensure_list, [vol.IsDir()]
|
||||
probatio.Optional(CONF_INTERNAL_URL): cv.url,
|
||||
probatio.Optional(CONF_EXTERNAL_URL): cv.url,
|
||||
probatio.Optional(CONF_ALLOWLIST_EXTERNAL_DIRS): probatio.All(
|
||||
cv.ensure_list, [probatio.IsDir()]
|
||||
),
|
||||
vol.Optional(LEGACY_CONF_WHITELIST_EXTERNAL_DIRS): vol.All(
|
||||
cv.ensure_list, [vol.IsDir()]
|
||||
probatio.Optional(LEGACY_CONF_WHITELIST_EXTERNAL_DIRS): probatio.All(
|
||||
cv.ensure_list, [probatio.IsDir()]
|
||||
),
|
||||
vol.Optional(CONF_ALLOWLIST_EXTERNAL_URLS): vol.All(
|
||||
probatio.Optional(CONF_ALLOWLIST_EXTERNAL_URLS): probatio.All(
|
||||
cv.ensure_list, [cv.url]
|
||||
),
|
||||
vol.Optional(CONF_PACKAGES, default={}): _PACKAGES_CONFIG_SCHEMA,
|
||||
vol.Optional(CONF_AUTH_PROVIDERS): vol.All(
|
||||
probatio.Optional(CONF_PACKAGES, default={}): _PACKAGES_CONFIG_SCHEMA,
|
||||
probatio.Optional(CONF_AUTH_PROVIDERS): probatio.All(
|
||||
cv.ensure_list,
|
||||
[
|
||||
auth_providers.AUTH_PROVIDER_SCHEMA.extend(
|
||||
{
|
||||
CONF_TYPE: vol.NotIn(
|
||||
CONF_TYPE: probatio.NotIn(
|
||||
["insecure_example"],
|
||||
(
|
||||
"The insecure_example auth provider"
|
||||
@@ -303,12 +305,12 @@ CORE_CONFIG_SCHEMA = vol.All(
|
||||
],
|
||||
_no_duplicate_auth_provider,
|
||||
),
|
||||
vol.Optional(CONF_AUTH_MFA_MODULES): vol.All(
|
||||
probatio.Optional(CONF_AUTH_MFA_MODULES): probatio.All(
|
||||
cv.ensure_list,
|
||||
[
|
||||
auth_mfa_modules.MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend(
|
||||
{
|
||||
CONF_TYPE: vol.NotIn(
|
||||
CONF_TYPE: probatio.NotIn(
|
||||
["insecure_example"],
|
||||
"The insecure_example mfa module is for testing only.",
|
||||
)
|
||||
@@ -317,24 +319,26 @@ CORE_CONFIG_SCHEMA = vol.All(
|
||||
],
|
||||
_no_duplicate_auth_mfa_module,
|
||||
),
|
||||
vol.Optional(CONF_MEDIA_DIRS): cv.schema_with_slug_keys(vol.IsDir()),
|
||||
vol.Remove(CONF_LEGACY_TEMPLATES): cv.boolean,
|
||||
vol.Optional(CONF_CURRENCY): _validate_currency,
|
||||
vol.Optional(CONF_COUNTRY): cv.country,
|
||||
vol.Optional(CONF_LANGUAGE): cv.language,
|
||||
vol.Optional(CONF_DEBUG): cv.boolean,
|
||||
vol.Optional(CONF_WEBRTC): vol.Schema(
|
||||
probatio.Optional(CONF_MEDIA_DIRS): cv.schema_with_slug_keys(
|
||||
probatio.IsDir()
|
||||
),
|
||||
probatio.Remove(CONF_LEGACY_TEMPLATES): cv.boolean,
|
||||
probatio.Optional(CONF_CURRENCY): _validate_currency,
|
||||
probatio.Optional(CONF_COUNTRY): cv.country,
|
||||
probatio.Optional(CONF_LANGUAGE): cv.language,
|
||||
probatio.Optional(CONF_DEBUG): cv.boolean,
|
||||
probatio.Optional(CONF_WEBRTC): probatio.Schema(
|
||||
{
|
||||
vol.Required(CONF_ICE_SERVERS): vol.All(
|
||||
probatio.Required(CONF_ICE_SERVERS): probatio.All(
|
||||
cv.ensure_list,
|
||||
[
|
||||
vol.Schema(
|
||||
probatio.Schema(
|
||||
{
|
||||
vol.Required(CONF_URL): vol.All(
|
||||
probatio.Required(CONF_URL): probatio.All(
|
||||
cv.ensure_list, [validate_stun_or_turn_url]
|
||||
),
|
||||
vol.Optional(CONF_USERNAME): cv.string,
|
||||
vol.Optional(CONF_CREDENTIAL): cv.string,
|
||||
probatio.Optional(CONF_USERNAME): cv.string,
|
||||
probatio.Optional(CONF_CREDENTIAL): cv.string,
|
||||
}
|
||||
)
|
||||
],
|
||||
@@ -352,7 +356,7 @@ async def async_process_ha_core_config(hass: HomeAssistant, config: dict) -> Non
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
# CORE_CONFIG_SCHEMA is not async safe since it uses vol.IsDir
|
||||
# CORE_CONFIG_SCHEMA is not async safe since it uses probatio.IsDir
|
||||
# so we need to run it in an executor job.
|
||||
config = await hass.async_add_executor_job(CORE_CONFIG_SCHEMA, config)
|
||||
|
||||
@@ -469,7 +473,7 @@ async def async_process_ha_core_config(hass: HomeAssistant, config: dict) -> Non
|
||||
|
||||
try:
|
||||
pkg_cust = _CUSTOMIZE_CONFIG_SCHEMA(pkg_cust)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
_LOGGER.warning("Package %s contains invalid customize", name)
|
||||
continue
|
||||
|
||||
@@ -884,7 +888,7 @@ class Config:
|
||||
"language" in owner_store.data
|
||||
and "language" in owner_store.data["language"]
|
||||
):
|
||||
with suppress(vol.InInvalid):
|
||||
with suppress(probatio.InInvalid):
|
||||
data["language"] = cv.language(
|
||||
owner_store.data["language"]["language"]
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@ import logging
|
||||
from types import MappingProxyType
|
||||
from typing import Any, Generic, Required, TypedDict, TypeVar, cast
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from .core import HomeAssistant, callback
|
||||
from .exceptions import HomeAssistantError
|
||||
@@ -87,7 +87,7 @@ class UnknownStep(FlowError):
|
||||
"""Unknown step specified."""
|
||||
|
||||
|
||||
class InvalidData(vol.Invalid):
|
||||
class InvalidData(probatio.Invalid):
|
||||
"""Invalid data provided."""
|
||||
|
||||
def __init__(
|
||||
@@ -130,7 +130,7 @@ class FlowResult(TypedDict, Generic[_FlowContextT, _HandlerT], total=False):
|
||||
"""Typed result dict."""
|
||||
|
||||
context: _FlowContextT
|
||||
data_schema: vol.Schema | None
|
||||
data_schema: probatio.Schema | None
|
||||
data: Mapping[str, Any]
|
||||
description_placeholders: Mapping[str, str] | None
|
||||
description: str | None
|
||||
@@ -155,8 +155,8 @@ class FlowResult(TypedDict, Generic[_FlowContextT, _HandlerT], total=False):
|
||||
|
||||
def _map_error_to_schema_errors(
|
||||
schema_errors: dict[str, Any],
|
||||
error: vol.Invalid,
|
||||
data_schema: vol.Schema,
|
||||
error: probatio.Invalid,
|
||||
data_schema: probatio.Schema,
|
||||
) -> None:
|
||||
"""Map an error to the correct position in the schema_errors.
|
||||
|
||||
@@ -171,7 +171,7 @@ def _map_error_to_schema_errors(
|
||||
if len(error_path) > 1:
|
||||
raise ValueError("Nested schemas are not supported")
|
||||
|
||||
# path_part can also be vol.Marker, but we need a string key
|
||||
# path_part can also be probatio.Marker, but we need a string key
|
||||
path_part_str = str(path_part)
|
||||
schema_errors[path_part_str] = error.error_message
|
||||
|
||||
@@ -355,12 +355,12 @@ class FlowManager(abc.ABC, Generic[_FlowContextT, _FlowResultT, _HandlerT]):
|
||||
if (
|
||||
data_schema := cur_step.get("data_schema")
|
||||
) is not None and user_input is not None:
|
||||
data_schema = cast(vol.Schema, data_schema)
|
||||
data_schema = cast(probatio.Schema, data_schema)
|
||||
try:
|
||||
user_input = data_schema(user_input)
|
||||
except vol.Invalid as ex:
|
||||
except probatio.Invalid as ex:
|
||||
raised_errors = [ex]
|
||||
if isinstance(ex, vol.MultipleInvalid):
|
||||
if isinstance(ex, probatio.MultipleInvalid):
|
||||
raised_errors = ex.errors
|
||||
|
||||
schema_errors: dict[str, Any] = {}
|
||||
@@ -666,8 +666,8 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
|
||||
return True
|
||||
|
||||
def add_suggested_values_to_schema(
|
||||
self, data_schema: vol.Schema, suggested_values: Mapping[str, Any] | None
|
||||
) -> vol.Schema:
|
||||
self, data_schema: probatio.Schema, suggested_values: Mapping[str, Any] | None
|
||||
) -> probatio.Schema:
|
||||
"""Make a copy of the schema, populated with suggested values.
|
||||
|
||||
For each schema marker matching items in `suggested_values`,
|
||||
@@ -694,20 +694,20 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
|
||||
if (
|
||||
suggested_values
|
||||
and key in suggested_values
|
||||
and isinstance(key, vol.Marker)
|
||||
and isinstance(key, probatio.Marker)
|
||||
):
|
||||
# Copy the marker to not modify the flow schema
|
||||
new_key = copy.copy(key)
|
||||
new_key.description = {"suggested_value": suggested_values[key.schema]}
|
||||
schema[new_key] = val
|
||||
return vol.Schema(schema)
|
||||
return probatio.Schema(schema)
|
||||
|
||||
@callback
|
||||
def async_show_form(
|
||||
self,
|
||||
*,
|
||||
step_id: str | None = None,
|
||||
data_schema: vol.Schema | None = None,
|
||||
data_schema: probatio.Schema | None = None,
|
||||
errors: dict[str, str] | None = None,
|
||||
description_placeholders: Mapping[str, str] | None = None,
|
||||
last_step: bool | None = None,
|
||||
@@ -891,7 +891,7 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
|
||||
type=FlowResultType.MENU,
|
||||
flow_id=self.flow_id,
|
||||
handler=self.handler,
|
||||
data_schema=vol.Schema({"next_step_id": vol.In(menu_options)}),
|
||||
data_schema=probatio.Schema({"next_step_id": probatio.In(menu_options)}),
|
||||
menu_options=menu_options,
|
||||
description_placeholders=description_placeholders,
|
||||
)
|
||||
@@ -939,14 +939,14 @@ class SectionConfig(TypedDict, total=False):
|
||||
class section:
|
||||
"""Data entry flow section."""
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
CONFIG_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional("collapsed", default=False): bool,
|
||||
probatio.Optional("collapsed", default=False): bool,
|
||||
},
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self, schema: vol.Schema, options: SectionConfig | None = None
|
||||
self, schema: probatio.Schema, options: SectionConfig | None = None
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
self.schema = schema
|
||||
|
||||
@@ -5,7 +5,7 @@ from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import Any, Final, Self
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import CONF_OPTIONS
|
||||
from homeassistant.core import HomeAssistant, split_entity_id
|
||||
@@ -78,7 +78,7 @@ def get_relative_description_key(domain: str, key: str) -> str:
|
||||
|
||||
|
||||
def move_top_level_schema_fields_to_options(
|
||||
config: ConfigType, options_schema_dict: dict[vol.Marker, Any]
|
||||
config: ConfigType, options_schema_dict: dict[probatio.Marker, Any]
|
||||
) -> ConfigType:
|
||||
"""Move top-level fields to options.
|
||||
|
||||
@@ -102,7 +102,7 @@ def move_top_level_schema_fields_to_options(
|
||||
|
||||
|
||||
def move_options_fields_to_top_level(
|
||||
config: ConfigType, base_schema: vol.Schema
|
||||
config: ConfigType, base_schema: probatio.Schema
|
||||
) -> ConfigType:
|
||||
"""Move options fields to top-level.
|
||||
|
||||
@@ -128,7 +128,7 @@ def move_options_fields_to_top_level(
|
||||
|
||||
try:
|
||||
new_config = base_schema(new_config)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
return config
|
||||
|
||||
new_config.update(options)
|
||||
|
||||
@@ -7,7 +7,7 @@ from pathlib import Path
|
||||
from typing import NamedTuple, Self
|
||||
|
||||
from annotatedyaml import loader as yaml_loader
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant import loader
|
||||
from homeassistant.config import ( # type: ignore[attr-defined]
|
||||
@@ -114,13 +114,13 @@ async def async_check_ha_config_file( # noqa: C901
|
||||
result.add_warning(message, domain, pack_config)
|
||||
|
||||
def _comp_error(
|
||||
ex: vol.Invalid | HomeAssistantError,
|
||||
ex: probatio.Invalid | HomeAssistantError,
|
||||
domain: str,
|
||||
component_config: ConfigType,
|
||||
config_to_attach: ConfigType,
|
||||
) -> None:
|
||||
"""Handle errors from components."""
|
||||
if isinstance(ex, vol.Invalid):
|
||||
if isinstance(ex, probatio.Invalid):
|
||||
message = format_schema_error(hass, ex, domain, component_config)
|
||||
else:
|
||||
message = format_homeassistant_error(hass, ex, domain, component_config)
|
||||
@@ -173,7 +173,7 @@ async def async_check_ha_config_file( # noqa: C901
|
||||
await merge_packages_config(
|
||||
hass, config, core_config.get(CONF_PACKAGES, {}), _pack_error
|
||||
)
|
||||
except vol.Invalid as err:
|
||||
except probatio.Invalid as err:
|
||||
result.add_error(
|
||||
format_schema_error(hass, err, HOMEASSISTANT_DOMAIN, core_config),
|
||||
HOMEASSISTANT_DOMAIN,
|
||||
@@ -224,7 +224,7 @@ async def async_check_ha_config_file( # noqa: C901
|
||||
await config_validator.async_validate_config(hass, config)
|
||||
)[domain]
|
||||
continue
|
||||
except (vol.Invalid, HomeAssistantError) as ex:
|
||||
except (probatio.Invalid, HomeAssistantError) as ex:
|
||||
_comp_error(ex, domain, config, config[domain])
|
||||
continue
|
||||
except Exception as err:
|
||||
@@ -245,7 +245,7 @@ async def async_check_ha_config_file( # noqa: C901
|
||||
# Don't fail if the validator removed the domain from the config
|
||||
if domain in validated_config:
|
||||
result[domain] = validated_config[domain]
|
||||
except vol.Invalid as ex:
|
||||
except probatio.Invalid as ex:
|
||||
_comp_error(ex, domain, config, config[domain])
|
||||
continue
|
||||
|
||||
@@ -265,7 +265,7 @@ async def async_check_ha_config_file( # noqa: C901
|
||||
p_validated = await cv.async_validate(
|
||||
hass, component_platform_schema, p_config
|
||||
)
|
||||
except vol.Invalid as ex:
|
||||
except probatio.Invalid as ex:
|
||||
_comp_error(ex, domain, p_config, p_config)
|
||||
continue
|
||||
|
||||
@@ -305,7 +305,7 @@ async def async_check_ha_config_file( # noqa: C901
|
||||
if platform_schema is not None:
|
||||
try:
|
||||
p_validated = platform_schema(p_validated)
|
||||
except vol.Invalid as ex:
|
||||
except probatio.Invalid as ex:
|
||||
_comp_error(ex, f"{domain}.{p_name}", p_config, p_config)
|
||||
continue
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import logging
|
||||
from operator import attrgetter
|
||||
from typing import Any, TypedDict, override
|
||||
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
import probatio
|
||||
from probatio.humanize import humanize_error
|
||||
|
||||
from homeassistant.components import websocket_api
|
||||
from homeassistant.const import CONF_ID
|
||||
@@ -590,7 +590,7 @@ class StorageCollectionWebsocket[_StorageCollectionT: StorageCollection]:
|
||||
f"{self.api_prefix}/list",
|
||||
list_handler,
|
||||
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
||||
{vol.Required("type"): f"{self.api_prefix}/list"}
|
||||
{probatio.Required("type"): f"{self.api_prefix}/list"}
|
||||
),
|
||||
)
|
||||
|
||||
@@ -603,7 +603,7 @@ class StorageCollectionWebsocket[_StorageCollectionT: StorageCollection]:
|
||||
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
||||
{
|
||||
**self.create_schema,
|
||||
vol.Required("type"): f"{self.api_prefix}/create",
|
||||
probatio.Required("type"): f"{self.api_prefix}/create",
|
||||
}
|
||||
),
|
||||
)
|
||||
@@ -613,7 +613,7 @@ class StorageCollectionWebsocket[_StorageCollectionT: StorageCollection]:
|
||||
f"{self.api_prefix}/subscribe",
|
||||
subscribe_handler,
|
||||
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
||||
{vol.Required("type"): f"{self.api_prefix}/subscribe"}
|
||||
{probatio.Required("type"): f"{self.api_prefix}/subscribe"}
|
||||
),
|
||||
)
|
||||
|
||||
@@ -626,8 +626,8 @@ class StorageCollectionWebsocket[_StorageCollectionT: StorageCollection]:
|
||||
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
||||
{
|
||||
**self.update_schema,
|
||||
vol.Required("type"): f"{self.api_prefix}/update",
|
||||
vol.Required(self.item_id_key): str,
|
||||
probatio.Required("type"): f"{self.api_prefix}/update",
|
||||
probatio.Required(self.item_id_key): str,
|
||||
}
|
||||
),
|
||||
)
|
||||
@@ -640,8 +640,8 @@ class StorageCollectionWebsocket[_StorageCollectionT: StorageCollection]:
|
||||
),
|
||||
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required("type"): f"{self.api_prefix}/delete",
|
||||
vol.Required(self.item_id_key): str,
|
||||
probatio.Required("type"): f"{self.api_prefix}/delete",
|
||||
probatio.Required(self.item_id_key): str,
|
||||
}
|
||||
),
|
||||
)
|
||||
@@ -663,7 +663,7 @@ class StorageCollectionWebsocket[_StorageCollectionT: StorageCollection]:
|
||||
data.pop("type")
|
||||
item = await self.storage_collection.async_create_item(data)
|
||||
connection.send_result(msg["id"], item)
|
||||
except vol.Invalid as err:
|
||||
except probatio.Invalid as err:
|
||||
connection.send_error(
|
||||
msg["id"],
|
||||
websocket_api.ERR_INVALID_FORMAT,
|
||||
@@ -740,7 +740,7 @@ class StorageCollectionWebsocket[_StorageCollectionT: StorageCollection]:
|
||||
websocket_api.ERR_NOT_FOUND,
|
||||
f"Unable to find {self.item_id_key} {item_id}",
|
||||
)
|
||||
except vol.Invalid as err:
|
||||
except probatio.Invalid as err:
|
||||
connection.send_error(
|
||||
msg["id"],
|
||||
websocket_api.ERR_INVALID_FORMAT,
|
||||
|
||||
@@ -26,7 +26,7 @@ from typing import (
|
||||
override,
|
||||
)
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_ABOVE,
|
||||
@@ -162,33 +162,33 @@ CONDITIONS: HassKey[dict[str, str]] = HassKey("conditions")
|
||||
|
||||
# Basic schemas to sanity check the condition descriptions,
|
||||
# full validation is done by hassfest.conditions
|
||||
_FIELD_DESCRIPTION_SCHEMA = vol.Schema(
|
||||
_FIELD_DESCRIPTION_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_SELECTOR): selector.validate_selector,
|
||||
probatio.Optional(CONF_SELECTOR): selector.validate_selector,
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
_CONDITION_DESCRIPTION_SCHEMA = vol.Schema(
|
||||
_CONDITION_DESCRIPTION_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional("target"): TargetSelector.CONFIG_SCHEMA,
|
||||
vol.Optional("fields"): vol.Schema({str: _FIELD_DESCRIPTION_SCHEMA}),
|
||||
probatio.Optional("target"): TargetSelector.CONFIG_SCHEMA,
|
||||
probatio.Optional("fields"): probatio.Schema({str: _FIELD_DESCRIPTION_SCHEMA}),
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
|
||||
def starts_with_dot(key: str) -> str:
|
||||
"""Check if key starts with dot."""
|
||||
if not key.startswith("."):
|
||||
raise vol.Invalid("Key does not start with .")
|
||||
raise probatio.Invalid("Key does not start with .")
|
||||
return key
|
||||
|
||||
|
||||
_CONDITIONS_DESCRIPTION_SCHEMA = vol.Schema(
|
||||
_CONDITIONS_DESCRIPTION_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Remove(vol.All(str, starts_with_dot)): object,
|
||||
cv.underscore_slug: vol.Any(None, _CONDITION_DESCRIPTION_SCHEMA),
|
||||
probatio.Remove(probatio.All(str, starts_with_dot)): object,
|
||||
cv.underscore_slug: probatio.Any(None, _CONDITION_DESCRIPTION_SCHEMA),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -265,16 +265,16 @@ async def _register_condition_platform(
|
||||
_LOGGER.exception("Error while notifying condition platform listener")
|
||||
|
||||
|
||||
_CONDITION_BASE_SCHEMA = vol.Schema(
|
||||
_CONDITION_BASE_SCHEMA = probatio.Schema(
|
||||
{
|
||||
**cv.CONDITION_BASE_SCHEMA,
|
||||
vol.Required(CONF_CONDITION): str,
|
||||
probatio.Required(CONF_CONDITION): str,
|
||||
}
|
||||
)
|
||||
_CONDITION_SCHEMA = _CONDITION_BASE_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_OPTIONS): object,
|
||||
vol.Optional(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
probatio.Optional(CONF_OPTIONS): object,
|
||||
probatio.Optional(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -436,14 +436,14 @@ ATTR_BEHAVIOR: Final = "behavior"
|
||||
BEHAVIOR_ANY: Final = "any"
|
||||
BEHAVIOR_ALL: Final = "all"
|
||||
|
||||
ENTITY_STATE_CONDITION_SCHEMA_ANY_ALL = vol.Schema(
|
||||
ENTITY_STATE_CONDITION_SCHEMA_ANY_ALL = probatio.Schema(
|
||||
{
|
||||
vol.Required(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
vol.Required(CONF_OPTIONS, default={}): {
|
||||
vol.Required(ATTR_BEHAVIOR, default=BEHAVIOR_ANY): vol.In(
|
||||
probatio.Required(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
probatio.Required(CONF_OPTIONS, default={}): {
|
||||
probatio.Required(ATTR_BEHAVIOR, default=BEHAVIOR_ANY): probatio.In(
|
||||
[BEHAVIOR_ANY, BEHAVIOR_ALL]
|
||||
),
|
||||
vol.Optional(CONF_FOR): cv.positive_time_period,
|
||||
probatio.Optional(CONF_FOR): cv.positive_time_period,
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -537,7 +537,7 @@ class EntityConditionBase(Condition):
|
||||
_excluded_states: Final[frozenset[str]] = frozenset(
|
||||
{STATE_UNAVAILABLE, STATE_UNKNOWN}
|
||||
)
|
||||
_schema: vol.Schema = ENTITY_STATE_CONDITION_SCHEMA_ANY_ALL
|
||||
_schema: probatio.Schema = ENTITY_STATE_CONDITION_SCHEMA_ANY_ALL
|
||||
# When True, indirect target expansion (via device/area/floor) skips
|
||||
# entities with an entity_category.
|
||||
_primary_entities_only: ClassVar[bool] = True
|
||||
@@ -942,8 +942,8 @@ def make_entity_state_condition(
|
||||
|
||||
NUMERICAL_CONDITION_SCHEMA = ENTITY_STATE_CONDITION_SCHEMA_ANY_ALL.extend(
|
||||
{
|
||||
vol.Required(CONF_OPTIONS): {
|
||||
vol.Required("threshold"): NumericThresholdSelector(
|
||||
probatio.Required(CONF_OPTIONS): {
|
||||
probatio.Required("threshold"): NumericThresholdSelector(
|
||||
NumericThresholdSelectorConfig(mode=NumericThresholdMode.IS)
|
||||
),
|
||||
},
|
||||
@@ -1065,12 +1065,12 @@ def make_entity_numerical_condition(
|
||||
|
||||
def _make_numerical_condition_with_unit_schema(
|
||||
unit_converter: type[BaseUnitConverter],
|
||||
) -> vol.Schema:
|
||||
) -> probatio.Schema:
|
||||
"""Factory for numerical condition schema with unit option."""
|
||||
return ENTITY_STATE_CONDITION_SCHEMA_ANY_ALL.extend(
|
||||
{
|
||||
vol.Required(CONF_OPTIONS): {
|
||||
vol.Required("threshold"): NumericThresholdSelector(
|
||||
probatio.Required(CONF_OPTIONS): {
|
||||
probatio.Required("threshold"): NumericThresholdSelector(
|
||||
NumericThresholdSelectorConfig(
|
||||
mode=NumericThresholdMode.IS,
|
||||
unit_of_measurement=list(unit_converter.VALID_UNITS),
|
||||
@@ -1746,7 +1746,7 @@ def state(
|
||||
for_period = cv.positive_time_period(render_complex(for_period, variables))
|
||||
except TemplateError as ex:
|
||||
raise ConditionErrorMessage("state", f"template error: {ex}") from ex
|
||||
except vol.Invalid as ex:
|
||||
except probatio.Invalid as ex:
|
||||
raise ConditionErrorMessage("state", f"schema error: {ex}") from ex
|
||||
|
||||
duration = dt_util.utcnow() - cast(timedelta, for_period)
|
||||
@@ -2014,7 +2014,7 @@ async def async_validate_condition_config(
|
||||
platform_domain, condition_key
|
||||
)
|
||||
if not (condition_class := condition_descriptors.get(relative_condition_key)):
|
||||
raise vol.Invalid(f"Invalid condition '{condition_key}' specified")
|
||||
raise probatio.Invalid(f"Invalid condition '{condition_key}' specified")
|
||||
return await condition_class.async_validate_complete_config(hass, config)
|
||||
|
||||
config = move_options_fields_to_top_level(config, _CONDITION_BASE_SCHEMA)
|
||||
@@ -2257,7 +2257,7 @@ def _load_conditions_file(integration: Integration) -> dict[str, Any]:
|
||||
"Unable to find conditions.yaml for the %s integration", integration.domain
|
||||
)
|
||||
return {}
|
||||
except (HomeAssistantError, vol.Invalid) as ex:
|
||||
except (HomeAssistantError, probatio.Invalid) as ex:
|
||||
_LOGGER.warning(
|
||||
"Unable to parse conditions.yaml for the %s integration: %s",
|
||||
integration.domain,
|
||||
|
||||
@@ -23,7 +23,7 @@ from aiohttp import ClientError, ClientResponseError, client, hdrs, web
|
||||
from habluetooth import BluetoothServiceInfoBleak
|
||||
import jwt
|
||||
from multidict import CIMultiDict
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
from yarl import URL
|
||||
|
||||
from homeassistant import config_entries
|
||||
@@ -548,11 +548,13 @@ class AbstractOAuth2FlowHandler(config_entries.ConfigFlow, metaclass=ABCMeta):
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="pick_implementation",
|
||||
data_schema=vol.Schema(
|
||||
data_schema=probatio.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
probatio.Required(
|
||||
"implementation", default=list(implementations)[0]
|
||||
): vol.In({key: impl.name for key, impl in implementations.items()})
|
||||
): probatio.In(
|
||||
{key: impl.name for key, impl in implementations.items()}
|
||||
)
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,8 +4,7 @@ from http import HTTPStatus
|
||||
from typing import Any, Generic, TypeVar
|
||||
|
||||
from aiohttp import web
|
||||
from probatio import to_field_list
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
@@ -51,7 +50,7 @@ class _BaseFlowManagerView(HomeAssistantView, Generic[_FlowManagerT, _FlowResult
|
||||
if (schema := result["data_schema"]) is None:
|
||||
data["data_schema"] = []
|
||||
else:
|
||||
data["data_schema"] = to_field_list(
|
||||
data["data_schema"] = probatio.to_field_list(
|
||||
schema, custom_serializer=cv.custom_serializer
|
||||
)
|
||||
return data
|
||||
@@ -61,11 +60,11 @@ class FlowManagerIndexView(_BaseFlowManagerView[_FlowManagerT, _FlowResultT]):
|
||||
"""View to create config flows."""
|
||||
|
||||
@RequestDataValidator(
|
||||
vol.Schema(
|
||||
probatio.Schema(
|
||||
{
|
||||
vol.Required("handler"): str,
|
||||
probatio.Required("handler"): str,
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
)
|
||||
async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
|
||||
@@ -113,7 +112,7 @@ class FlowManagerResourceView(_BaseFlowManagerView[_FlowManagerT, _FlowResultT])
|
||||
|
||||
return self.json(result)
|
||||
|
||||
@RequestDataValidator(vol.Schema(dict), allow_empty=True)
|
||||
@RequestDataValidator(probatio.Schema(dict), allow_empty=True)
|
||||
async def post(
|
||||
self, request: web.Request, data: dict[str, Any], flow_id: str
|
||||
) -> web.Response:
|
||||
|
||||
@@ -26,8 +26,8 @@ from typing import (
|
||||
override,
|
||||
)
|
||||
|
||||
import probatio
|
||||
from propcache.api import cached_property
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
DEVICE_DEFAULT_NAME,
|
||||
@@ -209,7 +209,7 @@ def get_unit_of_measurement(hass: HomeAssistant, entity_id: str) -> str | None:
|
||||
return entry.unit_of_measurement
|
||||
|
||||
|
||||
ENTITY_CATEGORIES_SCHEMA: Final = vol.Coerce(EntityCategory)
|
||||
ENTITY_CATEGORIES_SCHEMA: Final = probatio.Coerce(EntityCategory)
|
||||
|
||||
|
||||
class EntityInfo(TypedDict):
|
||||
|
||||
@@ -19,7 +19,7 @@ import time
|
||||
from typing import TYPE_CHECKING, Any, Literal, NotRequired, TypedDict, override
|
||||
|
||||
import attr
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import (
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
@@ -2768,13 +2768,13 @@ async def async_migrate_entries(
|
||||
def async_validate_entity_id(registry: EntityRegistry, entity_id_or_uuid: str) -> str:
|
||||
"""Validate and resolve an entity id or UUID to an entity id.
|
||||
|
||||
Raises vol.Invalid if the entity or UUID is invalid, or if the UUID is not
|
||||
Raises probatio.Invalid if the entity or UUID is invalid, or if the UUID is not
|
||||
associated with an entity registry item.
|
||||
"""
|
||||
if valid_entity_id(entity_id_or_uuid):
|
||||
return entity_id_or_uuid
|
||||
if (entry := registry.entities.get_entry(entity_id_or_uuid)) is None:
|
||||
raise vol.Invalid(f"Unknown entity registry entry {entity_id_or_uuid}")
|
||||
raise probatio.Invalid(f"Unknown entity registry entry {entity_id_or_uuid}")
|
||||
return entry.entity_id
|
||||
|
||||
|
||||
@@ -2801,7 +2801,7 @@ def async_validate_entity_ids(
|
||||
"""Validate and resolve a list of entity ids or UUIDs to a list of entity ids.
|
||||
|
||||
Returns a list with UUID resolved to entity_ids.
|
||||
Raises vol.Invalid if any item is invalid, or if any a UUID is not associated with
|
||||
Raises probatio.Invalid if any item is invalid, or if any a UUID is not associated with
|
||||
an entity registry item.
|
||||
"""
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from functools import lru_cache, partial
|
||||
import operator
|
||||
import re
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_DOMAINS,
|
||||
@@ -77,26 +77,26 @@ def convert_filter(config: dict[str, list[str]]) -> EntityFilter:
|
||||
return EntityFilter(config)
|
||||
|
||||
|
||||
BASE_FILTER_SCHEMA = vol.Schema(
|
||||
BASE_FILTER_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_EXCLUDE_DOMAINS, default=[]): vol.All(
|
||||
probatio.Optional(CONF_EXCLUDE_DOMAINS, default=[]): probatio.All(
|
||||
cv.ensure_list, [cv.string]
|
||||
),
|
||||
vol.Optional(CONF_EXCLUDE_ENTITY_GLOBS, default=[]): vol.All(
|
||||
probatio.Optional(CONF_EXCLUDE_ENTITY_GLOBS, default=[]): probatio.All(
|
||||
cv.ensure_list, [cv.string]
|
||||
),
|
||||
vol.Optional(CONF_EXCLUDE_ENTITIES, default=[]): cv.entity_ids,
|
||||
vol.Optional(CONF_INCLUDE_DOMAINS, default=[]): vol.All(
|
||||
probatio.Optional(CONF_EXCLUDE_ENTITIES, default=[]): cv.entity_ids,
|
||||
probatio.Optional(CONF_INCLUDE_DOMAINS, default=[]): probatio.All(
|
||||
cv.ensure_list, [cv.string]
|
||||
),
|
||||
vol.Optional(CONF_INCLUDE_ENTITY_GLOBS, default=[]): vol.All(
|
||||
probatio.Optional(CONF_INCLUDE_ENTITY_GLOBS, default=[]): probatio.All(
|
||||
cv.ensure_list, [cv.string]
|
||||
),
|
||||
vol.Optional(CONF_INCLUDE_ENTITIES, default=[]): cv.entity_ids,
|
||||
probatio.Optional(CONF_INCLUDE_ENTITIES, default=[]): cv.entity_ids,
|
||||
}
|
||||
)
|
||||
|
||||
FILTER_SCHEMA = vol.All(BASE_FILTER_SCHEMA, convert_filter)
|
||||
FILTER_SCHEMA = probatio.All(BASE_FILTER_SCHEMA, convert_filter)
|
||||
|
||||
|
||||
def convert_include_exclude_filter(
|
||||
@@ -117,28 +117,30 @@ def convert_include_exclude_filter(
|
||||
)
|
||||
|
||||
|
||||
INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER = vol.Schema(
|
||||
INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER = probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_DOMAINS, default=[]): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_ENTITY_GLOBS, default=[]): vol.All(
|
||||
probatio.Optional(CONF_DOMAINS, default=[]): probatio.All(
|
||||
cv.ensure_list, [cv.string]
|
||||
),
|
||||
vol.Optional(CONF_ENTITIES, default=[]): cv.entity_ids,
|
||||
probatio.Optional(CONF_ENTITY_GLOBS, default=[]): probatio.All(
|
||||
cv.ensure_list, [cv.string]
|
||||
),
|
||||
probatio.Optional(CONF_ENTITIES, default=[]): cv.entity_ids,
|
||||
}
|
||||
)
|
||||
|
||||
INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA = vol.Schema(
|
||||
INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
probatio.Optional(
|
||||
CONF_INCLUDE, default=INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER({})
|
||||
): INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER,
|
||||
vol.Optional(
|
||||
probatio.Optional(
|
||||
CONF_EXCLUDE, default=INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER({})
|
||||
): INCLUDE_EXCLUDE_FILTER_SCHEMA_INNER,
|
||||
}
|
||||
)
|
||||
|
||||
INCLUDE_EXCLUDE_FILTER_SCHEMA = vol.All(
|
||||
INCLUDE_EXCLUDE_FILTER_SCHEMA = probatio.All(
|
||||
INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA, convert_include_exclude_filter
|
||||
)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ from aiohttp.web_exceptions import (
|
||||
HTTPUnauthorized,
|
||||
)
|
||||
from aiohttp.web_urldispatcher import AbstractResource, AbstractRoute
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant import exceptions
|
||||
from homeassistant.const import CONTENT_TYPE_JSON
|
||||
@@ -92,7 +92,7 @@ def request_handler_factory(
|
||||
result = await handler(request, **request.match_info)
|
||||
else:
|
||||
result = handler(request, **request.match_info)
|
||||
except vol.Invalid as err:
|
||||
except probatio.Invalid as err:
|
||||
raise HTTPBadRequest from err
|
||||
except exceptions.ServiceNotFound as err:
|
||||
raise HTTPInternalServerError from err
|
||||
|
||||
@@ -10,8 +10,8 @@ from itertools import groupby
|
||||
import logging
|
||||
from typing import Any, override
|
||||
|
||||
import probatio
|
||||
from propcache.api import cached_property
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant.exposed_entities import async_should_expose
|
||||
from homeassistant.const import ATTR_ENTITY_ID, EntityStateAttribute
|
||||
@@ -56,7 +56,7 @@ INTENT_RESPOND = "HassRespond"
|
||||
INTENT_BROADCAST = "HassBroadcast"
|
||||
INTENT_GET_TEMPERATURE = "HassClimateGetTemperature"
|
||||
|
||||
SLOT_SCHEMA = vol.Schema({}, extra=vol.ALLOW_EXTRA)
|
||||
SLOT_SCHEMA = probatio.Schema({}, extra=probatio.ALLOW_EXTRA)
|
||||
|
||||
DATA_KEY: HassKey[dict[str, IntentHandler]] = HassKey("intent")
|
||||
|
||||
@@ -138,7 +138,7 @@ async def async_handle(
|
||||
try:
|
||||
_LOGGER.info("Triggering intent handler %s", handler)
|
||||
result = await handler.async_handle(intent)
|
||||
except vol.Invalid as err:
|
||||
except probatio.Invalid as err:
|
||||
_LOGGER.warning("Received invalid slot info for %s: %s", intent_type, err)
|
||||
raise InvalidSlotInfo(f"Received invalid slot info for {intent_type}") from err
|
||||
except IntentError:
|
||||
@@ -843,15 +843,15 @@ class IntentHandler:
|
||||
return self._slot_schema(slots) # type: ignore[no-any-return]
|
||||
|
||||
@cached_property
|
||||
def _slot_schema(self) -> vol.Schema:
|
||||
def _slot_schema(self) -> probatio.Schema:
|
||||
"""Create validation schema for slots."""
|
||||
assert self.slot_schema is not None
|
||||
return vol.Schema(
|
||||
return probatio.Schema(
|
||||
{
|
||||
key: SLOT_SCHEMA.extend({"value": validator})
|
||||
for key, validator in self.slot_schema.items()
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
async def async_handle(self, intent_obj: Intent) -> IntentResponse:
|
||||
@@ -868,7 +868,7 @@ def non_empty_string(value: Any) -> str:
|
||||
"""Coerce value to string and fail if string is empty or whitespace."""
|
||||
value_str = cv.string(value)
|
||||
if not value_str.strip():
|
||||
raise vol.Invalid("string value is empty")
|
||||
raise probatio.Invalid("string value is empty")
|
||||
|
||||
return value_str
|
||||
|
||||
@@ -883,7 +883,7 @@ class IntentSlotInfo:
|
||||
description: str | None = None
|
||||
"""Human readable description of the slot."""
|
||||
|
||||
value_schema: VolSchemaType | Callable[[Any], Any] = vol.Any
|
||||
value_schema: VolSchemaType | Callable[[Any], Any] = probatio.Any
|
||||
"""Validator for the slot."""
|
||||
|
||||
|
||||
@@ -947,16 +947,20 @@ class DynamicServiceIntentHandler(IntentHandler):
|
||||
def slot_schema(self) -> dict:
|
||||
"""Return a slot schema."""
|
||||
domain_validator = (
|
||||
vol.In(list(self.required_domains)) if self.required_domains else cv.string
|
||||
probatio.In(list(self.required_domains))
|
||||
if self.required_domains
|
||||
else cv.string
|
||||
)
|
||||
slot_schema = {
|
||||
vol.Any("name", "area", "floor"): non_empty_string,
|
||||
vol.Optional("domain"): vol.All(cv.ensure_list, [domain_validator]),
|
||||
probatio.Any("name", "area", "floor"): non_empty_string,
|
||||
probatio.Optional("domain"): probatio.All(
|
||||
cv.ensure_list, [domain_validator]
|
||||
),
|
||||
}
|
||||
if self.device_classes:
|
||||
# The typical way to match enums is with vol.Coerce, but we build a
|
||||
# The typical way to match enums is with probatio.Coerce, but we build a
|
||||
# flat list to make the API simpler to describe programmatically
|
||||
flattened_device_classes = vol.In(
|
||||
flattened_device_classes = probatio.In(
|
||||
[
|
||||
device_class.value
|
||||
for device_class_enum in self.device_classes
|
||||
@@ -965,7 +969,7 @@ class DynamicServiceIntentHandler(IntentHandler):
|
||||
)
|
||||
slot_schema.update(
|
||||
{
|
||||
vol.Optional("device_class"): vol.All(
|
||||
probatio.Optional("device_class"): probatio.All(
|
||||
cv.ensure_list,
|
||||
[flattened_device_classes],
|
||||
)
|
||||
@@ -974,15 +978,15 @@ class DynamicServiceIntentHandler(IntentHandler):
|
||||
|
||||
slot_schema.update(
|
||||
{
|
||||
vol.Optional("preferred_area_id"): cv.string,
|
||||
vol.Optional("preferred_floor_id"): cv.string,
|
||||
probatio.Optional("preferred_area_id"): cv.string,
|
||||
probatio.Optional("preferred_floor_id"): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
if self.required_slots:
|
||||
slot_schema.update(
|
||||
{
|
||||
vol.Required(
|
||||
probatio.Required(
|
||||
key, description=slot_info.description
|
||||
): slot_info.value_schema
|
||||
for key, slot_info in self.required_slots.items()
|
||||
@@ -992,7 +996,7 @@ class DynamicServiceIntentHandler(IntentHandler):
|
||||
if self.optional_slots:
|
||||
slot_schema.update(
|
||||
{
|
||||
vol.Optional(
|
||||
probatio.Optional(
|
||||
key, description=slot_info.description
|
||||
): slot_info.value_schema
|
||||
for key, slot_info in self.optional_slots.items()
|
||||
|
||||
@@ -5,9 +5,8 @@ from collections.abc import Callable
|
||||
from dataclasses import dataclass, field as dc_field
|
||||
from typing import Any, override
|
||||
|
||||
from probatio import UNSUPPORTED, to_openapi
|
||||
import probatio
|
||||
import slugify as unicode_slug
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
ATTR_DOMAIN,
|
||||
@@ -34,7 +33,7 @@ from .deprecation import deprecated_function
|
||||
from .singleton import singleton
|
||||
|
||||
ACTION_PARAMETERS_CACHE: HassKey[
|
||||
dict[str, dict[str, tuple[str | None, vol.Schema]]]
|
||||
dict[str, dict[str, tuple[str | None, probatio.Schema]]]
|
||||
] = HassKey("llm_action_parameters_cache")
|
||||
|
||||
APIS_CACHE: HassKey[dict[str, API]] = HassKey("llm_apis")
|
||||
@@ -160,7 +159,7 @@ class Tool:
|
||||
|
||||
name: str
|
||||
description: str | None = None
|
||||
parameters: vol.Schema = vol.Schema({})
|
||||
parameters: probatio.Schema = probatio.Schema({})
|
||||
|
||||
@abstractmethod
|
||||
async def async_call(
|
||||
@@ -247,7 +246,7 @@ class IntentTool(Tool):
|
||||
extra_slots.add(field)
|
||||
del slot_schema[field]
|
||||
|
||||
self.parameters = vol.Schema(slot_schema)
|
||||
self.parameters = probatio.Schema(slot_schema)
|
||||
if extra_slots:
|
||||
self.extra_slots = extra_slots
|
||||
|
||||
@@ -416,7 +415,7 @@ def selector_serializer(schema: Any) -> Any: # noqa: C901
|
||||
return {"type": "boolean"}
|
||||
|
||||
if not isinstance(schema, selector.Selector):
|
||||
return UNSUPPORTED
|
||||
return probatio.UNSUPPORTED
|
||||
|
||||
if isinstance(schema, selector.BackupLocationSelector):
|
||||
return {"type": "string", "pattern": "^(?:\\/backup|\\w+)$"}
|
||||
@@ -434,10 +433,10 @@ def selector_serializer(schema: Any) -> Any: # noqa: C901
|
||||
}
|
||||
|
||||
if isinstance(schema, selector.ConditionSelector):
|
||||
return to_openapi(cv.CONDITIONS_SCHEMA)
|
||||
return probatio.to_openapi(cv.CONDITIONS_SCHEMA)
|
||||
|
||||
if isinstance(schema, selector.ConstantSelector):
|
||||
return to_openapi(vol.Schema(schema.config["value"]))
|
||||
return probatio.to_openapi(probatio.Schema(schema.config["value"]))
|
||||
|
||||
result: dict[str, Any]
|
||||
if isinstance(schema, selector.ColorTempSelector):
|
||||
@@ -464,7 +463,7 @@ def selector_serializer(schema: Any) -> Any: # noqa: C901
|
||||
return {"type": "string", "format": "date-time"}
|
||||
|
||||
if isinstance(schema, selector.DurationSelector):
|
||||
return to_openapi(cv.time_period_dict)
|
||||
return probatio.to_openapi(cv.time_period_dict)
|
||||
|
||||
if isinstance(schema, selector.EntitySelector):
|
||||
if schema.config.get("multiple"):
|
||||
@@ -478,10 +477,10 @@ def selector_serializer(schema: Any) -> Any: # noqa: C901
|
||||
return {"type": "string", "format": "RFC 5646"}
|
||||
|
||||
if isinstance(schema, selector.LocationSelector):
|
||||
return to_openapi(schema.DATA_SCHEMA)
|
||||
return probatio.to_openapi(schema.DATA_SCHEMA)
|
||||
|
||||
if isinstance(schema, selector.MediaSelector):
|
||||
item_schema = to_openapi(schema.DATA_SCHEMA)
|
||||
item_schema = probatio.to_openapi(schema.DATA_SCHEMA)
|
||||
# Media selector allows multiple when configured
|
||||
if schema.config.get("multiple"):
|
||||
return {
|
||||
@@ -504,7 +503,7 @@ def selector_serializer(schema: Any) -> Any: # noqa: C901
|
||||
properties = {}
|
||||
required = []
|
||||
for field, field_schema in fields.items():
|
||||
properties[field] = to_openapi(
|
||||
properties[field] = probatio.to_openapi(
|
||||
selector.selector(field_schema["selector"]),
|
||||
custom_serializer=selector_serializer,
|
||||
)
|
||||
@@ -536,7 +535,7 @@ def selector_serializer(schema: Any) -> Any: # noqa: C901
|
||||
return {"type": "string", "enum": options}
|
||||
|
||||
if isinstance(schema, selector.TargetSelector):
|
||||
return to_openapi(cv.TARGET_FIELDS)
|
||||
return probatio.to_openapi(cv.TARGET_FIELDS)
|
||||
|
||||
if isinstance(schema, selector.TemplateSelector):
|
||||
return {"type": "string", "format": "jinja2"}
|
||||
@@ -555,10 +554,10 @@ def selector_serializer(schema: Any) -> Any: # noqa: C901
|
||||
|
||||
def _get_cached_action_parameters(
|
||||
hass: HomeAssistant, domain: str, action: str
|
||||
) -> tuple[str | None, vol.Schema]:
|
||||
) -> tuple[str | None, probatio.Schema]:
|
||||
"""Get action description and schema."""
|
||||
description = None
|
||||
parameters = vol.Schema({})
|
||||
parameters = probatio.Schema({})
|
||||
|
||||
parameters_cache = hass.data.get(ACTION_PARAMETERS_CACHE)
|
||||
|
||||
@@ -591,24 +590,24 @@ def _get_cached_action_parameters(
|
||||
hass, domain, action
|
||||
):
|
||||
description = action_desc.get("description")
|
||||
schema: dict[vol.Marker, Any] = {}
|
||||
schema: dict[probatio.Marker, Any] = {}
|
||||
fields = action_desc.get("fields", {})
|
||||
|
||||
for field, config in fields.items():
|
||||
field_description = config.get("description")
|
||||
if not field_description:
|
||||
field_description = config.get("name")
|
||||
key: vol.Marker
|
||||
key: probatio.Marker
|
||||
if config.get("required"):
|
||||
key = vol.Required(field, description=field_description)
|
||||
key = probatio.Required(field, description=field_description)
|
||||
else:
|
||||
key = vol.Optional(field, description=field_description)
|
||||
key = probatio.Optional(field, description=field_description)
|
||||
if "selector" in config:
|
||||
schema[key] = selector.selector(config["selector"])
|
||||
else:
|
||||
schema[key] = cv.string
|
||||
|
||||
parameters = vol.Schema(schema)
|
||||
parameters = probatio.Schema(schema)
|
||||
|
||||
parameters_cache.setdefault(domain, {})[action] = (description, parameters)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from dataclasses import dataclass
|
||||
import types
|
||||
from typing import Any, cast, override
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.config_entries import (
|
||||
ConfigEntry,
|
||||
@@ -37,11 +37,13 @@ class SchemaFlowFormStep(SchemaFlowStep):
|
||||
"""Define a config or options flow form step."""
|
||||
|
||||
schema: (
|
||||
vol.Schema
|
||||
| Callable[[SchemaCommonFlowHandler], Coroutine[Any, Any, vol.Schema | None]]
|
||||
probatio.Schema
|
||||
| Callable[
|
||||
[SchemaCommonFlowHandler], Coroutine[Any, Any, probatio.Schema | None]
|
||||
]
|
||||
| None
|
||||
) = None
|
||||
"""Optional voluptuous schema, or function which returns a schema or None, for
|
||||
"""Optional schema, or function which returns a schema or None, for
|
||||
requesting and validating user input.
|
||||
|
||||
- If a function is specified, the function will be passed the current
|
||||
@@ -168,10 +170,12 @@ class SchemaCommonFlowHandler:
|
||||
return form_step.options
|
||||
return await form_step.options(self)
|
||||
|
||||
async def _get_schema(self, form_step: SchemaFlowFormStep) -> vol.Schema | None:
|
||||
async def _get_schema(
|
||||
self, form_step: SchemaFlowFormStep
|
||||
) -> probatio.Schema | None:
|
||||
if form_step.schema is None:
|
||||
return None
|
||||
if isinstance(form_step.schema, vol.Schema):
|
||||
if isinstance(form_step.schema, probatio.Schema):
|
||||
return form_step.schema
|
||||
return await form_step.schema(self)
|
||||
|
||||
@@ -203,13 +207,13 @@ class SchemaCommonFlowHandler:
|
||||
self,
|
||||
values: dict[str, Any],
|
||||
user_input: dict[str, Any],
|
||||
data_schema: vol.Schema | None,
|
||||
data_schema: probatio.Schema | None,
|
||||
) -> None:
|
||||
values.update(user_input)
|
||||
if data_schema and data_schema.schema:
|
||||
for key in data_schema.schema:
|
||||
if (
|
||||
isinstance(key, vol.Optional)
|
||||
isinstance(key, probatio.Optional)
|
||||
and key not in user_input
|
||||
and not (
|
||||
# don't remove read_only keys
|
||||
|
||||
@@ -12,8 +12,8 @@ import logging
|
||||
from typing import Any, Literal, TypedDict, cast, overload, override
|
||||
|
||||
import async_interrupt
|
||||
import probatio
|
||||
from propcache.api import cached_property
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import exceptions
|
||||
from homeassistant.components import scene
|
||||
@@ -285,21 +285,23 @@ class trace_action:
|
||||
|
||||
|
||||
def make_script_schema(
|
||||
schema: Mapping[Any, Any], default_script_mode: str, extra: int = vol.PREVENT_EXTRA
|
||||
) -> vol.Schema:
|
||||
schema: Mapping[Any, Any],
|
||||
default_script_mode: str,
|
||||
extra: int = probatio.PREVENT_EXTRA,
|
||||
) -> probatio.Schema:
|
||||
"""Make a schema for a component that uses the script helper."""
|
||||
return vol.Schema(
|
||||
return probatio.Schema(
|
||||
{
|
||||
**schema,
|
||||
vol.Optional(CONF_MODE, default=default_script_mode): vol.In(
|
||||
probatio.Optional(CONF_MODE, default=default_script_mode): probatio.In(
|
||||
SCRIPT_MODE_CHOICES
|
||||
),
|
||||
vol.Optional(CONF_MAX, default=DEFAULT_MAX): vol.All(
|
||||
vol.Coerce(int), vol.Range(min=2)
|
||||
),
|
||||
vol.Optional(CONF_MAX_EXCEEDED, default=DEFAULT_MAX_EXCEEDED): vol.All(
|
||||
vol.Upper, vol.In(_MAX_EXCEEDED_CHOICES)
|
||||
probatio.Optional(CONF_MAX, default=DEFAULT_MAX): probatio.All(
|
||||
probatio.Coerce(int), probatio.Range(min=2)
|
||||
),
|
||||
probatio.Optional(
|
||||
CONF_MAX_EXCEEDED, default=DEFAULT_MAX_EXCEEDED
|
||||
): probatio.All(probatio.Upper, probatio.In(_MAX_EXCEEDED_CHOICES)),
|
||||
},
|
||||
extra=extra,
|
||||
)
|
||||
@@ -620,7 +622,7 @@ class _ScriptRun:
|
||||
if isinstance(
|
||||
exception,
|
||||
(
|
||||
vol.Invalid,
|
||||
probatio.Invalid,
|
||||
exceptions.TemplateError,
|
||||
exceptions.ServiceNotFound,
|
||||
exceptions.InvalidEntityFormatError,
|
||||
@@ -643,7 +645,7 @@ class _ScriptRun:
|
||||
error = str(exception)
|
||||
level = logging.ERROR
|
||||
|
||||
if isinstance(exception, vol.Invalid):
|
||||
if isinstance(exception, probatio.Invalid):
|
||||
error_desc = "Invalid data"
|
||||
|
||||
elif isinstance(exception, exceptions.TemplateError):
|
||||
@@ -1063,12 +1065,12 @@ class _ScriptRun:
|
||||
params[CONF_DOMAIN], params[CONF_SERVICE]
|
||||
)
|
||||
if supports_response == SupportsResponse.ONLY and not return_response:
|
||||
raise vol.Invalid(
|
||||
raise probatio.Invalid(
|
||||
f"Script requires '{CONF_RESPONSE_VARIABLE}' for response data "
|
||||
f"for service call {params[CONF_DOMAIN]}.{params[CONF_SERVICE]}"
|
||||
)
|
||||
if supports_response == SupportsResponse.NONE and return_response:
|
||||
raise vol.Invalid(
|
||||
raise probatio.Invalid(
|
||||
f"Script does not support '{CONF_RESPONSE_VARIABLE}' for service "
|
||||
f"'{params[CONF_DOMAIN]}.{params[CONF_SERVICE]}'"
|
||||
" which does not support response data."
|
||||
@@ -1186,7 +1188,7 @@ class _ScriptRun:
|
||||
return cv.positive_time_period( # type: ignore[no-any-return]
|
||||
template.render_complex(self._action[key], self._variables)
|
||||
)
|
||||
except (exceptions.TemplateError, vol.Invalid) as ex:
|
||||
except (exceptions.TemplateError, probatio.Invalid) as ex:
|
||||
self._log(
|
||||
"Error rendering %s %s template: %s",
|
||||
self._script.name,
|
||||
|
||||
+292
-269
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ import logging
|
||||
from types import ModuleType
|
||||
from typing import TYPE_CHECKING, Any, Literal, TypedDict, cast, overload
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.auth.permissions.const import CAT_ENTITIES, POLICY_CONTROL
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
||||
@@ -131,26 +131,26 @@ def _validate_option_or_feature(option_or_feature: str, label: str) -> Any:
|
||||
try:
|
||||
domain, enum, option = option_or_feature.split(".", 2)
|
||||
except ValueError as exc:
|
||||
raise vol.Invalid(
|
||||
raise probatio.Invalid(
|
||||
f"Invalid {label} '{option_or_feature}', expected <domain>.<enum>.<member>"
|
||||
) from exc
|
||||
|
||||
base_components = _base_components()
|
||||
if not (base_component := base_components.get(domain)):
|
||||
raise vol.Invalid(f"Unknown base component '{domain}'")
|
||||
raise probatio.Invalid(f"Unknown base component '{domain}'")
|
||||
|
||||
try:
|
||||
attribute_enum = getattr(base_component, enum)
|
||||
except AttributeError as exc:
|
||||
raise vol.Invalid(f"Unknown {label} enum '{domain}.{enum}'") from exc
|
||||
raise probatio.Invalid(f"Unknown {label} enum '{domain}.{enum}'") from exc
|
||||
|
||||
if not issubclass(attribute_enum, Enum):
|
||||
raise vol.Invalid(f"Expected {label} '{domain}.{enum}' to be an enum")
|
||||
raise probatio.Invalid(f"Expected {label} '{domain}.{enum}' to be an enum")
|
||||
|
||||
try:
|
||||
return getattr(attribute_enum, option).value
|
||||
except AttributeError as exc:
|
||||
raise vol.Invalid(f"Unknown {label} '{enum}.{option}'") from exc
|
||||
raise probatio.Invalid(f"Unknown {label} '{enum}.{option}'") from exc
|
||||
|
||||
|
||||
def validate_attribute_option(attribute_option: str) -> Any:
|
||||
@@ -165,50 +165,50 @@ def validate_supported_feature(supported_feature: str) -> Any:
|
||||
|
||||
# Basic schemas which translate attribute and supported feature enum names
|
||||
# to their values. Full validation is done by hassfest.services
|
||||
_FIELD_SCHEMA = vol.Schema(
|
||||
_FIELD_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_SELECTOR): selector.validate_selector,
|
||||
vol.Optional("filter"): {
|
||||
vol.Optional("attribute"): {
|
||||
vol.Required(str): [vol.All(str, validate_attribute_option)],
|
||||
probatio.Optional(CONF_SELECTOR): selector.validate_selector,
|
||||
probatio.Optional("filter"): {
|
||||
probatio.Optional("attribute"): {
|
||||
probatio.Required(str): [probatio.All(str, validate_attribute_option)],
|
||||
},
|
||||
vol.Optional("supported_features"): [
|
||||
vol.All(str, validate_supported_feature)
|
||||
probatio.Optional("supported_features"): [
|
||||
probatio.All(str, validate_supported_feature)
|
||||
],
|
||||
},
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
_SECTION_SCHEMA = vol.Schema(
|
||||
_SECTION_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Required("fields"): vol.Schema({str: _FIELD_SCHEMA}),
|
||||
probatio.Required("fields"): probatio.Schema({str: _FIELD_SCHEMA}),
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
_SERVICE_SCHEMA = vol.Schema(
|
||||
_SERVICE_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional("target"): TargetSelector.CONFIG_SCHEMA,
|
||||
vol.Optional("fields"): vol.Schema(
|
||||
{str: vol.Any(_SECTION_SCHEMA, _FIELD_SCHEMA)}
|
||||
probatio.Optional("target"): TargetSelector.CONFIG_SCHEMA,
|
||||
probatio.Optional("fields"): probatio.Schema(
|
||||
{str: probatio.Any(_SECTION_SCHEMA, _FIELD_SCHEMA)}
|
||||
),
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
|
||||
def starts_with_dot(key: str) -> str:
|
||||
"""Check if key starts with dot."""
|
||||
if not key.startswith("."):
|
||||
raise vol.Invalid("Key does not start with .")
|
||||
raise probatio.Invalid("Key does not start with .")
|
||||
return key
|
||||
|
||||
|
||||
_SERVICES_SCHEMA = vol.Schema(
|
||||
_SERVICES_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Remove(vol.All(str, starts_with_dot)): object,
|
||||
cv.slug: vol.Any(None, _SERVICE_SCHEMA),
|
||||
probatio.Remove(probatio.All(str, starts_with_dot)): object,
|
||||
cv.slug: probatio.Any(None, _SERVICE_SCHEMA),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -268,7 +268,7 @@ def async_prepare_call_from_config(
|
||||
if validate_config:
|
||||
try:
|
||||
config = cv.SERVICE_SCHEMA(config)
|
||||
except vol.Invalid as ex:
|
||||
except probatio.Invalid as ex:
|
||||
raise HomeAssistantError(
|
||||
f"Invalid config for calling service: {ex}"
|
||||
) from ex
|
||||
@@ -286,7 +286,7 @@ def async_prepare_call_from_config(
|
||||
raise HomeAssistantError(
|
||||
f"Error rendering service name template: {ex}"
|
||||
) from ex
|
||||
except vol.Invalid as ex:
|
||||
except probatio.Invalid as ex:
|
||||
raise HomeAssistantError(
|
||||
f"Template rendered invalid service: {domain_service}"
|
||||
) from ex
|
||||
@@ -314,7 +314,7 @@ def async_prepare_call_from_config(
|
||||
raise HomeAssistantError(
|
||||
f"Error rendering service target template: {ex}"
|
||||
) from ex
|
||||
except vol.Invalid as ex:
|
||||
except probatio.Invalid as ex:
|
||||
raise HomeAssistantError(
|
||||
f"Template rendered invalid entity IDs: {target[CONF_ENTITY_ID]}"
|
||||
) from ex
|
||||
@@ -457,7 +457,7 @@ def _load_services_file(integration: Integration) -> JSON_TYPE:
|
||||
"Unable to find services.yaml for the %s integration", integration.domain
|
||||
)
|
||||
return {}
|
||||
except (HomeAssistantError, vol.Invalid) as ex:
|
||||
except (HomeAssistantError, probatio.Invalid) as ex:
|
||||
_LOGGER.warning(
|
||||
"Unable to parse services.yaml for the %s integration: %s",
|
||||
integration.domain,
|
||||
@@ -615,7 +615,7 @@ def async_set_service_schema(
|
||||
# Match validation applied to descriptions loaded from services.yaml.
|
||||
try:
|
||||
description["target"] = TargetSelector.CONFIG_SCHEMA(schema["target"])
|
||||
except vol.Invalid as err:
|
||||
except probatio.Invalid as err:
|
||||
_LOGGER.warning(
|
||||
"Invalid target in the description of service %s.%s, ignoring it: %s",
|
||||
domain,
|
||||
@@ -1005,7 +1005,7 @@ def async_register_admin_service(
|
||||
| EntityServiceResponse
|
||||
| None,
|
||||
],
|
||||
schema: VolSchemaType = vol.Schema({}, extra=vol.PREVENT_EXTRA),
|
||||
schema: VolSchemaType = probatio.Schema({}, extra=probatio.PREVENT_EXTRA),
|
||||
supports_response: SupportsResponse = SupportsResponse.NONE,
|
||||
*,
|
||||
description_placeholders: Mapping[str, str] | None = None,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from collections.abc import Iterable
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
@@ -92,7 +92,7 @@ class AreaExtension(BaseTemplateExtension):
|
||||
|
||||
try:
|
||||
cv.entity_id(lookup_value)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
pass
|
||||
else:
|
||||
if entity := ent_reg.async_get(lookup_value):
|
||||
|
||||
@@ -4,7 +4,7 @@ from collections.abc import Iterable
|
||||
from itertools import chain
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.exceptions import TemplateError
|
||||
from homeassistant.helpers import (
|
||||
@@ -103,7 +103,7 @@ class DeviceExtension(BaseTemplateExtension):
|
||||
|
||||
try:
|
||||
cv.entity_id(lookup_value)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
pass
|
||||
else:
|
||||
if entity := ent_reg.async_get(lookup_value):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from collections.abc import Iterable
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
@@ -95,7 +95,7 @@ class LabelExtension(BaseTemplateExtension):
|
||||
|
||||
try:
|
||||
cv.entity_id(lookup_value)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
pass
|
||||
else:
|
||||
if entity := ent_reg.async_get(lookup_value):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NoReturn, overload
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
@@ -51,7 +51,7 @@ def resolve_area_id(hass: HomeAssistant, lookup_value: Any) -> str | None:
|
||||
# Check if it's an entity ID
|
||||
try:
|
||||
cv.entity_id(lookup_value)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
pass
|
||||
else:
|
||||
if entity := ent_reg.async_get(lookup_value):
|
||||
@@ -83,7 +83,7 @@ def forgiving_boolean[_T](
|
||||
"""Try to convert value to a boolean."""
|
||||
try:
|
||||
return cv.boolean(value)
|
||||
except vol.Invalid:
|
||||
except probatio.Invalid:
|
||||
if default is _SENTINEL:
|
||||
raise_no_default("bool", value)
|
||||
return default
|
||||
|
||||
@@ -22,7 +22,7 @@ from typing import (
|
||||
override,
|
||||
)
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
@@ -122,33 +122,33 @@ TRIGGERS: HassKey[dict[str, str]] = HassKey("triggers")
|
||||
|
||||
# Basic schemas to sanity check the trigger descriptions,
|
||||
# full validation is done by hassfest.triggers
|
||||
_FIELD_DESCRIPTION_SCHEMA = vol.Schema(
|
||||
_FIELD_DESCRIPTION_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_SELECTOR): selector.validate_selector,
|
||||
probatio.Optional(CONF_SELECTOR): selector.validate_selector,
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
_TRIGGER_DESCRIPTION_SCHEMA = vol.Schema(
|
||||
_TRIGGER_DESCRIPTION_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional("target"): TargetSelector.CONFIG_SCHEMA,
|
||||
vol.Optional("fields"): vol.Schema({str: _FIELD_DESCRIPTION_SCHEMA}),
|
||||
probatio.Optional("target"): TargetSelector.CONFIG_SCHEMA,
|
||||
probatio.Optional("fields"): probatio.Schema({str: _FIELD_DESCRIPTION_SCHEMA}),
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
|
||||
def starts_with_dot(key: str) -> str:
|
||||
"""Check if key starts with dot."""
|
||||
if not key.startswith("."):
|
||||
raise vol.Invalid("Key does not start with .")
|
||||
raise probatio.Invalid("Key does not start with .")
|
||||
return key
|
||||
|
||||
|
||||
_TRIGGERS_DESCRIPTION_SCHEMA = vol.Schema(
|
||||
_TRIGGERS_DESCRIPTION_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Remove(vol.All(str, starts_with_dot)): object,
|
||||
cv.underscore_slug: vol.Any(None, _TRIGGER_DESCRIPTION_SCHEMA),
|
||||
probatio.Remove(probatio.All(str, starts_with_dot)): object,
|
||||
cv.underscore_slug: probatio.Any(None, _TRIGGER_DESCRIPTION_SCHEMA),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -231,8 +231,8 @@ async def _register_trigger_platform(
|
||||
|
||||
_TRIGGER_SCHEMA = cv.TRIGGER_BASE_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_OPTIONS): object,
|
||||
vol.Optional(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
probatio.Optional(CONF_OPTIONS): object,
|
||||
probatio.Optional(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -355,21 +355,21 @@ def _backwards_compatible_behavior(value: Any) -> Any:
|
||||
return value
|
||||
|
||||
|
||||
ENTITY_STATE_TRIGGER_SCHEMA = vol.Schema(
|
||||
ENTITY_STATE_TRIGGER_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Required(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
vol.Required(CONF_OPTIONS, default={}): {},
|
||||
probatio.Required(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
probatio.Required(CONF_OPTIONS, default={}): {},
|
||||
}
|
||||
)
|
||||
|
||||
ENTITY_STATE_TRIGGER_SCHEMA_WITH_BEHAVIOR = ENTITY_STATE_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_OPTIONS, default={}): {
|
||||
vol.Required(ATTR_BEHAVIOR, default=BEHAVIOR_EACH): vol.All(
|
||||
probatio.Required(CONF_OPTIONS, default={}): {
|
||||
probatio.Required(ATTR_BEHAVIOR, default=BEHAVIOR_EACH): probatio.All(
|
||||
_backwards_compatible_behavior,
|
||||
vol.In([BEHAVIOR_FIRST, BEHAVIOR_ALL, BEHAVIOR_EACH]),
|
||||
probatio.In([BEHAVIOR_FIRST, BEHAVIOR_ALL, BEHAVIOR_EACH]),
|
||||
),
|
||||
vol.Optional(CONF_FOR): cv.positive_time_period,
|
||||
probatio.Optional(CONF_FOR): cv.positive_time_period,
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -391,7 +391,7 @@ class EntityTriggerBase(Trigger):
|
||||
# `_excluded_states`. Subclasses can override to relax the origin
|
||||
# check.
|
||||
_excluded_from_states: ClassVar[frozenset[str]] = _excluded_states
|
||||
_schema: vol.Schema = ENTITY_STATE_TRIGGER_SCHEMA_WITH_BEHAVIOR
|
||||
_schema: probatio.Schema = ENTITY_STATE_TRIGGER_SCHEMA_WITH_BEHAVIOR
|
||||
# When True, indirect target expansion (via device/area/floor) skips
|
||||
# entities with an entity_category.
|
||||
_primary_entities_only: ClassVar[bool] = True
|
||||
@@ -791,15 +791,15 @@ class StatelessEntityTriggerBase(EntityTriggerBase):
|
||||
after startup must still fire the trigger.
|
||||
"""
|
||||
|
||||
_schema: vol.Schema = ENTITY_STATE_TRIGGER_SCHEMA
|
||||
_schema: probatio.Schema = ENTITY_STATE_TRIGGER_SCHEMA
|
||||
_excluded_from_states: ClassVar[frozenset[str]] = frozenset({STATE_UNAVAILABLE})
|
||||
|
||||
|
||||
NUMERICAL_ATTRIBUTE_CHANGED_TRIGGER_SCHEMA = ENTITY_STATE_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_OPTIONS, default={}): vol.All(
|
||||
probatio.Required(CONF_OPTIONS, default={}): probatio.All(
|
||||
{
|
||||
vol.Required("threshold"): NumericThresholdSelector(
|
||||
probatio.Required("threshold"): NumericThresholdSelector(
|
||||
NumericThresholdSelectorConfig(mode=NumericThresholdMode.CHANGED)
|
||||
)
|
||||
},
|
||||
@@ -1097,13 +1097,13 @@ class EntityNumericalStateChangedTriggerBase(EntityNumericalStateTriggerBase):
|
||||
|
||||
def make_numerical_state_changed_with_unit_schema(
|
||||
unit_converter: type[BaseUnitConverter],
|
||||
) -> vol.Schema:
|
||||
) -> probatio.Schema:
|
||||
"""Factory for numerical state trigger schema with unit option."""
|
||||
return ENTITY_STATE_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_OPTIONS, default={}): vol.All(
|
||||
probatio.Required(CONF_OPTIONS, default={}): probatio.All(
|
||||
{
|
||||
vol.Required("threshold"): NumericThresholdSelector(
|
||||
probatio.Required("threshold"): NumericThresholdSelector(
|
||||
NumericThresholdSelectorConfig(
|
||||
mode=NumericThresholdMode.CHANGED,
|
||||
unit_of_measurement=list(unit_converter.VALID_UNITS),
|
||||
@@ -1131,8 +1131,8 @@ class EntityNumericalStateChangedTriggerWithUnitBase(
|
||||
NUMERICAL_ATTRIBUTE_CROSSED_THRESHOLD_SCHEMA = (
|
||||
ENTITY_STATE_TRIGGER_SCHEMA_WITH_BEHAVIOR.extend(
|
||||
{
|
||||
vol.Required(CONF_OPTIONS): {
|
||||
vol.Required("threshold"): NumericThresholdSelector(
|
||||
probatio.Required(CONF_OPTIONS): {
|
||||
probatio.Required("threshold"): NumericThresholdSelector(
|
||||
NumericThresholdSelectorConfig(mode=NumericThresholdMode.CROSSED)
|
||||
),
|
||||
},
|
||||
@@ -1158,7 +1158,7 @@ class EntityNumericalStateCrossedThresholdTriggerBase(EntityNumericalStateTrigge
|
||||
|
||||
def _make_numerical_state_crossed_threshold_with_unit_schema(
|
||||
unit_converter: type[BaseUnitConverter],
|
||||
) -> vol.Schema:
|
||||
) -> probatio.Schema:
|
||||
"""Trigger for numerical state and state attribute changes.
|
||||
|
||||
This trigger only fires when the observed attribute
|
||||
@@ -1166,8 +1166,8 @@ def _make_numerical_state_crossed_threshold_with_unit_schema(
|
||||
"""
|
||||
return ENTITY_STATE_TRIGGER_SCHEMA_WITH_BEHAVIOR.extend(
|
||||
{
|
||||
vol.Required(CONF_OPTIONS, default={}): {
|
||||
vol.Required("threshold"): NumericThresholdSelector(
|
||||
probatio.Required(CONF_OPTIONS, default={}): {
|
||||
probatio.Required("threshold"): NumericThresholdSelector(
|
||||
NumericThresholdSelectorConfig(
|
||||
mode=NumericThresholdMode.CROSSED,
|
||||
unit_of_measurement=list(unit_converter.VALID_UNITS),
|
||||
@@ -1353,7 +1353,7 @@ class TriggerProtocol(Protocol):
|
||||
async def async_get_triggers(self, hass: HomeAssistant) -> dict[str, type[Trigger]]:
|
||||
"""Return the triggers provided by this integration."""
|
||||
|
||||
TRIGGER_SCHEMA: vol.Schema
|
||||
TRIGGER_SCHEMA: probatio.Schema
|
||||
|
||||
async def async_validate_trigger_config(
|
||||
self, hass: HomeAssistant, config: ConfigType
|
||||
@@ -1634,11 +1634,11 @@ async def _async_get_trigger_platform(
|
||||
try:
|
||||
integration = await async_get_integration(hass, platform)
|
||||
except IntegrationNotFound:
|
||||
raise vol.Invalid(f"Invalid trigger '{trigger_key}' specified") from None
|
||||
raise probatio.Invalid(f"Invalid trigger '{trigger_key}' specified") from None
|
||||
try:
|
||||
platform_module = await integration.async_get_platform("trigger")
|
||||
except ImportError:
|
||||
raise vol.Invalid(
|
||||
raise probatio.Invalid(
|
||||
f"Integration '{platform}' does not provide trigger support"
|
||||
) from None
|
||||
|
||||
@@ -1662,7 +1662,7 @@ async def async_validate_trigger_config(
|
||||
platform_domain, trigger_key
|
||||
)
|
||||
if not (trigger := trigger_descriptors.get(relative_trigger_key)):
|
||||
raise vol.Invalid(f"Invalid trigger '{trigger_key}' specified")
|
||||
raise probatio.Invalid(f"Invalid trigger '{trigger_key}' specified")
|
||||
conf = await trigger.async_validate_complete_config(hass, conf)
|
||||
elif hasattr(platform, "async_validate_trigger_config"):
|
||||
conf = move_options_fields_to_top_level(conf, cv.TRIGGER_BASE_SCHEMA)
|
||||
@@ -1928,7 +1928,7 @@ def _load_triggers_file(integration: Integration) -> dict[str, Any]:
|
||||
"Unable to find triggers.yaml for the %s integration", integration.domain
|
||||
)
|
||||
return {}
|
||||
except (HomeAssistantError, vol.Invalid) as ex:
|
||||
except (HomeAssistantError, probatio.Invalid) as ex:
|
||||
_LOGGER.warning(
|
||||
"Unable to parse triggers.yaml for the %s integration: %s",
|
||||
integration.domain,
|
||||
|
||||
@@ -5,7 +5,7 @@ import logging
|
||||
from typing import Any, override
|
||||
|
||||
import jinja2
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
CONF_STATE_CLASS,
|
||||
@@ -51,24 +51,24 @@ CONF_TO_ATTRIBUTE = {
|
||||
CONF_PICTURE: EntityStateAttribute.ENTITY_PICTURE,
|
||||
}
|
||||
|
||||
TEMPLATE_ENTITY_BASE_SCHEMA = vol.Schema(
|
||||
TEMPLATE_ENTITY_BASE_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_ICON): cv.template,
|
||||
vol.Optional(CONF_NAME): cv.template,
|
||||
vol.Optional(CONF_PICTURE): cv.template,
|
||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
probatio.Optional(CONF_ICON): cv.template,
|
||||
probatio.Optional(CONF_NAME): cv.template,
|
||||
probatio.Optional(CONF_PICTURE): cv.template,
|
||||
probatio.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def make_template_entity_base_schema(default_name: str) -> vol.Schema:
|
||||
def make_template_entity_base_schema(default_name: str) -> probatio.Schema:
|
||||
"""Return a schema with default name."""
|
||||
return vol.Schema(
|
||||
return probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_ICON): cv.template,
|
||||
vol.Optional(CONF_NAME, default=default_name): cv.template,
|
||||
vol.Optional(CONF_PICTURE): cv.template,
|
||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
probatio.Optional(CONF_ICON): cv.template,
|
||||
probatio.Optional(CONF_NAME, default=default_name): cv.template,
|
||||
probatio.Optional(CONF_PICTURE): cv.template,
|
||||
probatio.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -94,11 +94,11 @@ def log_triggered_template_error(
|
||||
)
|
||||
|
||||
|
||||
TEMPLATE_SENSOR_BASE_SCHEMA = vol.Schema(
|
||||
TEMPLATE_SENSOR_BASE_SCHEMA = probatio.Schema(
|
||||
{
|
||||
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
||||
vol.Optional(CONF_STATE_CLASS): STATE_CLASSES_SCHEMA,
|
||||
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
||||
probatio.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
||||
probatio.Optional(CONF_STATE_CLASS): STATE_CLASSES_SCHEMA,
|
||||
probatio.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
||||
}
|
||||
).extend(TEMPLATE_ENTITY_BASE_SCHEMA.schema)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from collections.abc import Mapping
|
||||
from enum import Enum
|
||||
from typing import Any, Never
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
type GPSType = tuple[float, float]
|
||||
type ConfigType = dict[str, Any]
|
||||
@@ -13,8 +13,8 @@ type ServiceDataType = dict[str, Any]
|
||||
type StateType = str | int | float | None
|
||||
type TemplateVarsType = Mapping[str, Any] | None
|
||||
type NoEventData = Mapping[str, Never]
|
||||
type VolSchemaType = vol.Schema | vol.All | vol.Any
|
||||
type VolDictType = dict[str | vol.Marker, Any]
|
||||
type VolSchemaType = probatio.Schema | probatio.All | probatio.Any
|
||||
type VolDictType = dict[str | probatio.Marker, Any]
|
||||
|
||||
# Custom type for recorder Queries
|
||||
type QueryType = Any
|
||||
|
||||
@@ -31,8 +31,8 @@ from awesomeversion import (
|
||||
AwesomeVersionException,
|
||||
AwesomeVersionStrategy,
|
||||
)
|
||||
import probatio
|
||||
from propcache.api import cached_property
|
||||
import voluptuous as vol
|
||||
|
||||
from . import generated
|
||||
from .const import Platform
|
||||
@@ -379,7 +379,7 @@ async def async_get_config_flows(
|
||||
class ComponentProtocol(Protocol):
|
||||
"""Define the format of an integration."""
|
||||
|
||||
CONFIG_SCHEMA: vol.Schema
|
||||
CONFIG_SCHEMA: probatio.Schema
|
||||
DOMAIN: str
|
||||
|
||||
async def async_setup_entry(
|
||||
|
||||
@@ -4,7 +4,7 @@ from dataclasses import dataclass
|
||||
from numbers import Number
|
||||
from typing import TYPE_CHECKING, Final
|
||||
|
||||
import voluptuous as vol
|
||||
import probatio
|
||||
|
||||
from homeassistant.const import (
|
||||
ACCUMULATED_PRECIPITATION,
|
||||
@@ -249,10 +249,10 @@ def _deprecated_unit_system(value: str) -> str:
|
||||
return value
|
||||
|
||||
|
||||
validate_unit_system = vol.All(
|
||||
vol.Lower,
|
||||
validate_unit_system = probatio.All(
|
||||
probatio.Lower,
|
||||
_deprecated_unit_system,
|
||||
vol.Any(_CONF_UNIT_SYSTEM_METRIC, _CONF_UNIT_SYSTEM_US_CUSTOMARY),
|
||||
probatio.Any(_CONF_UNIT_SYSTEM_METRIC, _CONF_UNIT_SYSTEM_US_CUSTOMARY),
|
||||
)
|
||||
|
||||
METRIC_SYSTEM = UnitSystem(
|
||||
|
||||
Reference in New Issue
Block a user