From 2aac9c964c1808ce263fab44bafafc6b7e858ff2 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 26 Jul 2025 10:29:04 +0000 Subject: [PATCH 001/235] Prototype migration --- custom_components/battery_notes/__init__.py | 36 +++++++++++++++++++ .../battery_notes/config_flow.py | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 86ab8796d..c10549f6e 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -11,6 +11,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion +from homeassistant.config_entries import ConfigEntry from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv @@ -90,6 +91,7 @@ extra=vol.ALLOW_EXTRA, ) +_migrate_base_entry: ConfigEntry = None async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Integration setup.""" @@ -247,6 +249,40 @@ async def async_migrate_entry( new_version, ) + if config_entry.version < 3: + # Get the current config entries, see if one is at V3 and hold onto it as the base + if not _migrate_base_entry: + _LOGGER.debug("No base entry, looking for existing V3 entries") + + existing_entries = hass.config_entries.async_entries(DOMAIN) + for entry in existing_entries: + if entry.version == 3 and entry.unique_id == DOMAIN: + # We have a V3 entry, so we can use this as the base + _LOGGER.debug( + "Found existing V3 config entry %s, using it as the base for migration", + entry.entry_id, + ) + _migrate_base_entry = entry + break + # If no V3 then create one and hold onto it as the base + if not _migrate_base_entry: + _LOGGER.debug( + "No existing V3 config entry found, creating a new one for migration" + ) + _migrate_base_entry = ConfigEntry(domain=DOMAIN, title=config_entry.title,data=config_entry.data,version=3, unique_id=DOMAIN) + hass.config_entries.async_add(_migrate_base_entry) + + assert _migrate_base_entry is not None, "Base entry should not be None" + + # Change this config entry into a sub entry, add it to the base entry + _LOGGER.debug( + "Migrating config entry %s from version %s to version %s", + config_entry.entry_id, + config_entry.version, + new_version, + ) + + return True diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 4b81758d6..b882211d0 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -45,7 +45,7 @@ _LOGGER = logging.getLogger(__name__) -CONFIG_VERSION = 2 +CONFIG_VERSION = 3 DEVICE_SCHEMA_ALL = vol.Schema( { From a34466c6454e378e1df65b8fc8f744ef82ebb7af Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 26 Jul 2025 10:33:56 +0000 Subject: [PATCH 002/235] WIP --- custom_components/battery_notes/__init__.py | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index c10549f6e..6aa553390 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -41,6 +41,9 @@ MIN_HA_VERSION, PLATFORMS, ) +from .const import ( + NAME as INTEGRATION_NAME, +) from .coordinator import ( MY_KEY, BatteryNotesConfigEntry, @@ -269,7 +272,27 @@ async def async_migrate_entry( _LOGGER.debug( "No existing V3 config entry found, creating a new one for migration" ) - _migrate_base_entry = ConfigEntry(domain=DOMAIN, title=config_entry.title,data=config_entry.data,version=3, unique_id=DOMAIN) + + # TODO: Grab these from the configuration.yaml + options = { + CONF_ENABLE_AUTODISCOVERY: True, + CONF_SHOW_ALL_DEVICES: False, + CONF_ENABLE_REPLACED: True, + CONF_HIDE_BATTERY: False, + CONF_ROUND_BATTERY: False, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, + CONF_LIBRARY_URL: DEFAULT_LIBRARY_URL, + CONF_SCHEMA_URL: DEFAULT_SCHEMA_URL, + } + + _migrate_base_entry = ConfigEntry( + domain=DOMAIN, + title=INTEGRATION_NAME, + version=3, + unique_id=DOMAIN, + optons=options, + ) hass.config_entries.async_add(_migrate_base_entry) assert _migrate_base_entry is not None, "Base entry should not be None" From 5d52f54003d0408afb66e7684f5a105374947a1d Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 26 Jul 2025 15:19:31 +0000 Subject: [PATCH 003/235] WIP --- custom_components/battery_notes/__init__.py | 24 ++-- .../battery_notes/config_flow.py | 29 +++++ custom_components/battery_notes/const.py | 2 +- .../battery_notes/translations/en.json | 111 +++++++++++------- hacs.json | 2 +- poetry.lock | 2 +- pyproject.toml | 2 +- requirements.txt | 2 +- 8 files changed, 113 insertions(+), 61 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 6aa553390..bfa090f1f 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -273,17 +273,18 @@ async def async_migrate_entry( "No existing V3 config entry found, creating a new one for migration" ) - # TODO: Grab these from the configuration.yaml + domain_config = hass.data[MY_KEY] + options = { - CONF_ENABLE_AUTODISCOVERY: True, - CONF_SHOW_ALL_DEVICES: False, - CONF_ENABLE_REPLACED: True, - CONF_HIDE_BATTERY: False, - CONF_ROUND_BATTERY: False, - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, - CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, - CONF_LIBRARY_URL: DEFAULT_LIBRARY_URL, - CONF_SCHEMA_URL: DEFAULT_SCHEMA_URL, + CONF_ENABLE_AUTODISCOVERY: domain_config.enable_autodiscovery, + CONF_SHOW_ALL_DEVICES: domain_config.show_all_devices, + CONF_ENABLE_REPLACED: domain_config.enable_replaced, + CONF_HIDE_BATTERY: domain_config.hide_battery, + CONF_ROUND_BATTERY: domain_config.round_battery, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: domain_config.default_battery_low_threshold, + CONF_BATTERY_INCREASE_THRESHOLD: domain_config.battery_increased_threshod, + CONF_LIBRARY_URL: domain_config.library_url, + CONF_SCHEMA_URL: domain_config.schema_url, } _migrate_base_entry = ConfigEntry( @@ -297,7 +298,8 @@ async def async_migrate_entry( assert _migrate_base_entry is not None, "Base entry should not be None" - # Change this config entry into a sub entry, add it to the base entry + # TODO: Change this config entry into a sub entry, add it to the base entry + _LOGGER.debug( "Migrating config entry %s from version %s to version %s", config_entry.entry_id, diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index b882211d0..40e5c71cb 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -14,7 +14,9 @@ from homeassistant.config_entries import ( ConfigEntry, ConfigFlowResult, + ConfigSubentryFlow, OptionsFlow, + SubentryFlowResult, ) from homeassistant.const import ( CONF_DEVICE_ID, @@ -117,6 +119,16 @@ def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow: """Get the options flow for this handler.""" return OptionsFlowHandler() + @classmethod + @callback + def async_get_supported_subentry_types( + cls, config_entry: ConfigEntry + ) -> dict[str, type[ConfigSubentryFlow]]: + """Return subentries supported by this integration.""" + return { + "battery_note": BatteryNotesSubentryFlowHandler, + } + async def async_step_integration_discovery( self, discovery_info: DiscoveryInfoType, @@ -433,6 +445,23 @@ async def async_step_battery( errors=errors, ) +class BatteryNotesSubentryFlowHandler(ConfigSubentryFlow): + """Flow for managing Battery Notes subentries.""" + + options: dict[str, Any] + + @property + def _is_new(self) -> bool: + """Return if this is a new subentry.""" + return self.source == "user" + + async def async_step_user( + self, user_input: dict[str, Any] | None = None + ) -> SubentryFlowResult: + """Add a subentry.""" + + return await self.async_step_init() + class OptionsFlowHandler(OptionsFlow): """Handle an option flow for BatteryNotes.""" diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 6a84082ed..bb0058299 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -11,7 +11,7 @@ LOGGER: Logger = getLogger(__package__) -MIN_HA_VERSION = "2025.4.0" +MIN_HA_VERSION = "2025.7.0" manifestfile = Path(__file__).parent / "manifest.json" with open(file=manifestfile, encoding="UTF-8") as json_file: diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 3ab0abd97..d5a47d07a 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -3,59 +3,80 @@ "step": { "user": { "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Association type" + "title": "Setup Battery Notes" + } + }, + "abort": { + "already_configured": "Integration is already configured" + }, + "error": { + "unknown": "Unknown error occurred." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + + "step": { + "user": { + "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Association type" + }, + "menu_options": { + "device": "Device (recommended)", + "entity": "Entity" + }, + "title": "Choose your association type" }, - "menu_options": { - "device": "Device (recommended)", - "entity": "Entity" + "device": { + "data": { + "device_id": "Device", + "name": "Name" + }, + "data_description": { + "name": "Leaving blank will take the name from the source device" + } }, - "title": "Choose your association type" - }, - "device": { - "data": { - "device_id": "Device", - "name": "Name" + "entity": { + "data": { + "source_entity_id": "Entity", + "name": "Name" + }, + "data_description": { + "name": "Leaving blank will take the name from the source entity" + } }, - "data_description": { - "name": "Leaving blank will take the name from the source device" - } - }, - "entity": { - "data": { - "source_entity_id": "Entity", - "name": "Name" + "battery": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "Battery type", + "battery_quantity": "Battery quantity", + "battery_low_threshold": "Battery low threshold", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 will use the global default threshold", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } }, - "data_description": { - "name": "Leaving blank will take the name from the source entity" + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Device manual configuration" } }, - "battery": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", - "data": { - "battery_type": "Battery type", - "battery_quantity": "Battery quantity", - "battery_low_threshold": "Battery low threshold", - "battery_low_template": "Battery low template", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "battery_low_threshold": "0 will use the global default threshold", - "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } + "abort": { + "already_configured": "Device is already configured" }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" + "error": { + "unknown": "Unknown error occurred.", + "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." } - }, - "abort": { - "already_configured": "Device is already configured" - }, - "error": { - "unknown": "Unknown error occurred.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." } }, "options": { diff --git a/hacs.json b/hacs.json index c7dc0d44c..8cb5cee3f 100644 --- a/hacs.json +++ b/hacs.json @@ -2,6 +2,6 @@ "name": "Battery Notes", "filename": "battery_notes.zip", "hide_default_branch": true, - "homeassistant": "2025.4.0", + "homeassistant": "2025.7.0", "zip_release": true } diff --git a/poetry.lock b/poetry.lock index 6688380e5..9f6bd6677 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1574,7 +1574,7 @@ files = [ [[package]] name = "homeassistant" -version = "2025.4.0" +version = "2025.7.0" description = "Open-source home automation platform running on Python 3." optional = false python-versions = ">=3.13.0" diff --git a/pyproject.toml b/pyproject.toml index 52f0d92e2..1deeacb20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ repository = "https://github.com/andrew-codechimp/HA-Battery-Notes" version = "0.0.0" [tool.poetry.dependencies] -homeassistant = "2025.4.0" +homeassistant = "2025.7.0" python = ">=3.13,<3.14" [tool.poetry.group.dev.dependencies] diff --git a/requirements.txt b/requirements.txt index 71dd9dc1a..00f50cfe3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ colorlog>=6.8.2,<7.0 -homeassistant==2025.4.0 +homeassistant==2025.7.0 ruff>=0.5.0,<0.8.2 From 0a616279ec8cedabae2e767e9e823c1a61c2114e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 26 Jul 2025 15:26:37 +0000 Subject: [PATCH 004/235] WIP --- poetry.lock | 1941 +++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 912 insertions(+), 1031 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9f6bd6677..de4222bad 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,20 +1,20 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "acme" -version = "3.2.0" +version = "4.1.1" description = "ACME protocol implementation in Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.9.2" groups = ["main"] files = [ - {file = "acme-3.2.0-py3-none-any.whl", hash = "sha256:201b118d12426f746d936efc61706d30dc2f9e2635aebab0c86ec7f80eca5f30"}, - {file = "acme-3.2.0.tar.gz", hash = "sha256:e11d0ccf43ec19244ada40df1dc4ca49c9ce407749f3771d2cefe0674e206d84"}, + {file = "acme-4.1.1-py3-none-any.whl", hash = "sha256:9c904453bf1374789b6cd78c6314dea6e7609b4f6c58e35339ee91701f39cd20"}, + {file = "acme-4.1.1.tar.gz", hash = "sha256:0ffaaf6d3f41ff05772fd2b6170cf0b2b139f5134d7a70ee49f6e63ca20e8f9a"}, ] [package.dependencies] cryptography = ">=43.0.0" -josepy = ">=1.13.0,<2" +josepy = ">=2.0.0" PyOpenSSL = ">=25.0.0" pyrfc3339 = "*" pytz = ">=2019.3" @@ -26,18 +26,18 @@ test = ["pytest", "pytest-xdist", "typing-extensions"] [[package]] name = "aiodns" -version = "3.2.0" +version = "3.5.0" description = "Simple DNS resolver for asyncio" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiodns-3.2.0-py3-none-any.whl", hash = "sha256:e443c0c27b07da3174a109fd9e736d69058d808f144d3c9d56dbd1776964c5f5"}, - {file = "aiodns-3.2.0.tar.gz", hash = "sha256:62869b23409349c21b072883ec8998316b234c9a9e36675756e8e317e8768f72"}, + {file = "aiodns-3.5.0-py3-none-any.whl", hash = "sha256:6d0404f7d5215849233f6ee44854f2bb2481adf71b336b2279016ea5990ca5c5"}, + {file = "aiodns-3.5.0.tar.gz", hash = "sha256:11264edbab51896ecf546c18eb0dd56dff0428c6aa6d2cd87e643e07300eb310"}, ] [package.dependencies] -pycares = ">=4.0.0" +pycares = ">=4.9.0" [[package]] name = "aiohappyeyeballs" @@ -53,118 +53,122 @@ files = [ [[package]] name = "aiohasupervisor" -version = "0.3.0" +version = "0.3.1" description = "Asynchronous python client for Home Assistant Supervisor." optional = false python-versions = ">=3.12.0" groups = ["main"] files = [ - {file = "aiohasupervisor-0.3.0-py3-none-any.whl", hash = "sha256:f85b45c80ee24b381523e5a84a39f962f25e72c90026a3dcef2becea1d7f5501"}, - {file = "aiohasupervisor-0.3.0.tar.gz", hash = "sha256:91bf0b051f28582196f900a31c9bcbebec6de9e3ed1a32a2947a892c04748ce2"}, + {file = "aiohasupervisor-0.3.1-py3-none-any.whl", hash = "sha256:d5fa5df20562177703c701e95889a52595788c5790a856f285474d68553346a3"}, + {file = "aiohasupervisor-0.3.1.tar.gz", hash = "sha256:6d88c32e640932855cf5d7ade573208a003527a9687129923a71e3ab0f0cdf26"}, ] [package.dependencies] aiohttp = ">=3.3.0,<4.0.0" mashumaro = ">=3.11,<4.0" orjson = ">=3.6.1,<4.0.0" -yarl = ">=1.6.0,<2.0.0" [package.extras] -dev = ["aiohttp (==3.9.5)", "aioresponses (==0.7.6)", "codespell (==2.3.0)", "coverage (==7.6.0)", "mashumaro (==3.13.1)", "mypy (==1.10.1)", "orjson (==3.10.6)", "pre-commit (==3.7.1)", "pytest (==8.2.2)", "pytest-aiohttp (==1.0.5)", "pytest-cov (==5.0.0)", "pytest-timeout (==2.3.1)", "ruff (==0.5.2)", "yamllint (==1.35.1)", "yarl (==1.9.4)"] +dev = ["aiohttp (==3.11.18)", "aioresponses (==0.7.8)", "codespell (==2.4.1)", "coverage (==7.8.0)", "mashumaro (==3.15)", "mypy (==1.15.0)", "orjson (==3.10.16)", "pre-commit (==4.2.0)", "pytest (==8.3.5)", "pytest-aiohttp (==1.1.0)", "pytest-cov (==6.1.1)", "pytest-timeout (==2.3.1)", "ruff (==0.11.6)", "yamllint (==1.37.0)"] [[package]] name = "aiohttp" -version = "3.11.16" +version = "3.12.13" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.11.16-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa"}, - {file = "aiohttp-3.11.16-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955"}, - {file = "aiohttp-3.11.16-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8"}, - {file = "aiohttp-3.11.16-cp310-cp310-win32.whl", hash = "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814"}, - {file = "aiohttp-3.11.16-cp310-cp310-win_amd64.whl", hash = "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534"}, - {file = "aiohttp-3.11.16-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180"}, - {file = "aiohttp-3.11.16-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed"}, - {file = "aiohttp-3.11.16-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17"}, - {file = "aiohttp-3.11.16-cp311-cp311-win32.whl", hash = "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86"}, - {file = "aiohttp-3.11.16-cp311-cp311-win_amd64.whl", hash = "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24"}, - {file = "aiohttp-3.11.16-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27"}, - {file = "aiohttp-3.11.16-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713"}, - {file = "aiohttp-3.11.16-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71"}, - {file = "aiohttp-3.11.16-cp312-cp312-win32.whl", hash = "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2"}, - {file = "aiohttp-3.11.16-cp312-cp312-win_amd64.whl", hash = "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682"}, - {file = "aiohttp-3.11.16-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489"}, - {file = "aiohttp-3.11.16-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50"}, - {file = "aiohttp-3.11.16-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913"}, - {file = "aiohttp-3.11.16-cp313-cp313-win32.whl", hash = "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979"}, - {file = "aiohttp-3.11.16-cp313-cp313-win_amd64.whl", hash = "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802"}, - {file = "aiohttp-3.11.16-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bbcba75fe879ad6fd2e0d6a8d937f34a571f116a0e4db37df8079e738ea95c71"}, - {file = "aiohttp-3.11.16-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:87a6e922b2b2401e0b0cf6b976b97f11ec7f136bfed445e16384fbf6fd5e8602"}, - {file = "aiohttp-3.11.16-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccf10f16ab498d20e28bc2b5c1306e9c1512f2840f7b6a67000a517a4b37d5ee"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb3d0cc5cdb926090748ea60172fa8a213cec728bd6c54eae18b96040fcd6227"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d07502cc14ecd64f52b2a74ebbc106893d9a9717120057ea9ea1fd6568a747e7"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:776c8e959a01e5e8321f1dec77964cb6101020a69d5a94cd3d34db6d555e01f7"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0902e887b0e1d50424112f200eb9ae3dfed6c0d0a19fc60f633ae5a57c809656"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e87fd812899aa78252866ae03a048e77bd11b80fb4878ce27c23cade239b42b2"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0a950c2eb8ff17361abd8c85987fd6076d9f47d040ebffce67dce4993285e973"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:c10d85e81d0b9ef87970ecbdbfaeec14a361a7fa947118817fcea8e45335fa46"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7951decace76a9271a1ef181b04aa77d3cc309a02a51d73826039003210bdc86"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14461157d8426bcb40bd94deb0450a6fa16f05129f7da546090cebf8f3123b0f"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9756d9b9d4547e091f99d554fbba0d2a920aab98caa82a8fb3d3d9bee3c9ae85"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:87944bd16b7fe6160607f6a17808abd25f17f61ae1e26c47a491b970fb66d8cb"}, - {file = "aiohttp-3.11.16-cp39-cp39-win32.whl", hash = "sha256:92b7ee222e2b903e0a4b329a9943d432b3767f2d5029dbe4ca59fb75223bbe2e"}, - {file = "aiohttp-3.11.16-cp39-cp39-win_amd64.whl", hash = "sha256:17ae4664031aadfbcb34fd40ffd90976671fa0c0286e6c4113989f78bebab37a"}, - {file = "aiohttp-3.11.16.tar.gz", hash = "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8"}, -] - -[package.dependencies] -aiohappyeyeballs = ">=2.3.0" + {file = "aiohttp-3.12.13-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5421af8f22a98f640261ee48aae3a37f0c41371e99412d55eaf2f8a46d5dad29"}, + {file = "aiohttp-3.12.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fcda86f6cb318ba36ed8f1396a6a4a3fd8f856f84d426584392083d10da4de0"}, + {file = "aiohttp-3.12.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cd71c9fb92aceb5a23c4c39d8ecc80389c178eba9feab77f19274843eb9412d"}, + {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34ebf1aca12845066c963016655dac897651e1544f22a34c9b461ac3b4b1d3aa"}, + {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:893a4639694c5b7edd4bdd8141be296042b6806e27cc1d794e585c43010cc294"}, + {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:663d8ee3ffb3494502ebcccb49078faddbb84c1d870f9c1dd5a29e85d1f747ce"}, + {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0f8f6a85a0006ae2709aa4ce05749ba2cdcb4b43d6c21a16c8517c16593aabe"}, + {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1582745eb63df267c92d8b61ca655a0ce62105ef62542c00a74590f306be8cb5"}, + {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d59227776ee2aa64226f7e086638baa645f4b044f2947dbf85c76ab11dcba073"}, + {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06b07c418bde1c8e737d8fa67741072bd3f5b0fb66cf8c0655172188c17e5fa6"}, + {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9445c1842680efac0f81d272fd8db7163acfcc2b1436e3f420f4c9a9c5a50795"}, + {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:09c4767af0b0b98c724f5d47f2bf33395c8986995b0a9dab0575ca81a554a8c0"}, + {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3854fbde7a465318ad8d3fc5bef8f059e6d0a87e71a0d3360bb56c0bf87b18a"}, + {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2332b4c361c05ecd381edb99e2a33733f3db906739a83a483974b3df70a51b40"}, + {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1561db63fa1b658cd94325d303933553ea7d89ae09ff21cc3bcd41b8521fbbb6"}, + {file = "aiohttp-3.12.13-cp310-cp310-win32.whl", hash = "sha256:a0be857f0b35177ba09d7c472825d1b711d11c6d0e8a2052804e3b93166de1ad"}, + {file = "aiohttp-3.12.13-cp310-cp310-win_amd64.whl", hash = "sha256:fcc30ad4fb5cb41a33953292d45f54ef4066746d625992aeac33b8c681173178"}, + {file = "aiohttp-3.12.13-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c229b1437aa2576b99384e4be668af1db84b31a45305d02f61f5497cfa6f60c"}, + {file = "aiohttp-3.12.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04076d8c63471e51e3689c93940775dc3d12d855c0c80d18ac5a1c68f0904358"}, + {file = "aiohttp-3.12.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55683615813ce3601640cfaa1041174dc956d28ba0511c8cbd75273eb0587014"}, + {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:921bc91e602d7506d37643e77819cb0b840d4ebb5f8d6408423af3d3bf79a7b7"}, + {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e72d17fe0974ddeae8ed86db297e23dba39c7ac36d84acdbb53df2e18505a013"}, + {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0653d15587909a52e024a261943cf1c5bdc69acb71f411b0dd5966d065a51a47"}, + {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a77b48997c66722c65e157c06c74332cdf9c7ad00494b85ec43f324e5c5a9b9a"}, + {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6946bae55fd36cfb8e4092c921075cde029c71c7cb571d72f1079d1e4e013bc"}, + {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f95db8c8b219bcf294a53742c7bda49b80ceb9d577c8e7aa075612b7f39ffb7"}, + {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:03d5eb3cfb4949ab4c74822fb3326cd9655c2b9fe22e4257e2100d44215b2e2b"}, + {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6383dd0ffa15515283c26cbf41ac8e6705aab54b4cbb77bdb8935a713a89bee9"}, + {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6548a411bc8219b45ba2577716493aa63b12803d1e5dc70508c539d0db8dbf5a"}, + {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81b0fcbfe59a4ca41dc8f635c2a4a71e63f75168cc91026c61be665945739e2d"}, + {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a83797a0174e7995e5edce9dcecc517c642eb43bc3cba296d4512edf346eee2"}, + {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5734d8469a5633a4e9ffdf9983ff7cdb512524645c7a3d4bc8a3de45b935ac3"}, + {file = "aiohttp-3.12.13-cp311-cp311-win32.whl", hash = "sha256:fef8d50dfa482925bb6b4c208b40d8e9fa54cecba923dc65b825a72eed9a5dbd"}, + {file = "aiohttp-3.12.13-cp311-cp311-win_amd64.whl", hash = "sha256:9a27da9c3b5ed9d04c36ad2df65b38a96a37e9cfba6f1381b842d05d98e6afe9"}, + {file = "aiohttp-3.12.13-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0aa580cf80558557285b49452151b9c69f2fa3ad94c5c9e76e684719a8791b73"}, + {file = "aiohttp-3.12.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b103a7e414b57e6939cc4dece8e282cfb22043efd0c7298044f6594cf83ab347"}, + {file = "aiohttp-3.12.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f64e748e9e741d2eccff9597d09fb3cd962210e5b5716047cbb646dc8fe06f"}, + {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c955989bf4c696d2ededc6b0ccb85a73623ae6e112439398935362bacfaaf6"}, + {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d640191016763fab76072c87d8854a19e8e65d7a6fcfcbf017926bdbbb30a7e5"}, + {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dc507481266b410dede95dd9f26c8d6f5a14315372cc48a6e43eac652237d9b"}, + {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8a94daa873465d518db073bd95d75f14302e0208a08e8c942b2f3f1c07288a75"}, + {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f52420cde4ce0bb9425a375d95577fe082cb5721ecb61da3049b55189e4e6"}, + {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f7df1f620ec40f1a7fbcb99ea17d7326ea6996715e78f71a1c9a021e31b96b8"}, + {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3062d4ad53b36e17796dce1c0d6da0ad27a015c321e663657ba1cc7659cfc710"}, + {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:8605e22d2a86b8e51ffb5253d9045ea73683d92d47c0b1438e11a359bdb94462"}, + {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:54fbbe6beafc2820de71ece2198458a711e224e116efefa01b7969f3e2b3ddae"}, + {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:050bd277dfc3768b606fd4eae79dd58ceda67d8b0b3c565656a89ae34525d15e"}, + {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2637a60910b58f50f22379b6797466c3aa6ae28a6ab6404e09175ce4955b4e6a"}, + {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e986067357550d1aaa21cfe9897fa19e680110551518a5a7cf44e6c5638cb8b5"}, + {file = "aiohttp-3.12.13-cp312-cp312-win32.whl", hash = "sha256:ac941a80aeea2aaae2875c9500861a3ba356f9ff17b9cb2dbfb5cbf91baaf5bf"}, + {file = "aiohttp-3.12.13-cp312-cp312-win_amd64.whl", hash = "sha256:671f41e6146a749b6c81cb7fd07f5a8356d46febdaaaf07b0e774ff04830461e"}, + {file = "aiohttp-3.12.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d4a18e61f271127465bdb0e8ff36e8f02ac4a32a80d8927aa52371e93cd87938"}, + {file = "aiohttp-3.12.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:532542cb48691179455fab429cdb0d558b5e5290b033b87478f2aa6af5d20ace"}, + {file = "aiohttp-3.12.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d7eea18b52f23c050ae9db5d01f3d264ab08f09e7356d6f68e3f3ac2de9dfabb"}, + {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad7c8e5c25f2a26842a7c239de3f7b6bfb92304593ef997c04ac49fb703ff4d7"}, + {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6af355b483e3fe9d7336d84539fef460120c2f6e50e06c658fe2907c69262d6b"}, + {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a95cf9f097498f35c88e3609f55bb47b28a5ef67f6888f4390b3d73e2bac6177"}, + {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8ed8c38a1c584fe99a475a8f60eefc0b682ea413a84c6ce769bb19a7ff1c5ef"}, + {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0b9170d5d800126b5bc89d3053a2363406d6e327afb6afaeda2d19ee8bb103"}, + {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:372feeace612ef8eb41f05ae014a92121a512bd5067db8f25101dd88a8db11da"}, + {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a946d3702f7965d81f7af7ea8fb03bb33fe53d311df48a46eeca17e9e0beed2d"}, + {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a0c4725fae86555bbb1d4082129e21de7264f4ab14baf735278c974785cd2041"}, + {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b28ea2f708234f0a5c44eb6c7d9eb63a148ce3252ba0140d050b091b6e842d1"}, + {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d4f5becd2a5791829f79608c6f3dc745388162376f310eb9c142c985f9441cc1"}, + {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:60f2ce6b944e97649051d5f5cc0f439360690b73909230e107fd45a359d3e911"}, + {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69fc1909857401b67bf599c793f2183fbc4804717388b0b888f27f9929aa41f3"}, + {file = "aiohttp-3.12.13-cp313-cp313-win32.whl", hash = "sha256:7d7e68787a2046b0e44ba5587aa723ce05d711e3a3665b6b7545328ac8e3c0dd"}, + {file = "aiohttp-3.12.13-cp313-cp313-win_amd64.whl", hash = "sha256:5a178390ca90419bfd41419a809688c368e63c86bd725e1186dd97f6b89c2706"}, + {file = "aiohttp-3.12.13-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:36f6c973e003dc9b0bb4e8492a643641ea8ef0e97ff7aaa5c0f53d68839357b4"}, + {file = "aiohttp-3.12.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6cbfc73179bd67c229eb171e2e3745d2afd5c711ccd1e40a68b90427f282eab1"}, + {file = "aiohttp-3.12.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1e8b27b2d414f7e3205aa23bb4a692e935ef877e3a71f40d1884f6e04fd7fa74"}, + {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eabded0c2b2ef56243289112c48556c395d70150ce4220d9008e6b4b3dd15690"}, + {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:003038e83f1a3ff97409999995ec02fe3008a1d675478949643281141f54751d"}, + {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b6f46613031dbc92bdcaad9c4c22c7209236ec501f9c0c5f5f0b6a689bf50f3"}, + {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c332c6bb04650d59fb94ed96491f43812549a3ba6e7a16a218e612f99f04145e"}, + {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fea41a2c931fb582cb15dc86a3037329e7b941df52b487a9f8b5aa960153cbd"}, + {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:846104f45d18fb390efd9b422b27d8f3cf8853f1218c537f36e71a385758c896"}, + {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d6c85ac7dd350f8da2520bac8205ce99df4435b399fa7f4dc4a70407073e390"}, + {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5a1ecce0ed281bec7da8550da052a6b89552db14d0a0a45554156f085a912f48"}, + {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5304d74867028cca8f64f1cc1215eb365388033c5a691ea7aa6b0dc47412f495"}, + {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:64d1f24ee95a2d1e094a4cd7a9b7d34d08db1bbcb8aa9fb717046b0a884ac294"}, + {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:119c79922a7001ca6a9e253228eb39b793ea994fd2eccb79481c64b5f9d2a055"}, + {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bb18f00396d22e2f10cd8825d671d9f9a3ba968d708a559c02a627536b36d91c"}, + {file = "aiohttp-3.12.13-cp39-cp39-win32.whl", hash = "sha256:0022de47ef63fd06b065d430ac79c6b0bd24cdae7feaf0e8c6bac23b805a23a8"}, + {file = "aiohttp-3.12.13-cp39-cp39-win_amd64.whl", hash = "sha256:29e08111ccf81b2734ae03f1ad1cb03b9615e7d8f616764f22f71209c094f122"}, + {file = "aiohttp-3.12.13.tar.gz", hash = "sha256:47e2da578528264a12e4e3dd8dd72a7289e5f812758fe086473fab037a10fcce"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.5.0" aiosignal = ">=1.1.2" attrs = ">=17.3.0" frozenlist = ">=1.1.1" @@ -173,7 +177,7 @@ propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.2.0) ; sys_platform == \"linux\" or sys_platform == \"darwin\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "brotlicffi ; platform_python_implementation != \"CPython\""] [[package]] name = "aiohttp-asyncmdnsresolver" @@ -194,29 +198,29 @@ zeroconf = ">=0.142.0" [[package]] name = "aiohttp-cors" -version = "0.7.0" +version = "0.8.1" description = "CORS support for aiohttp" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-cors-0.7.0.tar.gz", hash = "sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d"}, - {file = "aiohttp_cors-0.7.0-py3-none-any.whl", hash = "sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e"}, + {file = "aiohttp_cors-0.8.1-py3-none-any.whl", hash = "sha256:3180cf304c5c712d626b9162b195b1db7ddf976a2a25172b35bb2448b890a80d"}, + {file = "aiohttp_cors-0.8.1.tar.gz", hash = "sha256:ccacf9cb84b64939ea15f859a146af1f662a6b1d68175754a07315e305fb1403"}, ] [package.dependencies] -aiohttp = ">=1.1" +aiohttp = ">=3.9" [[package]] name = "aiohttp-fast-zlib" -version = "0.2.3" +version = "0.3.0" description = "Use the fastest installed zlib compatible library with aiohttp" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp_fast_zlib-0.2.3-py3-none-any.whl", hash = "sha256:41a93670f88042faff3ebbd039fd2fc37a0c956193c20eb758be45b1655a7e04"}, - {file = "aiohttp_fast_zlib-0.2.3.tar.gz", hash = "sha256:d7e34621f2ac47155d9ad5d78f15ffb066a4ee849cb3d55df0077395ab4b3eff"}, + {file = "aiohttp_fast_zlib-0.3.0-py3-none-any.whl", hash = "sha256:d4cb20760a3e1137c93cb42c13871cbc9cd1fdc069352f2712cd650d6c0e537e"}, + {file = "aiohttp_fast_zlib-0.3.0.tar.gz", hash = "sha256:963a09de571b67fa0ef9cb44c5a32ede5cb1a51bc79fc21181b1cddd56b58b28"}, ] [package.dependencies] @@ -396,21 +400,21 @@ files = [ [[package]] name = "attrs" -version = "25.1.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, - {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] @@ -459,51 +463,75 @@ files = [ [[package]] name = "awesomeversion" -version = "24.6.0" +version = "25.5.0" description = "One version package to rule them all, One version package to find them, One version package to bring them all, and in the darkness bind them." optional = false -python-versions = "<4.0,>=3.8" +python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "awesomeversion-24.6.0-py3-none-any.whl", hash = "sha256:6768415b8954b379a25cebf21ed4f682cab10aebf3f82a6640aaaa15ec6821f2"}, - {file = "awesomeversion-24.6.0.tar.gz", hash = "sha256:aee7ccbaed6f8d84e0f0364080c7734a0166d77ea6ccfcc4900b38917f1efc71"}, + {file = "awesomeversion-25.5.0-py3-none-any.whl", hash = "sha256:34a676ae10e10d3a96829fcc890a1d377fe1a7a2b98ee19951631951c2aebff6"}, + {file = "awesomeversion-25.5.0.tar.gz", hash = "sha256:d64c9f3579d2f60a5aa506a9dd0b38a74ab5f45e04800f943a547c1102280f31"}, ] [[package]] name = "bcrypt" -version = "4.2.0" +version = "4.3.0" description = "Modern password hashing for your software and your servers" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7"}, - {file = "bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458"}, - {file = "bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5"}, - {file = "bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8"}, - {file = "bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34"}, - {file = "bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9"}, - {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a"}, - {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db"}, - {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170"}, - {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184"}, - {file = "bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221"}, + {file = "bcrypt-4.3.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d"}, + {file = "bcrypt-4.3.0-cp313-cp313t-win32.whl", hash = "sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4"}, + {file = "bcrypt-4.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669"}, + {file = "bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304"}, + {file = "bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51"}, + {file = "bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62"}, + {file = "bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505"}, + {file = "bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a"}, + {file = "bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c950d682f0952bafcceaf709761da0a32a942272fad381081b51096ffa46cea1"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:107d53b5c67e0bbc3f03ebf5b030e0403d24dda980f8e244795335ba7b4a027d"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:b693dbb82b3c27a1604a3dff5bfc5418a7e6a781bb795288141e5f80cf3a3492"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:b6354d3760fcd31994a14c89659dee887f1351a06e5dac3c1142307172a79f90"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a839320bf27d474e52ef8cb16449bb2ce0ba03ca9f44daba6d93fa1d8828e48a"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:bdc6a24e754a555d7316fa4774e64c6c3997d27ed2d1964d55920c7c227bc4ce"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:55a935b8e9a1d2def0626c4269db3fcd26728cbff1e84f0341465c31c4ee56d8"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938"}, + {file = "bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18"}, ] [package.extras] @@ -664,18 +692,18 @@ docs = ["Sphinx (>=5,<9)", "myst-parser (>=0.18,<4.1)", "sphinx-rtd-theme (>=1,< [[package]] name = "boto3" -version = "1.39.4" +version = "1.39.14" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "boto3-1.39.4-py3-none-any.whl", hash = "sha256:f8e9534b429121aa5c5b7c685c6a94dd33edf14f87926e9a182d5b50220ba284"}, - {file = "boto3-1.39.4.tar.gz", hash = "sha256:6c955729a1d70181bc8368e02a7d3f350884290def63815ebca8408ee6d47571"}, + {file = "boto3-1.39.14-py3-none-any.whl", hash = "sha256:82c6868cad18c3bd4170915e9525f9af5f83e9779c528417f8863629558fc2d0"}, + {file = "boto3-1.39.14.tar.gz", hash = "sha256:fabb16360a93b449d5241006485bcc761c26694e75ac01009f4459f114acc06e"}, ] [package.dependencies] -botocore = ">=1.39.4,<1.40.0" +botocore = ">=1.39.14,<1.40.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -684,14 +712,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.39.4" +version = "1.39.14" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "botocore-1.39.4-py3-none-any.whl", hash = "sha256:c41e167ce01cfd1973c3fa9856ef5244a51ddf9c82cb131120d8617913b6812a"}, - {file = "botocore-1.39.4.tar.gz", hash = "sha256:e662ac35c681f7942a93f2ec7b4cde8f8b56dd399da47a79fa3e370338521a56"}, + {file = "botocore-1.39.14-py3-none-any.whl", hash = "sha256:4ed551c77194167b7e8063f33059bc2f9b2ead0ed4ee33dc7857273648ed4349"}, + {file = "botocore-1.39.14.tar.gz", hash = "sha256:7fc44d4ad13b524e5d8a6296785776ef5898ac026ff74df9b35313831d507926"}, ] [package.dependencies] @@ -1010,112 +1038,118 @@ files = [ [[package]] name = "cryptography" -version = "44.0.1" +version = "45.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["main"] files = [ - {file = "cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd"}, - {file = "cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0"}, - {file = "cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf"}, - {file = "cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864"}, - {file = "cryptography-44.0.1-cp37-abi3-win32.whl", hash = "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a"}, - {file = "cryptography-44.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00"}, - {file = "cryptography-44.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62"}, - {file = "cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41"}, - {file = "cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b"}, - {file = "cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7"}, - {file = "cryptography-44.0.1-cp39-abi3-win32.whl", hash = "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9"}, - {file = "cryptography-44.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4"}, - {file = "cryptography-44.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7"}, - {file = "cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14"}, -] - -[package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + {file = "cryptography-45.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:7573d9eebaeceeb55285205dbbb8753ac1e962af3d9640791d12b36864065e71"}, + {file = "cryptography-45.0.3-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d377dde61c5d67eb4311eace661c3efda46c62113ff56bf05e2d679e02aebb5b"}, + {file = "cryptography-45.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae1e637f527750811588e4582988932c222f8251f7b7ea93739acb624e1487f"}, + {file = "cryptography-45.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ca932e11218bcc9ef812aa497cdf669484870ecbcf2d99b765d6c27a86000942"}, + {file = "cryptography-45.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af3f92b1dc25621f5fad065288a44ac790c5798e986a34d393ab27d2b27fcff9"}, + {file = "cryptography-45.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f8f8f0b73b885ddd7f3d8c2b2234a7d3ba49002b0223f58cfde1bedd9563c56"}, + {file = "cryptography-45.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9cc80ce69032ffa528b5e16d217fa4d8d4bb7d6ba8659c1b4d74a1b0f4235fca"}, + {file = "cryptography-45.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c824c9281cb628015bfc3c59335163d4ca0540d49de4582d6c2637312907e4b1"}, + {file = "cryptography-45.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5833bb4355cb377ebd880457663a972cd044e7f49585aee39245c0d592904578"}, + {file = "cryptography-45.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bb5bf55dcb69f7067d80354d0a348368da907345a2c448b0babc4215ccd3497"}, + {file = "cryptography-45.0.3-cp311-abi3-win32.whl", hash = "sha256:3ad69eeb92a9de9421e1f6685e85a10fbcfb75c833b42cc9bc2ba9fb00da4710"}, + {file = "cryptography-45.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:97787952246a77d77934d41b62fb1b6f3581d83f71b44796a4158d93b8f5c490"}, + {file = "cryptography-45.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:c92519d242703b675ccefd0f0562eb45e74d438e001f8ab52d628e885751fb06"}, + {file = "cryptography-45.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5edcb90da1843df85292ef3a313513766a78fbbb83f584a5a58fb001a5a9d57"}, + {file = "cryptography-45.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38deed72285c7ed699864f964a3f4cf11ab3fb38e8d39cfcd96710cd2b5bb716"}, + {file = "cryptography-45.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5555365a50efe1f486eed6ac7062c33b97ccef409f5970a0b6f205a7cfab59c8"}, + {file = "cryptography-45.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e4253ed8f5948a3589b3caee7ad9a5bf218ffd16869c516535325fece163dcc"}, + {file = "cryptography-45.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cfd84777b4b6684955ce86156cfb5e08d75e80dc2585e10d69e47f014f0a5342"}, + {file = "cryptography-45.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:a2b56de3417fd5f48773ad8e91abaa700b678dc7fe1e0c757e1ae340779acf7b"}, + {file = "cryptography-45.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:57a6500d459e8035e813bd8b51b671977fb149a8c95ed814989da682314d0782"}, + {file = "cryptography-45.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f22af3c78abfbc7cbcdf2c55d23c3e022e1a462ee2481011d518c7fb9c9f3d65"}, + {file = "cryptography-45.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:232954730c362638544758a8160c4ee1b832dc011d2c41a306ad8f7cccc5bb0b"}, + {file = "cryptography-45.0.3-cp37-abi3-win32.whl", hash = "sha256:cb6ab89421bc90e0422aca911c69044c2912fc3debb19bb3c1bfe28ee3dff6ab"}, + {file = "cryptography-45.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:d54ae41e6bd70ea23707843021c778f151ca258081586f0cfa31d936ae43d1b2"}, + {file = "cryptography-45.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed43d396f42028c1f47b5fec012e9e12631266e3825e95c00e3cf94d472dac49"}, + {file = "cryptography-45.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:fed5aaca1750e46db870874c9c273cd5182a9e9deb16f06f7bdffdb5c2bde4b9"}, + {file = "cryptography-45.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:00094838ecc7c6594171e8c8a9166124c1197b074cfca23645cee573910d76bc"}, + {file = "cryptography-45.0.3-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:92d5f428c1a0439b2040435a1d6bc1b26ebf0af88b093c3628913dd464d13fa1"}, + {file = "cryptography-45.0.3-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:ec64ee375b5aaa354b2b273c921144a660a511f9df8785e6d1c942967106438e"}, + {file = "cryptography-45.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:71320fbefd05454ef2d457c481ba9a5b0e540f3753354fff6f780927c25d19b0"}, + {file = "cryptography-45.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:edd6d51869beb7f0d472e902ef231a9b7689508e83880ea16ca3311a00bf5ce7"}, + {file = "cryptography-45.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:555e5e2d3a53b4fabeca32835878b2818b3f23966a4efb0d566689777c5a12c8"}, + {file = "cryptography-45.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:25286aacb947286620a31f78f2ed1a32cded7be5d8b729ba3fb2c988457639e4"}, + {file = "cryptography-45.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:050ce5209d5072472971e6efbfc8ec5a8f9a841de5a4db0ebd9c2e392cb81972"}, + {file = "cryptography-45.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:dc10ec1e9f21f33420cc05214989544727e776286c1c16697178978327b95c9c"}, + {file = "cryptography-45.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:9eda14f049d7f09c2e8fb411dda17dd6b16a3c76a1de5e249188a32aeb92de19"}, + {file = "cryptography-45.0.3.tar.gz", hash = "sha256:ec21313dd335c51d7877baf2972569f40a4291b76a0ce51391523ae358d05899"}, +] + +[package.dependencies] +cffi = {version = ">=1.14", markers = "platform_python_implementation != \"PyPy\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0) ; python_version >= \"3.8\""] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs ; python_full_version >= \"3.8.0\"", "sphinx-rtd-theme (>=3.0.0) ; python_full_version >= \"3.8.0\""] docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""] -pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8.0\""] +pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==44.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.3)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] name = "dbus-fast" -version = "2.44.1" +version = "2.44.2" description = "A faster version of dbus-next" optional = false python-versions = ">=3.9" groups = ["main"] markers = "platform_system == \"Linux\"" files = [ - {file = "dbus_fast-2.44.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c78a004ba43aeaf203a19169d2b4be238375905645999da30cb0da730df80cf2"}, - {file = "dbus_fast-2.44.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65a634286651398f3f1326e8200fc54289d52c2c00249d29cacfc691660a5da1"}, - {file = "dbus_fast-2.44.1-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0c4a128f8b29941307fc5722f37a1bb87ddcf733188d917ab374d9da0c6e1ce7"}, - {file = "dbus_fast-2.44.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:adaf459fbce22a63d3578f3ec782c6978edf975eb06d71fb5b7a690496cf6bbe"}, - {file = "dbus_fast-2.44.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:de871cf722c436bdcceb96b2a3af7084e1fa468f7916ae278ec8ec49a6fa7eef"}, - {file = "dbus_fast-2.44.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b40863de172031bcc02f54c6f05cccb0b882dc2e1b09e11314a8ccf38c558760"}, - {file = "dbus_fast-2.44.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8b7ae16555df6b56d3befcc51e036779ef47c0e954fdb9fb0821ac25212aefe9"}, - {file = "dbus_fast-2.44.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a220a28e88062a2548f0c6da9eb15fb7e3af70eae56729fc3795ce3e3fba057d"}, - {file = "dbus_fast-2.44.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ec5db912bd4cfeadf7134163d6dde684271cd44cf26e3b4720107f3de406623"}, - {file = "dbus_fast-2.44.1-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:6ad99f626837753b39a39e09facd2091ee4851ee1eb6ebec5fa9a9a231734254"}, - {file = "dbus_fast-2.44.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7aa157f689a114bfb5367c55884d35e25d57cf25202a6590ce05010f929e7df"}, - {file = "dbus_fast-2.44.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f961d8bcad80359f24c0156b3094f58a87d583d56139ee50922fe5894b6797cf"}, - {file = "dbus_fast-2.44.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1f38fb5c31846c3ada8fc2b693d8d19953d376a9ea21079e3686e93faa1f8a0f"}, - {file = "dbus_fast-2.44.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35e3cde53cc9180ce95c6c84a1e8d1ded429031e4a0a182606e8d22cf57d3294"}, - {file = "dbus_fast-2.44.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f30fb09f1ea13658fb4316511e27d6b94f8363b16f2d093efe73e6e289b740"}, - {file = "dbus_fast-2.44.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dd0f8d41f6ab9d4a782c116470bc319d690f9b50c97b6debc6d1fef08e4615a"}, - {file = "dbus_fast-2.44.1-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:9d6e386658343db380b9e4e81b3bf4e3c17135dbb5889173b1f2582b675b9a8c"}, - {file = "dbus_fast-2.44.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3bd27563c11219b6fde7a5458141d860d8445c2defb036bab360d1f9bf1dfae0"}, - {file = "dbus_fast-2.44.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0272784aceac821dd63c8187a8860179061a850269617ff5c5bd25ca37bf9307"}, - {file = "dbus_fast-2.44.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eed613a909a45f0e0a415c88b373024f007a9be56b1316812ed616d69a3b9161"}, - {file = "dbus_fast-2.44.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0d4288f2cba4f8309dcfd9f4392e0f4f2b5be6c796dfdb0c5e03228b1ab649b1"}, - {file = "dbus_fast-2.44.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50a9a4c6921f4b7446717fb4869750f54b561ce486b25b36550cb2a910c988d9"}, - {file = "dbus_fast-2.44.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89dc5db158bf9838979f732acc39e0e1ecd7e3295a09fa8adb93b09c097615a4"}, - {file = "dbus_fast-2.44.1-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:f11878c0c089d278861e48c02db8002496c2233b0f605b5630ef61f0b7fb0ea3"}, - {file = "dbus_fast-2.44.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd81f483b3ffb71e88478cfabccc1fab8d7154fccb1c661bfafcff9b0cfd996"}, - {file = "dbus_fast-2.44.1-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:ad499de96a991287232749c98a59f2436ed260f6fd9ad4cb3b04a4b1bbbef148"}, - {file = "dbus_fast-2.44.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:36c44286b11e83977cd29f9551b66b446bb6890dff04585852d975aa3a038ca2"}, - {file = "dbus_fast-2.44.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:89f2f6eccbb0e464b90e5a8741deb9d6a91873eeb41a8c7b963962b39eb1e0cd"}, - {file = "dbus_fast-2.44.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb74a227b071e1a7c517bf3a3e4a5a0a2660620084162e74f15010075534c9d5"}, - {file = "dbus_fast-2.44.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e3719399e687359b0ef66af1b720661dd4f12059db1c4f506e678569a2256b4"}, - {file = "dbus_fast-2.44.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:806450623ef3f8df846524da7e448edc8174261a01cfd5dfda92e3df89c0de10"}, - {file = "dbus_fast-2.44.1-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:55ad499b7ef08cb76fce9c9fdcdd6589d2ebfc7e53b3d261d8f40c6d97a8d901"}, - {file = "dbus_fast-2.44.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55d717865219ec2ae9977b6d067c05261cdc3ef6205c687c8bb92b3437886e58"}, - {file = "dbus_fast-2.44.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:39d4cc61e491e11912f76d70cc1c47387ab4f2e5b71f34bfa13eb11aa6026268"}, - {file = "dbus_fast-2.44.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9b3b10151f1140f7b6dd47a89fc37edd05d6213be0a1748eadba82fc144c05c2"}, - {file = "dbus_fast-2.44.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:33772c223f5cef1bacc298e83dc04b27b3a47065b245fde766fcc126e761dca7"}, - {file = "dbus_fast-2.44.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e3f42f982af45bcfa0ff23e808f3aa54a45fe4bf43aadd3beb5ace816fba76"}, - {file = "dbus_fast-2.44.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f29a81d86c9ce3020a5df8c1e5557edaa00e1e00c9804ec874d46c99d967a686"}, - {file = "dbus_fast-2.44.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:5dec134715457601c0fa8df3040a56d319de1a152464ae4d4bfc53bbb5c02e04"}, - {file = "dbus_fast-2.44.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893509b516f2f24b4e3f09a6b1f3a30f856cf237cd773cdc505ea7ab4fa3c863"}, - {file = "dbus_fast-2.44.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:db81275d708774f6a17c89f2e063398c0deb358c4d22b663a3dd99861f6683a4"}, - {file = "dbus_fast-2.44.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:161a3e6fc8783c30c9feb072e09604d96ec0c465b06bd35b6acc1a0316bd2a27"}, - {file = "dbus_fast-2.44.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:67febe6454e714d85a532bd84969001ed948bbaf1699a7e1e4c6abb5508c9522"}, - {file = "dbus_fast-2.44.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890f0fc046d5db66524ddedeca8c14b65739fbbf32d6488175c07428362bf250"}, - {file = "dbus_fast-2.44.1.tar.gz", hash = "sha256:b027e96c39ed5622bb54d811dcdbbe9d9d6edec3454808a85a1ceb1867d9e25c"}, + {file = "dbus_fast-2.44.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a07e3a66c0ac5fb0ae6f296f7f659c759347e739a5b6c5faf5fd470209715436"}, + {file = "dbus_fast-2.44.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10160e8e25a80b7b84363c82f43bafbba3ba320869f33dcf46eb68172f97d9a"}, + {file = "dbus_fast-2.44.2-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:526674fbb9de53e2538c513c2d1025985d0fd99b2f97855120a308eab8a90b82"}, + {file = "dbus_fast-2.44.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5c46a6698a31ff3f2600e75b39adf79a9db32ecac84a9eff6fbca41dfef6b51"}, + {file = "dbus_fast-2.44.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a5ff265dec3afe1f37d8f7da57f7e0b544479d8e29e126fbcecf0f539e13215"}, + {file = "dbus_fast-2.44.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b9ec223b9c83a3dde27602000a273e48de17b76f9f1cd16f8df2fd536b391891"}, + {file = "dbus_fast-2.44.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c037f93fe754399a52e0c0d049e30d2768009249ccaa065c47358625007e37c1"}, + {file = "dbus_fast-2.44.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b9e0f153165e6e4571d7611a9f1d34ace4168f0304a33c43ff9fad8c5855cef5"}, + {file = "dbus_fast-2.44.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ce7bccaefe0461138c17d414762a84751b4071fe2383f577b8437c0594caad4"}, + {file = "dbus_fast-2.44.2-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0ef232a0e5713e47a4f7201484646f2034606ea09d60a1bc9d79444bfc9052fe"}, + {file = "dbus_fast-2.44.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c3f940a48543e364f241cac0279c568fde7d748dc79c97cc5606823ec3035f2"}, + {file = "dbus_fast-2.44.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9c4079ee0da668cde461b72b072cf29061c96bff1210aa79d48aafea598fea5d"}, + {file = "dbus_fast-2.44.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e6f5ac08cbe344ab47c1e5f5b5912028403edd79a08c610c919ffc6f3346c959"}, + {file = "dbus_fast-2.44.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170fdbb232c060b885cb7329feab34d253d4705b4429727b431fddd0cd928bc4"}, + {file = "dbus_fast-2.44.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:567c2c7b1499e08f1bf3f6dee6dacac17f04d46c7b89984647f7923bfaf81e51"}, + {file = "dbus_fast-2.44.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ee39aa85d4b997726efe8698f82942e4988399abf85a1ad4c463f95e725110"}, + {file = "dbus_fast-2.44.2-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a0afe5cd44d1ee196dc02e81e4932fdf1fdbf5ca3ce8afbb439a1d9ddc33d6b5"}, + {file = "dbus_fast-2.44.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482b467685e9554c2515c528a7302b57edb2c9dd962d04379c2e22ab489680f5"}, + {file = "dbus_fast-2.44.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:613e0e3360c6c9a3a75ad1c90b5eee5ba2f4af405dd532c0cc0fc44ca6c82374"}, + {file = "dbus_fast-2.44.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a66b495be204716f6d51b3da58d8315f75288b85fe53fe7dc2ee97e3cafcab8"}, + {file = "dbus_fast-2.44.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4b5c2ccdffd547bb362671eb9cb251728077b8588701cb9bbe18f49f6362d182"}, + {file = "dbus_fast-2.44.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:13704054d837e51e74524cec0fbccb7318342f6d3aac430075c69f24e1664993"}, + {file = "dbus_fast-2.44.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcc5bf32596b0a2de7f3f708745203e1846be35949b621edf03a14732dcf0f8d"}, + {file = "dbus_fast-2.44.2-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:95263c7ffb07641341a4d58a0e371d8a5eaac3e05df33b4b6b407166e678594d"}, + {file = "dbus_fast-2.44.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1477afc3456a237a68cd1bb0e9d41f8cf721718f564ba92839d0b3db8435d6a4"}, + {file = "dbus_fast-2.44.2-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:b697ab2c32937af8ca7ea2029a7f81cea4b560ca6b33d2f10a6d97c897e104ba"}, + {file = "dbus_fast-2.44.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6b8886ddeb1a8db48490a7609a0559dc27dccd73a62f189ce2cf7f1a96afbcdf"}, + {file = "dbus_fast-2.44.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b6ccd00ae8f42d6d098f8252d56f1101c1a876adda94d1909e6c50ea71f79907"}, + {file = "dbus_fast-2.44.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bdf0014cd60a6de1cff80abdd7aa508bfc71bbd9d447bb69c061c6c77173ed13"}, + {file = "dbus_fast-2.44.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:123b9ca6640188cf7df34226f2a0468be19ace8ea8ea007679ed03e48ffe1fac"}, + {file = "dbus_fast-2.44.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcdbb4b4a0c42e6212267095e990ab2cedfe29c5afe1adcdb4195c25b4fc6de0"}, + {file = "dbus_fast-2.44.2-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a0f4af1fd6439845c127970f93102f41d75f94be8ec09390c39ad9fa9eee6696"}, + {file = "dbus_fast-2.44.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:797db94a38e6d9436b0bf5206794017ebbe019ec969a7f911368ea7097ff8fe0"}, + {file = "dbus_fast-2.44.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9eb55aa73bd5ae4e3b1090a5ae3a92f8ae5263e0c122b9d1b2f6091275b83ca4"}, + {file = "dbus_fast-2.44.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fd017a1ad478acacd145ec25a403253249fdb31ab6d2bc567bd3ef18f0a887a9"}, + {file = "dbus_fast-2.44.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b7f0dc2dd2d38a14bd8f0cc4db4dcef630c248ce743fe60cbf1f0c54fc41b7a0"}, + {file = "dbus_fast-2.44.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:206dc3b9a8619b932f234e55d39fe30c914adcd6bec70bd89ded71d382d2f46a"}, + {file = "dbus_fast-2.44.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96a33d043763b1ee17c2b1e9c5108e34b4091e3323f638af8b3e0e7bd441f667"}, + {file = "dbus_fast-2.44.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:713de29c3fc122726f871bffffd0ac5ecf2e578bd9031c1388d271b757571776"}, + {file = "dbus_fast-2.44.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e46159b0f236ba2b8f7ec5b02eed5c1fd5fa6e4485c89f082887b071ce3ff3df"}, + {file = "dbus_fast-2.44.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3667ce4c7d433c94cb428ac75dd6b041673335f8bb34487d806a5ac7d3540f8c"}, + {file = "dbus_fast-2.44.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5304cd238f927bd11a468d2a8607663152bca5ee69f9b13d64aff45628c025fd"}, + {file = "dbus_fast-2.44.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:19c97f9106b5f036e3db086a6066bfbbb0c3f34f172b24772ccf4f5e7a17e630"}, + {file = "dbus_fast-2.44.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6720a25717b2c41fd15e85ae920bc745aeddb93325822474334f4759e641b6f0"}, + {file = "dbus_fast-2.44.2.tar.gz", hash = "sha256:752f355c32e28468ba9f57b509e2694c4ba0d3d55ae6eb0035511c226438eb35"}, ] [[package]] @@ -1136,14 +1170,14 @@ profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "distlib" -version = "0.3.9" +version = "0.4.0" description = "Distribution utilities" optional = false python-versions = "*" groups = ["dev"] files = [ - {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, - {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, + {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, + {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, ] [[package]] @@ -1180,50 +1214,50 @@ typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] [[package]] name = "fnv-hash-fast" -version = "1.4.0" +version = "1.5.0" description = "A fast version of fnv1a" optional = false python-versions = "<4.0,>=3.10" groups = ["main"] files = [ - {file = "fnv_hash_fast-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9fd0d020e7dc9f9553316a833a225ec041ba34e31fa20c3d964a84743861feed"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:926cf9f74352f74e0945351c94ae2f114efcc8a89d99cbebd05e2ba7fc51e3dd"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32dc3e906878fffcd8a0b867c4bf9f4b65a60afece2b6ece4959b7683ba52161"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:11dafb53a5d3eb362e5b16bd958988b731ed376987b1486cb116a17939083295"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a990a9594bf20fdbcd03954f0af59449e91fbb82e825c72d1c2752d2e4ac5b7"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e5505f61d1bd7f94fd071f613814f84a6109226511b2228a2f70c9cdb63562f"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9efa2ccd2d6a849ebbc4231664098657f3257a8fc4f9326ddad31d4b92f90517"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4f3ce21650669f2db523f2c16a4abffb5af2544b7e6f5731657af426988e3204"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d108821985fd3c38ab586edcc617271c97fc9b6a1b5c07ff667dec4da0ea8dc4"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9992ff6e13cb7ecca44fc9289e0315ac634832eb24b61dcf7909901de657350b"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-win32.whl", hash = "sha256:9a4816bbcf41615ca7f48f6cf517abb952373b6adb0cdba996b019a3eafdfccb"}, - {file = "fnv_hash_fast-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:17b4ba9e0ccc0776a27625882db9e8faa591e1922df4a7b6d2d0b42bdf2b3547"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:10e55bf0987b2e74af39211223e6d4e7c17380ad91e5bd9d799eb5ec78b3f19d"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b49f0f8df92efc3f7d8894b1c5217379cb25d826716690b42692b93661b3eea0"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e489052acf4f279ffbd3ad7326b7306df9e91388295b207077e939fc10fdb9"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:4472a130fa7eb740c995f39c7c882e5b587a23489dcce5c8c96423f5adc443fb"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6acb872d1026293814ac5ca31adb80fb898e8b4823fc19dbb38cff12f1adad18"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:64f1a35e860442a24c36503a5bf5442bb548fe2f4bc8c06ae7c873dd387d7e96"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e609e8412520328c454418fd355ea6e558a66684fef9a91c55a1f90524977134"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:66f37b3fb877fd0719eaddcb924375c2a5a3d1dde443857720d41f69fe0a791c"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c53060f9d50164040649489f19c11b1b89bd04a061320e1bd7d1b6af714c236b"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9fe7aff4247cdc66e099b2bb5470cc2bceb4e1ae10be3adb89a2f0e83c7ef919"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-win32.whl", hash = "sha256:1db95120a50ebddd9bca8eaf8d20883334f3aa6f743d4651a0368058110a8ceb"}, - {file = "fnv_hash_fast-1.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:72a61703e02fcd2571631a07f09146352ec6f08320ce1604a24cba54bf310642"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7f1bbfe718df3aa10aafa2c40cf6bb9581a267c914a4005fc0f5e3ce21a01a12"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:25dd05a0e7f8381b2d881b122400862da4f855b80fa9d6f5a20cda0706fde9b7"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1038ab67c143f1119b2cad9fb3d909439e88f72f3b137015eb642ad91245734"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c5ae87deee0204f2aaabfc861bf322f0f1dea078c847e10e35bc67c7becfefd6"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a07b27755378f08e399fc124f724f3af58f8f54167f6fd525068e51ba7e9e9f"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37cb8e67d8d4df670a699d928a4ed74b7284724d73df736a8ff9f57178e6a720"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:5fa7945986ae71c68eef522335d33a671ed2c33952272ea4360d0c44331f90eb"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e6dd8f20122d0fba69171858438eb74f1f12f4630178ab0db9d05bd0dfc68054"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c410adea6d70c8663a168b1f499bb3cb9ff743675921aa8b6fb99e07cd83eb45"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:579e5ba4265f4fc41dbe6fbe12d133d22aa7948455ef8a16fbe7bc5d1666d6d8"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c9568b00ab3e91af8a8409c2955b5d781f9a338c0c00428e788ff77f3baac3ec"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-win32.whl", hash = "sha256:c04e54d919b5e0ef2cb6a2de0fbabb3d075ee2609324a678d2471c87542bbacb"}, - {file = "fnv_hash_fast-1.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:5eec9b18aee7ed014ba0b8a2cf59d5c2f2d83af683c4ad87e9c03dd2f4f5d573"}, - {file = "fnv_hash_fast-1.4.0.tar.gz", hash = "sha256:12a2a437263f08815bd2d5759c12e881408718bb82cfffceb0341575f2c43f0a"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:979ff5af776ad9f544ee5fccfbfb54dcd98717f57ae0e0cfb8cfe562d0324885"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb45441577b638f65756a46d7432459460335008557f34959c216d6d1b3f09b2"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3505142822a4c0eede472498f9528db5fc5a0ed08d3005dd8f1e0598b0a66f2b"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:6232702a03e6f34d6596042d842af3443aa7072818e6c4a1f3bf084f1051067b"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1db24e0f3addd6d87ab64c341e15504585d81f71af4fb289d61a50e0d14f1ea"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba29b624c6ab25801171e6c87ba28095a66230fd25af43cd16a9104813650d24"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49757db065cf8ef4e5de23139d023706ae58d85e0505d50eef380b486ccb4217"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9f091cfdd9b5891d80cd59951d1893e738bbf722ba021f0f1262c08f8388ac33"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b8d4abd9ff5d2cd34fa2c7b6d3847e9162cf65ec019f741807a489a04bf8c33b"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d35ef4f1b0ac3c04c8673e311b55d436c87ff9bb972716fbdd8d4fd6865dddb9"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-win32.whl", hash = "sha256:b374f16ab57e60bc08937d488b550b0ac83e97db45c9f6cec989cbcdee54c85e"}, + {file = "fnv_hash_fast-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0851115a98cbdabaa291b2ee5dc35810d8d56a4769a0c32bd5eec8b5aa6ccb6b"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ccf029f0f3eeca99c99a8fc7b7096f7af710e9791e208fcfa01d7ea55fb4999c"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a39408ac586ee9ccc24cf445576a37a51d1c483b76888f0d340bc19feec585c"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2f5ec4ab8d551e2e5a751b318b8829672d769f6f4b3e49719fd87e6577a839e"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:ad864cbfec3aec3390a99e9ace7901cca98863f72627afb234f5cc23e8aa203e"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abd37c3f36c2bf73cfa0817d0259e7cfc62db2c325be15c7dca9037a76cfd646"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd5c0f051598cb01b8e7a61cc9ca47a097c500a46e5abada8dcd549aee3b3a39"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c3f765093a7f6e87c38c08c331959a87925d05813c91de5fff109ff498dd9b17"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:14c5b6409749d79191e5857646dd1204b2111838e75fe220114ab3a952061766"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aa80edbbaded0cd7ef8655c3368c3b63c904824391c13eb0862c4588f516193d"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4dadc880e49ef50fcd427abd7e47f52990045bf48945af29ba110b44e500f45c"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-win32.whl", hash = "sha256:9ac99977bd88874a7a3b27e9a59ecf0aa3b30835d81ac3abc5144207a4d3dbfc"}, + {file = "fnv_hash_fast-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:d01f5c5c365109a786a09187ff129f79162c5b423ba9610640ecde692d4d866c"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0294a449e672583589e8e5cce9d60dfc5e29db3fb05737ccae98deba28b7d77f"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:643002874f4620c408fdf881041e7d8b23683e56b1d588604a3640758c4e6dfe"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13904ceb14e09c5d6092eca8f6e1a65ea8bb606328b4b86d055365f23657ca58"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:5747cc25ee940eaa70c05d0b3d0a49808e952b7dd8388453980b94ea9e95e837"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9640989256fcb9e95a383ebde372b79bb4b7e14d296e5242fb32c422a6d83480"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e3b79e3fada2925810efd1605f265f0335cafe48f1389c96c51261b3e2e05ff"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:ccd18302d1a2d800f6403be7d8cb02293f2e39363bc64cd843ed040396d36f1a"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:14c7672ae4cfaf8f88418dc23ef50977f4603c602932038ae52fae44b1b03aec"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:90fff41560a95d5262f2237259a94d0c8c662e131b13540e9db51dbec1a14912"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9b52650bd9107cfe8a81087b6bd9fa995f0ba23dafa1a7cb343aed99c136062"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a4b3fa3e5e3273872d021bc2d6ef26db273bdd82a1bedd49b3f798dbcb34bba"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-win32.whl", hash = "sha256:381175ad08ee8b0c69c14283a60a20d953c24bc19e2d80e5932eb590211c50dc"}, + {file = "fnv_hash_fast-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:db8e61e38d5eddf4a4115e82bbee35f0b1b1d5affe8736f78ffc833751746cf2"}, + {file = "fnv_hash_fast-1.5.0.tar.gz", hash = "sha256:c3f0d077a5e0eee6bc12938a6f560b6394b5736f3e30db83b2eca8e0fb948a74"}, ] [package.dependencies] @@ -1435,21 +1469,6 @@ files = [ {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] -[[package]] -name = "ha-ffmpeg" -version = "3.2.2" -description = "A library that handling with ffmpeg for home-assistant" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "ha_ffmpeg-3.2.2-py3-none-any.whl", hash = "sha256:4fd4a4f4cdaf3243d2737942f3f41f141e4437d2af1167655815dc03283b1652"}, - {file = "ha_ffmpeg-3.2.2.tar.gz", hash = "sha256:80e4a77b3eda73df456ec9cc3295a898ed7cbb8cd2d59798f10e8c10a8e6c401"}, -] - -[package.dependencies] -async-timeout = "*" - [[package]] name = "habluetooth" version = "4.0.1" @@ -1503,47 +1522,32 @@ dbus-fast = {version = ">=2.30.2", markers = "platform_system == \"Linux\""} [[package]] name = "hass-nabucasa" -version = "0.94.0" +version = "0.104.0" description = "Home Assistant cloud integration by Nabu Casa, Inc." optional = false python-versions = ">=3.13" groups = ["main"] files = [ - {file = "hass_nabucasa-0.94.0-py3-none-any.whl", hash = "sha256:5acbe999373b81e7f6cc8d2f5918fe9db0a9e18e52e6ddb19d7857818c039c46"}, - {file = "hass_nabucasa-0.94.0.tar.gz", hash = "sha256:2ae8ca877dbd7c128fd49f64383e69bd86a395ed175cf73d6f33478d07491947"}, + {file = "hass_nabucasa-0.104.0-py3-none-any.whl", hash = "sha256:c24a23dcc5cfb22c5f80bbbb9a7aaa51beb32590b926e9725326af96e2e0d662"}, + {file = "hass_nabucasa-0.104.0.tar.gz", hash = "sha256:c4d3755d004a47e68604f8b11cb54e92fe4bdbf7d29aef3f22395be0c09d880c"}, ] [package.dependencies] -acme = "3.2.0" +acme = "4.1.1" aiohttp = ">=3.6.1" async_timeout = ">=4" atomicwrites-homeassistant = "1.4.1" attrs = ">=19.3" ciso8601 = ">=2.3.0" cryptography = ">=42.0.0" +josepy = ">=2,<3" pycognito = "2024.5.1" PyJWT = ">=2.8.0" snitun = "0.40.0" webrtc-models = "<1.0.0" [package.extras] -test = ["codespell (==2.4.1)", "mypy (==1.15.0)", "pre-commit (==4.1.0)", "pre-commit-hooks (==5.0.0)", "pylint (==3.3.4)", "pytest (==8.3.4)", "pytest-aiohttp (==1.1.0)", "pytest-timeout (==2.3.1)", "ruff (==0.9.7)", "syrupy (==4.8.2)", "tomli (==2.2.1)", "types_atomicwrites (==1.4.5.1)", "types_pyOpenSSL (==24.1.0.20240722)", "xmltodict (==0.14.2)"] - -[[package]] -name = "hassil" -version = "2.2.3" -description = "The Home Assistant Intent Language parser" -optional = false -python-versions = ">=3.8.0" -groups = ["main"] -files = [ - {file = "hassil-2.2.3-py3-none-any.whl", hash = "sha256:d22032c5268e6bdfc7fb60fa8f52f3a955d5ca982ccbfe535ed074c593e66bdf"}, - {file = "hassil-2.2.3.tar.gz", hash = "sha256:8516ebde2caf72362ea566cd677cb382138be3f5d36889fee21bb313bfd7d0d8"}, -] - -[package.dependencies] -PyYAML = ">=6.0,<7" -unicode-rbnf = ">=2.2,<3" +test = ["codespell (==2.4.1)", "mypy (==1.16.1)", "pre-commit (==4.2.0)", "pre-commit-hooks (==5.0.0)", "pylint (==3.3.7)", "pytest (==8.4.1)", "pytest-aiohttp (==1.1.0)", "pytest-timeout (==2.4.0)", "ruff (==0.12.0)", "syrupy (==4.9.1)", "tomli (==2.2.1)", "types_atomicwrites (==1.4.5.1)", "types_pyOpenSSL (==24.1.0.20240722)", "xmltodict (==0.14.2)"] [[package]] name = "home-assistant-bluetooth" @@ -1560,89 +1564,69 @@ files = [ [package.dependencies] habluetooth = ">=3.0" -[[package]] -name = "home-assistant-intents" -version = "2025.3.28" -description = "Intents for Home Assistant" -optional = false -python-versions = ">=3.9.0" -groups = ["main"] -files = [ - {file = "home_assistant_intents-2025.3.28-py3-none-any.whl", hash = "sha256:14f589a5a188f8b0c52f06ff8998c171fda25f8729de7a4011636295d90e7295"}, - {file = "home_assistant_intents-2025.3.28.tar.gz", hash = "sha256:3b93717525ae738f9163a2215bb0628321b86bd8418bfd64e1d5ce571b84fef4"}, -] - [[package]] name = "homeassistant" version = "2025.7.0" description = "Open-source home automation platform running on Python 3." optional = false -python-versions = ">=3.13.0" +python-versions = ">=3.13.2" groups = ["main"] files = [ - {file = "homeassistant-2025.4.0-py3-none-any.whl", hash = "sha256:b1159c123b97fe372feadbe505cf920b87fbcd932177e5c0c86a6f6b3c6ee1b9"}, - {file = "homeassistant-2025.4.0.tar.gz", hash = "sha256:c1f9702e4a935da061d5f95254d25c039282862a510b3643ee76fb55a2b610f3"}, + {file = "homeassistant-2025.7.0-py3-none-any.whl", hash = "sha256:60e34c152a645c186d251612515b8ed5a2d2f631af57d51a19a7d4a2d43917bf"}, + {file = "homeassistant-2025.7.0.tar.gz", hash = "sha256:628b101cdb39e658939dd2954f423153f567a6a5a0f0ac86ec855e1d63f2905c"}, ] [package.dependencies] -aiodns = "3.2.0" -aiohasupervisor = "0.3.0" -aiohttp = "3.11.16" +aiodns = "3.5.0" +aiohasupervisor = "0.3.1" +aiohttp = "3.12.13" aiohttp-asyncmdnsresolver = "0.1.1" -aiohttp_cors = "0.7.0" -aiohttp-fast-zlib = "0.2.3" +aiohttp_cors = "0.8.1" +aiohttp-fast-zlib = "0.3.0" aiozoneinfo = "0.2.3" annotatedyaml = "0.4.5" astral = "2.2" async-interrupt = "1.2.2" atomicwrites-homeassistant = "1.4.1" -attrs = "25.1.0" +attrs = "25.3.0" audioop-lts = "0.2.1" -awesomeversion = "24.6.0" -bcrypt = "4.2.0" +awesomeversion = "25.5.0" +bcrypt = "4.3.0" certifi = ">=2021.5.30" ciso8601 = "2.3.2" cronsim = "2.6" -cryptography = "44.0.1" -fnv-hash-fast = "1.4.0" -ha-ffmpeg = "3.2.2" -hass-nabucasa = "0.94.0" -hassil = "2.2.3" +cryptography = "45.0.3" +fnv-hash-fast = "1.5.0" +hass-nabucasa = "0.104.0" home-assistant-bluetooth = "1.13.1" -home-assistant-intents = "2025.3.28" httpx = "0.28.1" ifaddr = "0.2.0" Jinja2 = "3.1.6" lru-dict = "1.3.0" -mutagen = "1.47.0" -numpy = "2.2.2" -orjson = "3.10.16" +orjson = "3.10.18" packaging = ">=23.1" -Pillow = "11.1.0" -propcache = "0.3.0" +Pillow = "11.2.1" +propcache = "0.3.2" psutil-home-assistant = "0.0.1" PyJWT = "2.10.1" -pymicro-vad = "1.0.1" -pyOpenSSL = "25.0.0" -pyspeex-noise = "1.0.2" +pyOpenSSL = "25.1.0" python-slugify = "8.0.4" -PyTurboJPEG = "1.7.5" PyYAML = "6.0.2" -requests = "2.32.3" +requests = "2.32.4" securetar = "2025.2.1" -SQLAlchemy = "2.0.39" +SQLAlchemy = "2.0.41" standard-aifc = "3.13.0" standard-telnetlib = "3.13.0" -typing-extensions = ">=4.13.0,<5.0" +typing-extensions = ">=4.14.0,<5.0" ulid-transform = "1.4.0" -urllib3 = ">=1.26.5,<2" -uv = "0.6.10" +urllib3 = ">=2.0" +uv = "0.7.1" voluptuous = "0.15.2" -voluptuous-openapi = "0.0.6" +voluptuous-openapi = "0.1.0" voluptuous-serialize = "2.6.0" webrtc-models = "0.3.0" -yarl = "1.18.3" -zeroconf = "0.146.0" +yarl = "1.20.1" +zeroconf = "0.147.0" [[package]] name = "httpcore" @@ -1781,19 +1765,18 @@ files = [ [[package]] name = "josepy" -version = "1.15.0" +version = "2.1.0" description = "JOSE protocol implementation in Python" optional = false -python-versions = "<4.0,>=3.8" +python-versions = "<4.0,>=3.9.2" groups = ["main"] files = [ - {file = "josepy-1.15.0-py3-none-any.whl", hash = "sha256:878c08cedd0a892c98c6d1a90b3cb869736f9c751f68ec8901e7b05a0c040fed"}, - {file = "josepy-1.15.0.tar.gz", hash = "sha256:46c9b13d1a5104ffbfa5853e555805c915dcde71c2cd91ce5386e84211281223"}, + {file = "josepy-2.1.0-py3-none-any.whl", hash = "sha256:0eadf09b96821bdae9a8b14145425cb9fe0bbee64c6fdfce3ccd4ceb7d7efbbd"}, + {file = "josepy-2.1.0.tar.gz", hash = "sha256:9beafbaa107ec7128e6c21d86b2bc2aea2f590158e50aca972dca3753046091f"}, ] [package.dependencies] cryptography = ">=1.5" -pyopenssl = ">=0.13" [package.extras] docs = ["sphinx (>=4.3.0)", "sphinx-rtd-theme (>=1.0)"] @@ -2116,18 +2099,6 @@ files = [ {file = "multidict-6.6.3.tar.gz", hash = "sha256:798a9eb12dab0a6c2e29c1de6f3468af5cb2da6053a20dfa3344907eed0937cc"}, ] -[[package]] -name = "mutagen" -version = "1.47.0" -description = "read and write audio tags for many formats" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719"}, - {file = "mutagen-1.47.0.tar.gz", hash = "sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99"}, -] - [[package]] name = "nodeenv" version = "1.9.1" @@ -2140,147 +2111,86 @@ files = [ {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] -[[package]] -name = "numpy" -version = "2.2.2" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "numpy-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e"}, - {file = "numpy-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e"}, - {file = "numpy-2.2.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715"}, - {file = "numpy-2.2.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a"}, - {file = "numpy-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97"}, - {file = "numpy-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957"}, - {file = "numpy-2.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d"}, - {file = "numpy-2.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd"}, - {file = "numpy-2.2.2-cp310-cp310-win32.whl", hash = "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160"}, - {file = "numpy-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014"}, - {file = "numpy-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189"}, - {file = "numpy-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323"}, - {file = "numpy-2.2.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac"}, - {file = "numpy-2.2.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e"}, - {file = "numpy-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c"}, - {file = "numpy-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f"}, - {file = "numpy-2.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826"}, - {file = "numpy-2.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8"}, - {file = "numpy-2.2.2-cp311-cp311-win32.whl", hash = "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50"}, - {file = "numpy-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2"}, - {file = "numpy-2.2.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467"}, - {file = "numpy-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a"}, - {file = "numpy-2.2.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825"}, - {file = "numpy-2.2.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37"}, - {file = "numpy-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748"}, - {file = "numpy-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0"}, - {file = "numpy-2.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278"}, - {file = "numpy-2.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba"}, - {file = "numpy-2.2.2-cp312-cp312-win32.whl", hash = "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283"}, - {file = "numpy-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb"}, - {file = "numpy-2.2.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc"}, - {file = "numpy-2.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369"}, - {file = "numpy-2.2.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd"}, - {file = "numpy-2.2.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be"}, - {file = "numpy-2.2.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84"}, - {file = "numpy-2.2.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff"}, - {file = "numpy-2.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0"}, - {file = "numpy-2.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de"}, - {file = "numpy-2.2.2-cp313-cp313-win32.whl", hash = "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9"}, - {file = "numpy-2.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369"}, - {file = "numpy-2.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391"}, - {file = "numpy-2.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39"}, - {file = "numpy-2.2.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317"}, - {file = "numpy-2.2.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49"}, - {file = "numpy-2.2.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2"}, - {file = "numpy-2.2.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7"}, - {file = "numpy-2.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb"}, - {file = "numpy-2.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648"}, - {file = "numpy-2.2.2-cp313-cp313t-win32.whl", hash = "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4"}, - {file = "numpy-2.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576"}, - {file = "numpy-2.2.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495"}, - {file = "numpy-2.2.2-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df"}, - {file = "numpy-2.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a"}, - {file = "numpy-2.2.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60"}, - {file = "numpy-2.2.2.tar.gz", hash = "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f"}, -] - [[package]] name = "orjson" -version = "3.10.16" +version = "3.10.18" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "orjson-3.10.16-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4cb473b8e79154fa778fb56d2d73763d977be3dcc140587e07dbc545bbfc38f8"}, - {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:622a8e85eeec1948690409a19ca1c7d9fd8ff116f4861d261e6ae2094fe59a00"}, - {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c682d852d0ce77613993dc967e90e151899fe2d8e71c20e9be164080f468e370"}, - {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c520ae736acd2e32df193bcff73491e64c936f3e44a2916b548da048a48b46b"}, - {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:134f87c76bfae00f2094d85cfab261b289b76d78c6da8a7a3b3c09d362fd1e06"}, - {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b59afde79563e2cf37cfe62ee3b71c063fd5546c8e662d7fcfc2a3d5031a5c4c"}, - {file = "orjson-3.10.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113602f8241daaff05d6fad25bd481d54c42d8d72ef4c831bb3ab682a54d9e15"}, - {file = "orjson-3.10.16-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4fc0077d101f8fab4031e6554fc17b4c2ad8fdbc56ee64a727f3c95b379e31da"}, - {file = "orjson-3.10.16-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9c6bf6ff180cd69e93f3f50380224218cfab79953a868ea3908430bcfaf9cb5e"}, - {file = "orjson-3.10.16-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5673eadfa952f95a7cd76418ff189df11b0a9c34b1995dff43a6fdbce5d63bf4"}, - {file = "orjson-3.10.16-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5fe638a423d852b0ae1e1a79895851696cb0d9fa0946fdbfd5da5072d9bb9551"}, - {file = "orjson-3.10.16-cp310-cp310-win32.whl", hash = "sha256:33af58f479b3c6435ab8f8b57999874b4b40c804c7a36b5cc6b54d8f28e1d3dd"}, - {file = "orjson-3.10.16-cp310-cp310-win_amd64.whl", hash = "sha256:0338356b3f56d71293c583350af26f053017071836b07e064e92819ecf1aa055"}, - {file = "orjson-3.10.16-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44fcbe1a1884f8bc9e2e863168b0f84230c3d634afe41c678637d2728ea8e739"}, - {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78177bf0a9d0192e0b34c3d78bcff7fe21d1b5d84aeb5ebdfe0dbe637b885225"}, - {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12824073a010a754bb27330cad21d6e9b98374f497f391b8707752b96f72e741"}, - {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddd41007e56284e9867864aa2f29f3136bb1dd19a49ca43c0b4eda22a579cf53"}, - {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0877c4d35de639645de83666458ca1f12560d9fa7aa9b25d8bb8f52f61627d14"}, - {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9a09a539e9cc3beead3e7107093b4ac176d015bec64f811afb5965fce077a03c"}, - {file = "orjson-3.10.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31b98bc9b40610fec971d9a4d67bb2ed02eec0a8ae35f8ccd2086320c28526ca"}, - {file = "orjson-3.10.16-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0ce243f5a8739f3a18830bc62dc2e05b69a7545bafd3e3249f86668b2bcd8e50"}, - {file = "orjson-3.10.16-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:64792c0025bae049b3074c6abe0cf06f23c8e9f5a445f4bab31dc5ca23dbf9e1"}, - {file = "orjson-3.10.16-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ea53f7e68eec718b8e17e942f7ca56c6bd43562eb19db3f22d90d75e13f0431d"}, - {file = "orjson-3.10.16-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a741ba1a9488c92227711bde8c8c2b63d7d3816883268c808fbeada00400c164"}, - {file = "orjson-3.10.16-cp311-cp311-win32.whl", hash = "sha256:c7ed2c61bb8226384c3fdf1fb01c51b47b03e3f4536c985078cccc2fd19f1619"}, - {file = "orjson-3.10.16-cp311-cp311-win_amd64.whl", hash = "sha256:cd67d8b3e0e56222a2e7b7f7da9031e30ecd1fe251c023340b9f12caca85ab60"}, - {file = "orjson-3.10.16-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6d3444abbfa71ba21bb042caa4b062535b122248259fdb9deea567969140abca"}, - {file = "orjson-3.10.16-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:30245c08d818fdcaa48b7d5b81499b8cae09acabb216fe61ca619876b128e184"}, - {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0ba1d0baa71bf7579a4ccdcf503e6f3098ef9542106a0eca82395898c8a500a"}, - {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb0beefa5ef3af8845f3a69ff2a4aa62529b5acec1cfe5f8a6b4141033fd46ef"}, - {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6daa0e1c9bf2e030e93c98394de94506f2a4d12e1e9dadd7c53d5e44d0f9628e"}, - {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9da9019afb21e02410ef600e56666652b73eb3e4d213a0ec919ff391a7dd52aa"}, - {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:daeb3a1ee17b69981d3aae30c3b4e786b0f8c9e6c71f2b48f1aef934f63f38f4"}, - {file = "orjson-3.10.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fed80eaf0e20a31942ae5d0728849862446512769692474be5e6b73123a23b"}, - {file = "orjson-3.10.16-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73390ed838f03764540a7bdc4071fe0123914c2cc02fb6abf35182d5fd1b7a42"}, - {file = "orjson-3.10.16-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a22bba012a0c94ec02a7768953020ab0d3e2b884760f859176343a36c01adf87"}, - {file = "orjson-3.10.16-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5385bbfdbc90ff5b2635b7e6bebf259652db00a92b5e3c45b616df75b9058e88"}, - {file = "orjson-3.10.16-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:02c6279016346e774dd92625d46c6c40db687b8a0d685aadb91e26e46cc33e1e"}, - {file = "orjson-3.10.16-cp312-cp312-win32.whl", hash = "sha256:7ca55097a11426db80f79378e873a8c51f4dde9ffc22de44850f9696b7eb0e8c"}, - {file = "orjson-3.10.16-cp312-cp312-win_amd64.whl", hash = "sha256:86d127efdd3f9bf5f04809b70faca1e6836556ea3cc46e662b44dab3fe71f3d6"}, - {file = "orjson-3.10.16-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:148a97f7de811ba14bc6dbc4a433e0341ffd2cc285065199fb5f6a98013744bd"}, - {file = "orjson-3.10.16-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1d960c1bf0e734ea36d0adc880076de3846aaec45ffad29b78c7f1b7962516b8"}, - {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a318cd184d1269f68634464b12871386808dc8b7c27de8565234d25975a7a137"}, - {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df23f8df3ef9223d1d6748bea63fca55aae7da30a875700809c500a05975522b"}, - {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b94dda8dd6d1378f1037d7f3f6b21db769ef911c4567cbaa962bb6dc5021cf90"}, - {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f12970a26666a8775346003fd94347d03ccb98ab8aa063036818381acf5f523e"}, - {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15a1431a245d856bd56e4d29ea0023eb4d2c8f71efe914beb3dee8ab3f0cd7fb"}, - {file = "orjson-3.10.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c83655cfc247f399a222567d146524674a7b217af7ef8289c0ff53cfe8db09f0"}, - {file = "orjson-3.10.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fa59ae64cb6ddde8f09bdbf7baf933c4cd05734ad84dcf4e43b887eb24e37652"}, - {file = "orjson-3.10.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ca5426e5aacc2e9507d341bc169d8af9c3cbe88f4cd4c1cf2f87e8564730eb56"}, - {file = "orjson-3.10.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6fd5da4edf98a400946cd3a195680de56f1e7575109b9acb9493331047157430"}, - {file = "orjson-3.10.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:980ecc7a53e567169282a5e0ff078393bac78320d44238da4e246d71a4e0e8f5"}, - {file = "orjson-3.10.16-cp313-cp313-win32.whl", hash = "sha256:28f79944dd006ac540a6465ebd5f8f45dfdf0948ff998eac7a908275b4c1add6"}, - {file = "orjson-3.10.16-cp313-cp313-win_amd64.whl", hash = "sha256:fe0a145e96d51971407cb8ba947e63ead2aa915db59d6631a355f5f2150b56b7"}, - {file = "orjson-3.10.16-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c35b5c1fb5a5d6d2fea825dec5d3d16bea3c06ac744708a8e1ff41d4ba10cdf1"}, - {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9aac7ecc86218b4b3048c768f227a9452287001d7548500150bb75ee21bf55d"}, - {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6e19f5102fff36f923b6dfdb3236ec710b649da975ed57c29833cb910c5a73ab"}, - {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17210490408eb62755a334a6f20ed17c39f27b4f45d89a38cd144cd458eba80b"}, - {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbbe04451db85916e52a9f720bd89bf41f803cf63b038595674691680cbebd1b"}, - {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a966eba501a3a1f309f5a6af32ed9eb8f316fa19d9947bac3e6350dc63a6f0a"}, - {file = "orjson-3.10.16-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01e0d22f06c81e6c435723343e1eefc710e0510a35d897856766d475f2a15687"}, - {file = "orjson-3.10.16-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7c1e602d028ee285dbd300fb9820b342b937df64d5a3336e1618b354e95a2569"}, - {file = "orjson-3.10.16-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d230e5020666a6725629df81e210dc11c3eae7d52fe909a7157b3875238484f3"}, - {file = "orjson-3.10.16-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0f8baac07d4555f57d44746a7d80fbe6b2c4fe2ed68136b4abb51cfec512a5e9"}, - {file = "orjson-3.10.16-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:524e48420b90fc66953e91b660b3d05faaf921277d6707e328fde1c218b31250"}, - {file = "orjson-3.10.16-cp39-cp39-win32.whl", hash = "sha256:a9f614e31423d7292dbca966a53b2d775c64528c7d91424ab2747d8ab8ce5c72"}, - {file = "orjson-3.10.16-cp39-cp39-win_amd64.whl", hash = "sha256:c338dc2296d1ed0d5c5c27dfb22d00b330555cb706c2e0be1e1c3940a0895905"}, - {file = "orjson-3.10.16.tar.gz", hash = "sha256:d2aaa5c495e11d17b9b93205f5fa196737ee3202f000aaebf028dc9a73750f10"}, + {file = "orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be3b9b143e8b9db05368b13b04c84d37544ec85bb97237b3a923f076265ec89c"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9b0aa09745e2c9b3bf779b096fa71d1cc2d801a604ef6dd79c8b1bfef52b2f92"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53a245c104d2792e65c8d225158f2b8262749ffe64bc7755b00024757d957a13"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9495ab2611b7f8a0a8a505bcb0f0cbdb5469caafe17b0e404c3c746f9900469"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73be1cbcebadeabdbc468f82b087df435843c809cd079a565fb16f0f3b23238f"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8936ee2679e38903df158037a2f1c108129dee218975122e37847fb1d4ac68"}, + {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7115fcbc8525c74e4c2b608129bef740198e9a120ae46184dac7683191042056"}, + {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:771474ad34c66bc4d1c01f645f150048030694ea5b2709b87d3bda273ffe505d"}, + {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c14047dbbea52886dd87169f21939af5d55143dad22d10db6a7514f058156a8"}, + {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:641481b73baec8db14fdf58f8967e52dc8bda1f2aba3aa5f5c1b07ed6df50b7f"}, + {file = "orjson-3.10.18-cp310-cp310-win32.whl", hash = "sha256:607eb3ae0909d47280c1fc657c4284c34b785bae371d007595633f4b1a2bbe06"}, + {file = "orjson-3.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:8770432524ce0eca50b7efc2a9a5f486ee0113a5fbb4231526d414e6254eba92"}, + {file = "orjson-3.10.18-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e0a183ac3b8e40471e8d843105da6fbe7c070faab023be3b08188ee3f85719b8"}, + {file = "orjson-3.10.18-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5ef7c164d9174362f85238d0cd4afdeeb89d9e523e4651add6a5d458d6f7d42d"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd14c5d99cdc7bf93f22b12ec3b294931518aa019e2a147e8aa2f31fd3240f7"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b672502323b6cd133c4af6b79e3bea36bad2d16bca6c1f645903fce83909a7a"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51f8c63be6e070ec894c629186b1c0fe798662b8687f3d9fdfa5e401c6bd7679"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9478ade5313d724e0495d167083c6f3be0dd2f1c9c8a38db9a9e912cdaf947"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:187aefa562300a9d382b4b4eb9694806e5848b0cedf52037bb5c228c61bb66d4"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da552683bc9da222379c7a01779bddd0ad39dd699dd6300abaf43eadee38334"}, + {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e450885f7b47a0231979d9c49b567ed1c4e9f69240804621be87c40bc9d3cf17"}, + {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5e3c9cc2ba324187cd06287ca24f65528f16dfc80add48dc99fa6c836bb3137e"}, + {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:50ce016233ac4bfd843ac5471e232b865271d7d9d44cf9d33773bcd883ce442b"}, + {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b3ceff74a8f7ffde0b2785ca749fc4e80e4315c0fd887561144059fb1c138aa7"}, + {file = "orjson-3.10.18-cp311-cp311-win32.whl", hash = "sha256:fdba703c722bd868c04702cac4cb8c6b8ff137af2623bc0ddb3b3e6a2c8996c1"}, + {file = "orjson-3.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:c28082933c71ff4bc6ccc82a454a2bffcef6e1d7379756ca567c772e4fb3278a"}, + {file = "orjson-3.10.18-cp311-cp311-win_arm64.whl", hash = "sha256:a6c7c391beaedd3fa63206e5c2b7b554196f14debf1ec9deb54b5d279b1b46f5"}, + {file = "orjson-3.10.18-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:50c15557afb7f6d63bc6d6348e0337a880a04eaa9cd7c9d569bcb4e760a24753"}, + {file = "orjson-3.10.18-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:356b076f1662c9813d5fa56db7d63ccceef4c271b1fb3dd522aca291375fcf17"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:559eb40a70a7494cd5beab2d73657262a74a2c59aff2068fdba8f0424ec5b39d"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3c29eb9a81e2fbc6fd7ddcfba3e101ba92eaff455b8d602bf7511088bbc0eae"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6612787e5b0756a171c7d81ba245ef63a3533a637c335aa7fcb8e665f4a0966f"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ac6bd7be0dcab5b702c9d43d25e70eb456dfd2e119d512447468f6405b4a69c"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f72f100cee8dde70100406d5c1abba515a7df926d4ed81e20a9730c062fe9ad"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca85398d6d093dd41dc0983cbf54ab8e6afd1c547b6b8a311643917fbf4e0c"}, + {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22748de2a07fcc8781a70edb887abf801bb6142e6236123ff93d12d92db3d406"}, + {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a83c9954a4107b9acd10291b7f12a6b29e35e8d43a414799906ea10e75438e6"}, + {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:303565c67a6c7b1f194c94632a4a39918e067bd6176a48bec697393865ce4f06"}, + {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:86314fdb5053a2f5a5d881f03fca0219bfdf832912aa88d18676a5175c6916b5"}, + {file = "orjson-3.10.18-cp312-cp312-win32.whl", hash = "sha256:187ec33bbec58c76dbd4066340067d9ece6e10067bb0cc074a21ae3300caa84e"}, + {file = "orjson-3.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:f9f94cf6d3f9cd720d641f8399e390e7411487e493962213390d1ae45c7814fc"}, + {file = "orjson-3.10.18-cp312-cp312-win_arm64.whl", hash = "sha256:3d600be83fe4514944500fa8c2a0a77099025ec6482e8087d7659e891f23058a"}, + {file = "orjson-3.10.18-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:69c34b9441b863175cc6a01f2935de994025e773f814412030f269da4f7be147"}, + {file = "orjson-3.10.18-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1ebeda919725f9dbdb269f59bc94f861afbe2a27dce5608cdba2d92772364d1c"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5adf5f4eed520a4959d29ea80192fa626ab9a20b2ea13f8f6dc58644f6927103"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7592bb48a214e18cd670974f289520f12b7aed1fa0b2e2616b8ed9e069e08595"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f872bef9f042734110642b7a11937440797ace8c87527de25e0c53558b579ccc"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0315317601149c244cb3ecef246ef5861a64824ccbcb8018d32c66a60a84ffbc"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0da26957e77e9e55a6c2ce2e7182a36a6f6b180ab7189315cb0995ec362e049"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb70d489bc79b7519e5803e2cc4c72343c9dc1154258adf2f8925d0b60da7c58"}, + {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9e86a6af31b92299b00736c89caf63816f70a4001e750bda179e15564d7a034"}, + {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c382a5c0b5931a5fc5405053d36c1ce3fd561694738626c77ae0b1dfc0242ca1"}, + {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8e4b2ae732431127171b875cb2668f883e1234711d3c147ffd69fe5be51a8012"}, + {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d808e34ddb24fc29a4d4041dcfafbae13e129c93509b847b14432717d94b44f"}, + {file = "orjson-3.10.18-cp313-cp313-win32.whl", hash = "sha256:ad8eacbb5d904d5591f27dee4031e2c1db43d559edb8f91778efd642d70e6bea"}, + {file = "orjson-3.10.18-cp313-cp313-win_amd64.whl", hash = "sha256:aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52"}, + {file = "orjson-3.10.18-cp313-cp313-win_arm64.whl", hash = "sha256:f54c1385a0e6aba2f15a40d703b858bedad36ded0491e55d35d905b2c34a4cc3"}, + {file = "orjson-3.10.18-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c95fae14225edfd699454e84f61c3dd938df6629a00c6ce15e704f57b58433bb"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5232d85f177f98e0cefabb48b5e7f60cff6f3f0365f9c60631fecd73849b2a82"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2783e121cafedf0d85c148c248a20470018b4ffd34494a68e125e7d5857655d1"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e54ee3722caf3db09c91f442441e78f916046aa58d16b93af8a91500b7bbf273"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2daf7e5379b61380808c24f6fc182b7719301739e4271c3ec88f2984a2d61f89"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f39b371af3add20b25338f4b29a8d6e79a8c7ed0e9dd49e008228a065d07781"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b819ed34c01d88c6bec290e6842966f8e9ff84b7694632e88341363440d4cc0"}, + {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2f6c57debaef0b1aa13092822cbd3698a1fb0209a9ea013a969f4efa36bdea57"}, + {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:755b6d61ffdb1ffa1e768330190132e21343757c9aa2308c67257cc81a1a6f5a"}, + {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce8d0a875a85b4c8579eab5ac535fb4b2a50937267482be402627ca7e7570ee3"}, + {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57b5d0673cbd26781bebc2bf86f99dd19bd5a9cb55f71cc4f66419f6b50f3d77"}, + {file = "orjson-3.10.18-cp39-cp39-win32.whl", hash = "sha256:951775d8b49d1d16ca8818b1f20c4965cae9157e7b562a2ae34d3967b8f21c8e"}, + {file = "orjson-3.10.18-cp39-cp39-win_amd64.whl", hash = "sha256:fdd9d68f83f0bc4406610b1ac68bdcded8c5ee58605cc69e643a06f4d075f429"}, + {file = "orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53"}, ] [[package]] @@ -2297,89 +2207,100 @@ files = [ [[package]] name = "pillow" -version = "11.1.0" +version = "11.2.1" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pillow-11.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8"}, - {file = "pillow-11.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192"}, - {file = "pillow-11.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a07dba04c5e22824816b2615ad7a7484432d7f540e6fa86af60d2de57b0fcee2"}, - {file = "pillow-11.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e267b0ed063341f3e60acd25c05200df4193e15a4a5807075cd71225a2386e26"}, - {file = "pillow-11.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bd165131fd51697e22421d0e467997ad31621b74bfc0b75956608cb2906dda07"}, - {file = "pillow-11.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:abc56501c3fd148d60659aae0af6ddc149660469082859fa7b066a298bde9482"}, - {file = "pillow-11.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:54ce1c9a16a9561b6d6d8cb30089ab1e5eb66918cb47d457bd996ef34182922e"}, - {file = "pillow-11.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73ddde795ee9b06257dac5ad42fcb07f3b9b813f8c1f7f870f402f4dc54b5269"}, - {file = "pillow-11.1.0-cp310-cp310-win32.whl", hash = "sha256:3a5fe20a7b66e8135d7fd617b13272626a28278d0e578c98720d9ba4b2439d49"}, - {file = "pillow-11.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:b6123aa4a59d75f06e9dd3dac5bf8bc9aa383121bb3dd9a7a612e05eabc9961a"}, - {file = "pillow-11.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:a76da0a31da6fcae4210aa94fd779c65c75786bc9af06289cd1c184451ef7a65"}, - {file = "pillow-11.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e06695e0326d05b06833b40b7ef477e475d0b1ba3a6d27da1bb48c23209bf457"}, - {file = "pillow-11.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96f82000e12f23e4f29346e42702b6ed9a2f2fea34a740dd5ffffcc8c539eb35"}, - {file = "pillow-11.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3cd561ded2cf2bbae44d4605837221b987c216cff94f49dfeed63488bb228d2"}, - {file = "pillow-11.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f189805c8be5ca5add39e6f899e6ce2ed824e65fb45f3c28cb2841911da19070"}, - {file = "pillow-11.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dd0052e9db3474df30433f83a71b9b23bd9e4ef1de13d92df21a52c0303b8ab6"}, - {file = "pillow-11.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:837060a8599b8f5d402e97197d4924f05a2e0d68756998345c829c33186217b1"}, - {file = "pillow-11.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aa8dd43daa836b9a8128dbe7d923423e5ad86f50a7a14dc688194b7be5c0dea2"}, - {file = "pillow-11.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0a2f91f8a8b367e7a57c6e91cd25af510168091fb89ec5146003e424e1558a96"}, - {file = "pillow-11.1.0-cp311-cp311-win32.whl", hash = "sha256:c12fc111ef090845de2bb15009372175d76ac99969bdf31e2ce9b42e4b8cd88f"}, - {file = "pillow-11.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd43429d0d7ed6533b25fc993861b8fd512c42d04514a0dd6337fb3ccf22761"}, - {file = "pillow-11.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:f7955ecf5609dee9442cbface754f2c6e541d9e6eda87fad7f7a989b0bdb9d71"}, - {file = "pillow-11.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a"}, - {file = "pillow-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b"}, - {file = "pillow-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3"}, - {file = "pillow-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a"}, - {file = "pillow-11.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1"}, - {file = "pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f"}, - {file = "pillow-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91"}, - {file = "pillow-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c"}, - {file = "pillow-11.1.0-cp312-cp312-win32.whl", hash = "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6"}, - {file = "pillow-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf"}, - {file = "pillow-11.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5"}, - {file = "pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc"}, - {file = "pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0"}, - {file = "pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1"}, - {file = "pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec"}, - {file = "pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5"}, - {file = "pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114"}, - {file = "pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352"}, - {file = "pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3"}, - {file = "pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9"}, - {file = "pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c"}, - {file = "pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65"}, - {file = "pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861"}, - {file = "pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081"}, - {file = "pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c"}, - {file = "pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547"}, - {file = "pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab"}, - {file = "pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9"}, - {file = "pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe"}, - {file = "pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756"}, - {file = "pillow-11.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:bf902d7413c82a1bfa08b06a070876132a5ae6b2388e2712aab3a7cbc02205c6"}, - {file = "pillow-11.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c1eec9d950b6fe688edee07138993e54ee4ae634c51443cfb7c1e7613322718e"}, - {file = "pillow-11.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e275ee4cb11c262bd108ab2081f750db2a1c0b8c12c1897f27b160c8bd57bbc"}, - {file = "pillow-11.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db853948ce4e718f2fc775b75c37ba2efb6aaea41a1a5fc57f0af59eee774b2"}, - {file = "pillow-11.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:ab8a209b8485d3db694fa97a896d96dd6533d63c22829043fd9de627060beade"}, - {file = "pillow-11.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:54251ef02a2309b5eec99d151ebf5c9904b77976c8abdcbce7891ed22df53884"}, - {file = "pillow-11.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5bb94705aea800051a743aa4874bb1397d4695fb0583ba5e425ee0328757f196"}, - {file = "pillow-11.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89dbdb3e6e9594d512780a5a1c42801879628b38e3efc7038094430844e271d8"}, - {file = "pillow-11.1.0-cp39-cp39-win32.whl", hash = "sha256:e5449ca63da169a2e6068dd0e2fcc8d91f9558aba89ff6d02121ca8ab11e79e5"}, - {file = "pillow-11.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:3362c6ca227e65c54bf71a5f88b3d4565ff1bcbc63ae72c34b07bbb1cc59a43f"}, - {file = "pillow-11.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:b20be51b37a75cc54c2c55def3fa2c65bb94ba859dde241cd0a4fd302de5ae0a"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8c730dc3a83e5ac137fbc92dfcfe1511ce3b2b5d7578315b63dbbb76f7f51d90"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d33d2fae0e8b170b6a6c57400e077412240f6f5bb2a342cf1ee512a787942bb"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8d65b38173085f24bc07f8b6c505cbb7418009fa1a1fcb111b1f4961814a442"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:015c6e863faa4779251436db398ae75051469f7c903b043a48f078e437656f83"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d44ff19eea13ae4acdaaab0179fa68c0c6f2f45d66a4d8ec1eda7d6cecbcc15f"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d3d8da4a631471dfaf94c10c85f5277b1f8e42ac42bade1ac67da4b4a7359b73"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4637b88343166249fe8aa94e7c4a62a180c4b3898283bb5d3d2fd5fe10d8e4e0"}, - {file = "pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20"}, + {file = "pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047"}, + {file = "pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95"}, + {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61"}, + {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1"}, + {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c"}, + {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d"}, + {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97"}, + {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579"}, + {file = "pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d"}, + {file = "pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad"}, + {file = "pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2"}, + {file = "pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70"}, + {file = "pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf"}, + {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7"}, + {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8"}, + {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600"}, + {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788"}, + {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e"}, + {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e"}, + {file = "pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6"}, + {file = "pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193"}, + {file = "pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7"}, + {file = "pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f"}, + {file = "pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b"}, + {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d"}, + {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4"}, + {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d"}, + {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4"}, + {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443"}, + {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c"}, + {file = "pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3"}, + {file = "pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941"}, + {file = "pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb"}, + {file = "pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28"}, + {file = "pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830"}, + {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0"}, + {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1"}, + {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f"}, + {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155"}, + {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14"}, + {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b"}, + {file = "pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2"}, + {file = "pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691"}, + {file = "pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c"}, + {file = "pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22"}, + {file = "pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7"}, + {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16"}, + {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b"}, + {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406"}, + {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91"}, + {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751"}, + {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9"}, + {file = "pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd"}, + {file = "pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e"}, + {file = "pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681"}, + {file = "pillow-11.2.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:7491cf8a79b8eb867d419648fff2f83cb0b3891c8b36da92cc7f1931d46108c8"}, + {file = "pillow-11.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b02d8f9cb83c52578a0b4beadba92e37d83a4ef11570a8688bbf43f4ca50909"}, + {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:014ca0050c85003620526b0ac1ac53f56fc93af128f7546623cc8e31875ab928"}, + {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3692b68c87096ac6308296d96354eddd25f98740c9d2ab54e1549d6c8aea9d79"}, + {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:f781dcb0bc9929adc77bad571b8621ecb1e4cdef86e940fe2e5b5ee24fd33b35"}, + {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:2b490402c96f907a166615e9a5afacf2519e28295f157ec3a2bb9bd57de638cb"}, + {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6b20b93b3ccc9c1b597999209e4bc5cf2853f9ee66e3fc9a400a78733ffc9a"}, + {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4b835d89c08a6c2ee7781b8dd0a30209a8012b5f09c0a665b65b0eb3560b6f36"}, + {file = "pillow-11.2.1-cp39-cp39-win32.whl", hash = "sha256:b10428b3416d4f9c61f94b494681280be7686bda15898a3a9e08eb66a6d92d67"}, + {file = "pillow-11.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:6ebce70c3f486acf7591a3d73431fa504a4e18a9b97ff27f5f47b7368e4b9dd1"}, + {file = "pillow-11.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:c27476257b2fdcd7872d54cfd119b3a9ce4610fb85c8e32b70b42e3680a29a1e"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044"}, + {file = "pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] +test-arrow = ["pyarrow"] tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] @@ -2437,110 +2358,110 @@ files = [ [[package]] name = "propcache" -version = "0.3.0" +version = "0.3.2" description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f"}, - {file = "propcache-0.3.0-cp310-cp310-win32.whl", hash = "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c"}, - {file = "propcache-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c"}, - {file = "propcache-0.3.0-cp311-cp311-win32.whl", hash = "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d"}, - {file = "propcache-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c"}, - {file = "propcache-0.3.0-cp312-cp312-win32.whl", hash = "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d"}, - {file = "propcache-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626"}, - {file = "propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374"}, - {file = "propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf"}, - {file = "propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863"}, - {file = "propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f"}, - {file = "propcache-0.3.0-cp39-cp39-win32.whl", hash = "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663"}, - {file = "propcache-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929"}, - {file = "propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043"}, - {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, + {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770"}, + {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3"}, + {file = "propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c"}, + {file = "propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70"}, + {file = "propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e"}, + {file = "propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897"}, + {file = "propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1"}, + {file = "propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1"}, + {file = "propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43"}, + {file = "propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02"}, + {file = "propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330"}, + {file = "propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394"}, + {file = "propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a7fad897f14d92086d6b03fdd2eb844777b0c4d7ec5e3bac0fbae2ab0602bbe5"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1f43837d4ca000243fd7fd6301947d7cb93360d03cd08369969450cc6b2ce3b4"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:261df2e9474a5949c46e962065d88eb9b96ce0f2bd30e9d3136bcde84befd8f2"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e514326b79e51f0a177daab1052bc164d9d9e54133797a3a58d24c9c87a3fe6d"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4a996adb6904f85894570301939afeee65f072b4fd265ed7e569e8d9058e4ec"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76cace5d6b2a54e55b137669b30f31aa15977eeed390c7cbfb1dafa8dfe9a701"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31248e44b81d59d6addbb182c4720f90b44e1efdc19f58112a3c3a1615fb47ef"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb7fa19dbf88d3857363e0493b999b8011eea856b846305d8c0512dfdf8fbb1"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d81ac3ae39d38588ad0549e321e6f773a4e7cc68e7751524a22885d5bbadf886"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:cc2782eb0f7a16462285b6f8394bbbd0e1ee5f928034e941ffc444012224171b"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:db429c19a6c7e8a1c320e6a13c99799450f411b02251fb1b75e6217cf4a14fcb"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:21d8759141a9e00a681d35a1f160892a36fb6caa715ba0b832f7747da48fb6ea"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2ca6d378f09adb13837614ad2754fa8afaee330254f404299611bce41a8438cb"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:34a624af06c048946709f4278b4176470073deda88d91342665d95f7c6270fbe"}, + {file = "propcache-0.3.2-cp39-cp39-win32.whl", hash = "sha256:4ba3fef1c30f306b1c274ce0b8baaa2c3cdd91f645c48f06394068f37d3837a1"}, + {file = "propcache-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:7a2368eed65fc69a7a7a40b27f22e85e7627b74216f0846b04ba5c116e191ec9"}, + {file = "propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f"}, + {file = "propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168"}, ] [[package]] @@ -2750,32 +2671,6 @@ tomlkit = ">=0.10.1" spelling = ["pyenchant (>=3.2,<4.0)"] testutils = ["gitpython (>3)"] -[[package]] -name = "pymicro-vad" -version = "1.0.1" -description = "Self-contained voice activity detector" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "pymicro_vad-1.0.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:036ae4ade4c9ad48e9f9d0c27ddb35dacd8f656790a1c0bc98200f8fbdf884e4"}, - {file = "pymicro_vad-1.0.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04a425f576f00cbdd91b3b85b8a23c3c081b1aa7edea8f19b2d6a18809cbcd32"}, - {file = "pymicro_vad-1.0.1-cp310-cp310-manylinux_2_34_armv7l.whl", hash = "sha256:0b17d5cd20aecd040a17f3730932ae87c17e72d4dd6bd6364b5ab5fd58a16957"}, - {file = "pymicro_vad-1.0.1-cp311-cp311-macosx_10_14_universal2.whl", hash = "sha256:2f1e691b37b1b50ad39534a74cb21961b2167fc50938c4c9b87702d91c6f66df"}, - {file = "pymicro_vad-1.0.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fa2bdbbe9dc7285950187116f165a26c2c373bffbd3f7482adb37f76a7eb9916"}, - {file = "pymicro_vad-1.0.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebbb6c44df9c7081f4e191cb45a26abcb2635faffdb2a3f615fd787872fd12e1"}, - {file = "pymicro_vad-1.0.1-cp311-cp311-manylinux_2_34_armv7l.whl", hash = "sha256:e8408fb819a7ec922f8c613f301e9174a3c8550f0f577eacfa6d5ff6f3d73d85"}, - {file = "pymicro_vad-1.0.1-cp312-cp312-macosx_10_14_universal2.whl", hash = "sha256:c4917f2862f8bfc862ce0cc46a63a5505f7d960d3987fe06b7b5e420446c098e"}, - {file = "pymicro_vad-1.0.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:499bf2799efde7f1135b215f52d5fab25718504deab919f5d3b0423a70d258ef"}, - {file = "pymicro_vad-1.0.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca40fd192807fa4e537e247747e70cc5d630ba13f035e2a60b4d00670c698f1"}, - {file = "pymicro_vad-1.0.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c78d72d7f02d8d33caaf176ed13e097b08b81051920bb22a0be905f4bf1e17f"}, - {file = "pymicro_vad-1.0.1-cp312-cp312-manylinux_2_34_armv7l.whl", hash = "sha256:29c0ccb5b8bd77d564c90526828260e94ea132c08098198f82ac1c5d6df767d6"}, - {file = "pymicro_vad-1.0.1-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c64635685a5e01995365b1f6956a7d39ef962c1739103a30e26c969f8b9ecb16"}, - {file = "pymicro_vad-1.0.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83ac1b0acf92a5f8049349f5c085a6a8cb01f0377c24201d59783a57af6ace20"}, - {file = "pymicro_vad-1.0.1-cp39-cp39-manylinux_2_34_armv7l.whl", hash = "sha256:d22ea23ca695958010943b6b03ccfae999b6b767deda086ce1445affd1b74a4b"}, - {file = "pymicro_vad-1.0.1.tar.gz", hash = "sha256:60e0508b338b694c7ad71c633c0da6fcd2678a88abb8e948b80fa68934965111"}, -] - [[package]] name = "pyobjc-core" version = "11.1" @@ -2869,18 +2764,18 @@ pyobjc-framework-Cocoa = ">=11.1" [[package]] name = "pyopenssl" -version = "25.0.0" +version = "25.1.0" description = "Python wrapper module around the OpenSSL library" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "pyOpenSSL-25.0.0-py3-none-any.whl", hash = "sha256:424c247065e46e76a37411b9ab1782541c23bb658bf003772c3405fbaa128e90"}, - {file = "pyopenssl-25.0.0.tar.gz", hash = "sha256:cd2cef799efa3936bb08e8ccb9433a575722b9dd986023f1cabc4ae64e9dac16"}, + {file = "pyopenssl-25.1.0-py3-none-any.whl", hash = "sha256:2b11f239acc47ac2e5aca04fd7fa829800aeee22a2eb30d744572a157bd8a1ab"}, + {file = "pyopenssl-25.1.0.tar.gz", hash = "sha256:8d031884482e0c67ee92bf9a4d8cceb08d92aba7136432ffb0703c5280fc205b"}, ] [package.dependencies] -cryptography = ">=41.0.5,<45" +cryptography = ">=41.0.5,<46" [package.extras] docs = ["sphinx (!=5.2.0,!=5.2.0.post0,!=7.2.5)", "sphinx_rtd_theme"] @@ -2909,17 +2804,6 @@ files = [ {file = "PyRIC-0.1.6.3.tar.gz", hash = "sha256:b539b01cafebd2406c00097f94525ea0f8ecd1dd92f7731f43eac0ef16c2ccc9"}, ] -[[package]] -name = "pyspeex-noise" -version = "1.0.2" -description = "Noise suppression and automatic gain with speex" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "pyspeex_noise-1.0.2.tar.gz", hash = "sha256:56a888ca2ef7fdea2316aa7fad3636d2fcf5f4450f3a0db58caa7c10a614b254"}, -] - [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -2953,20 +2837,6 @@ text-unidecode = ">=1.3" [package.extras] unidecode = ["Unidecode (>=1.1.1)"] -[[package]] -name = "pyturbojpeg" -version = "1.7.5" -description = "A Python wrapper of libjpeg-turbo for decoding and encoding JPEG image." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "PyTurboJPEG-1.7.5.tar.gz", hash = "sha256:5dd5f40dbf4159f41b6abaa123733910e8b1182df562b6ddb768991868b487d3"}, -] - -[package.dependencies] -numpy = "*" - [[package]] name = "pytz" version = "2025.2" @@ -3044,19 +2914,19 @@ files = [ [[package]] name = "requests" -version = "2.32.3" +version = "2.32.4" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, + {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, + {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" +charset_normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<3" @@ -3170,14 +3040,14 @@ files = [ [[package]] name = "s3transfer" -version = "0.13.0" +version = "0.13.1" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be"}, - {file = "s3transfer-0.13.0.tar.gz", hash = "sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"}, + {file = "s3transfer-0.13.1-py3-none-any.whl", hash = "sha256:a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724"}, + {file = "s3transfer-0.13.1.tar.gz", hash = "sha256:c3fdba22ba1bd367922f27ec8032d6a1cf5f10c934fb5d68cf60fd5a23d936cf"}, ] [package.dependencies] @@ -3249,81 +3119,81 @@ test = ["pytest (==8.3.4)", "pytest-aiohttp (==1.0.5)", "pytest-timeout (==2.3.1 [[package]] name = "sqlalchemy" -version = "2.0.39" +version = "2.0.41" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "SQLAlchemy-2.0.39-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:66a40003bc244e4ad86b72abb9965d304726d05a939e8c09ce844d27af9e6d37"}, - {file = "SQLAlchemy-2.0.39-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67de057fbcb04a066171bd9ee6bcb58738d89378ee3cabff0bffbf343ae1c787"}, - {file = "SQLAlchemy-2.0.39-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:533e0f66c32093a987a30df3ad6ed21170db9d581d0b38e71396c49718fbb1ca"}, - {file = "SQLAlchemy-2.0.39-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7399d45b62d755e9ebba94eb89437f80512c08edde8c63716552a3aade61eb42"}, - {file = "SQLAlchemy-2.0.39-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:788b6ff6728072b313802be13e88113c33696a9a1f2f6d634a97c20f7ef5ccce"}, - {file = "SQLAlchemy-2.0.39-cp37-cp37m-win32.whl", hash = "sha256:01da15490c9df352fbc29859d3c7ba9cd1377791faeeb47c100832004c99472c"}, - {file = "SQLAlchemy-2.0.39-cp37-cp37m-win_amd64.whl", hash = "sha256:f2bcb085faffcacf9319b1b1445a7e1cfdc6fb46c03f2dce7bc2d9a4b3c1cdc5"}, - {file = "SQLAlchemy-2.0.39-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b761a6847f96fdc2d002e29e9e9ac2439c13b919adfd64e8ef49e75f6355c548"}, - {file = "SQLAlchemy-2.0.39-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d7e3866eb52d914aea50c9be74184a0feb86f9af8aaaa4daefe52b69378db0b"}, - {file = "SQLAlchemy-2.0.39-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:995c2bacdddcb640c2ca558e6760383dcdd68830160af92b5c6e6928ffd259b4"}, - {file = "SQLAlchemy-2.0.39-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:344cd1ec2b3c6bdd5dfde7ba7e3b879e0f8dd44181f16b895940be9b842fd2b6"}, - {file = "SQLAlchemy-2.0.39-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5dfbc543578058c340360f851ddcecd7a1e26b0d9b5b69259b526da9edfa8875"}, - {file = "SQLAlchemy-2.0.39-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3395e7ed89c6d264d38bea3bfb22ffe868f906a7985d03546ec7dc30221ea980"}, - {file = "SQLAlchemy-2.0.39-cp38-cp38-win32.whl", hash = "sha256:bf555f3e25ac3a70c67807b2949bfe15f377a40df84b71ab2c58d8593a1e036e"}, - {file = "SQLAlchemy-2.0.39-cp38-cp38-win_amd64.whl", hash = "sha256:463ecfb907b256e94bfe7bcb31a6d8c7bc96eca7cbe39803e448a58bb9fcad02"}, - {file = "sqlalchemy-2.0.39-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6827f8c1b2f13f1420545bd6d5b3f9e0b85fe750388425be53d23c760dcf176b"}, - {file = "sqlalchemy-2.0.39-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9f119e7736967c0ea03aff91ac7d04555ee038caf89bb855d93bbd04ae85b41"}, - {file = "sqlalchemy-2.0.39-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4600c7a659d381146e1160235918826c50c80994e07c5b26946a3e7ec6c99249"}, - {file = "sqlalchemy-2.0.39-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a06e6c8e31c98ddc770734c63903e39f1947c9e3e5e4bef515c5491b7737dde"}, - {file = "sqlalchemy-2.0.39-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c4c433f78c2908ae352848f56589c02b982d0e741b7905228fad628999799de4"}, - {file = "sqlalchemy-2.0.39-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7bd5c5ee1448b6408734eaa29c0d820d061ae18cb17232ce37848376dcfa3e92"}, - {file = "sqlalchemy-2.0.39-cp310-cp310-win32.whl", hash = "sha256:87a1ce1f5e5dc4b6f4e0aac34e7bb535cb23bd4f5d9c799ed1633b65c2bcad8c"}, - {file = "sqlalchemy-2.0.39-cp310-cp310-win_amd64.whl", hash = "sha256:871f55e478b5a648c08dd24af44345406d0e636ffe021d64c9b57a4a11518304"}, - {file = "sqlalchemy-2.0.39-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a28f9c238f1e143ff42ab3ba27990dfb964e5d413c0eb001b88794c5c4a528a9"}, - {file = "sqlalchemy-2.0.39-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:08cf721bbd4391a0e765fe0fe8816e81d9f43cece54fdb5ac465c56efafecb3d"}, - {file = "sqlalchemy-2.0.39-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a8517b6d4005facdbd7eb4e8cf54797dbca100a7df459fdaff4c5123265c1cd"}, - {file = "sqlalchemy-2.0.39-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b2de1523d46e7016afc7e42db239bd41f2163316935de7c84d0e19af7e69538"}, - {file = "sqlalchemy-2.0.39-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:412c6c126369ddae171c13987b38df5122cb92015cba6f9ee1193b867f3f1530"}, - {file = "sqlalchemy-2.0.39-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b35e07f1d57b79b86a7de8ecdcefb78485dab9851b9638c2c793c50203b2ae8"}, - {file = "sqlalchemy-2.0.39-cp311-cp311-win32.whl", hash = "sha256:3eb14ba1a9d07c88669b7faf8f589be67871d6409305e73e036321d89f1d904e"}, - {file = "sqlalchemy-2.0.39-cp311-cp311-win_amd64.whl", hash = "sha256:78f1b79132a69fe8bd6b5d91ef433c8eb40688ba782b26f8c9f3d2d9ca23626f"}, - {file = "sqlalchemy-2.0.39-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c457a38351fb6234781d054260c60e531047e4d07beca1889b558ff73dc2014b"}, - {file = "sqlalchemy-2.0.39-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:018ee97c558b499b58935c5a152aeabf6d36b3d55d91656abeb6d93d663c0c4c"}, - {file = "sqlalchemy-2.0.39-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5493a8120d6fc185f60e7254fc056a6742f1db68c0f849cfc9ab46163c21df47"}, - {file = "sqlalchemy-2.0.39-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2cf5b5ddb69142511d5559c427ff00ec8c0919a1e6c09486e9c32636ea2b9dd"}, - {file = "sqlalchemy-2.0.39-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f03143f8f851dd8de6b0c10784363712058f38209e926723c80654c1b40327a"}, - {file = "sqlalchemy-2.0.39-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06205eb98cb3dd52133ca6818bf5542397f1dd1b69f7ea28aa84413897380b06"}, - {file = "sqlalchemy-2.0.39-cp312-cp312-win32.whl", hash = "sha256:7f5243357e6da9a90c56282f64b50d29cba2ee1f745381174caacc50d501b109"}, - {file = "sqlalchemy-2.0.39-cp312-cp312-win_amd64.whl", hash = "sha256:2ed107331d188a286611cea9022de0afc437dd2d3c168e368169f27aa0f61338"}, - {file = "sqlalchemy-2.0.39-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87"}, - {file = "sqlalchemy-2.0.39-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716"}, - {file = "sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4"}, - {file = "sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6b0a1c7ed54a5361aaebb910c1fa864bae34273662bb4ff788a527eafd6e14d"}, - {file = "sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e"}, - {file = "sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c08a972cbac2a14810463aec3a47ff218bb00c1a607e6689b531a7c589c50723"}, - {file = "sqlalchemy-2.0.39-cp313-cp313-win32.whl", hash = "sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7"}, - {file = "sqlalchemy-2.0.39-cp313-cp313-win_amd64.whl", hash = "sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0"}, - {file = "sqlalchemy-2.0.39-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2600a50d590c22d99c424c394236899ba72f849a02b10e65b4c70149606408b5"}, - {file = "sqlalchemy-2.0.39-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4eff9c270afd23e2746e921e80182872058a7a592017b2713f33f96cc5f82e32"}, - {file = "sqlalchemy-2.0.39-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7332868ce891eda48896131991f7f2be572d65b41a4050957242f8e935d5d7"}, - {file = "sqlalchemy-2.0.39-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:125a7763b263218a80759ad9ae2f3610aaf2c2fbbd78fff088d584edf81f3782"}, - {file = "sqlalchemy-2.0.39-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:04545042969833cb92e13b0a3019549d284fd2423f318b6ba10e7aa687690a3c"}, - {file = "sqlalchemy-2.0.39-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:805cb481474e111ee3687c9047c5f3286e62496f09c0e82e8853338aaaa348f8"}, - {file = "sqlalchemy-2.0.39-cp39-cp39-win32.whl", hash = "sha256:34d5c49f18778a3665d707e6286545a30339ad545950773d43977e504815fa70"}, - {file = "sqlalchemy-2.0.39-cp39-cp39-win_amd64.whl", hash = "sha256:35e72518615aa5384ef4fae828e3af1b43102458b74a8c481f69af8abf7e802a"}, - {file = "sqlalchemy-2.0.39-py3-none-any.whl", hash = "sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f"}, - {file = "sqlalchemy-2.0.39.tar.gz", hash = "sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22"}, -] - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} + {file = "SQLAlchemy-2.0.41-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6854175807af57bdb6425e47adbce7d20a4d79bbfd6f6d6519cd10bb7109a7f8"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05132c906066142103b83d9c250b60508af556982a385d96c4eaa9fb9720ac2b"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b4af17bda11e907c51d10686eda89049f9ce5669b08fbe71a29747f1e876036"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:c0b0e5e1b5d9f3586601048dd68f392dc0cc99a59bb5faf18aab057ce00d00b2"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0b3dbf1e7e9bc95f4bac5e2fb6d3fb2f083254c3fdd20a1789af965caf2d2348"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-win32.whl", hash = "sha256:1e3f196a0c59b0cae9a0cd332eb1a4bda4696e863f4f1cf84ab0347992c548c2"}, + {file = "SQLAlchemy-2.0.41-cp37-cp37m-win_amd64.whl", hash = "sha256:6ab60a5089a8f02009f127806f777fca82581c49e127f08413a66056bd9166dd"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-win32.whl", hash = "sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda"}, + {file = "sqlalchemy-2.0.41-cp310-cp310-win_amd64.whl", hash = "sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-win32.whl", hash = "sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8"}, + {file = "sqlalchemy-2.0.41-cp311-cp311-win_amd64.whl", hash = "sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-win32.whl", hash = "sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6"}, + {file = "sqlalchemy-2.0.41-cp312-cp312-win_amd64.whl", hash = "sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f"}, + {file = "sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90144d3b0c8b139408da50196c5cad2a6909b51b23df1f0538411cd23ffa45d3"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:023b3ee6169969beea3bb72312e44d8b7c27c75b347942d943cf49397b7edeb5"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725875a63abf7c399d4548e686debb65cdc2549e1825437096a0af1f7e374814"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81965cc20848ab06583506ef54e37cf15c83c7e619df2ad16807c03100745dea"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dd5ec3aa6ae6e4d5b5de9357d2133c07be1aff6405b136dad753a16afb6717dd"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ff8e80c4c4932c10493ff97028decfdb622de69cae87e0f127a7ebe32b4069c6"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-win32.whl", hash = "sha256:4d44522480e0bf34c3d63167b8cfa7289c1c54264c2950cc5fc26e7850967e45"}, + {file = "sqlalchemy-2.0.41-cp38-cp38-win_amd64.whl", hash = "sha256:81eedafa609917040d39aa9332e25881a8e7a0862495fcdf2023a9667209deda"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9a420a91913092d1e20c86a2f5f1fc85c1a8924dbcaf5e0586df8aceb09c9cc2"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:906e6b0d7d452e9a98e5ab8507c0da791856b2380fdee61b765632bb8698026f"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a373a400f3e9bac95ba2a06372c4fd1412a7cee53c37fc6c05f829bf672b8769"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:087b6b52de812741c27231b5a3586384d60c353fbd0e2f81405a814b5591dc8b"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:34ea30ab3ec98355235972dadc497bb659cc75f8292b760394824fab9cf39826"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8280856dd7c6a68ab3a164b4a4b1c51f7691f6d04af4d4ca23d6ecf2261b7923"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-win32.whl", hash = "sha256:b50eab9994d64f4a823ff99a0ed28a6903224ddbe7fef56a6dd865eec9243440"}, + {file = "sqlalchemy-2.0.41-cp39-cp39-win_amd64.whl", hash = "sha256:5e22575d169529ac3e0a120cf050ec9daa94b6a9597993d1702884f6954a7d71"}, + {file = "sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576"}, + {file = "sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9"}, +] + +[package.dependencies] +greenlet = {version = ">=1", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} typing-extensions = ">=4.6.0" [package.extras] -aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] -aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"] +aioodbc = ["aioodbc", "greenlet (>=1)"] +aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (>=1)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"] mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] @@ -3334,7 +3204,7 @@ mysql-connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=8)"] oracle-oracledb = ["oracledb (>=1.0.1)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"] postgresql-pg8000 = ["pg8000 (>=1.29.1)"] postgresql-psycopg = ["psycopg (>=3.0.7)"] postgresql-psycopg2binary = ["psycopg2-binary"] @@ -3455,34 +3325,23 @@ files = [ {file = "ulid_transform-1.4.0.tar.gz", hash = "sha256:5914a3c4277b0d25ebb67f47bfee2167ac858d970249ea275221fb3e5d91c9a0"}, ] -[[package]] -name = "unicode-rbnf" -version = "2.3.0" -description = "Rule-based number formatting using Unicode CLDR data" -optional = false -python-versions = ">=3.8.0" -groups = ["main"] -files = [ - {file = "unicode_rbnf-2.3.0-py3-none-any.whl", hash = "sha256:cb4fd74dcd090faf3eb17d528ba03cef09b44d3c360f5905c51245fec154ffcc"}, - {file = "unicode_rbnf-2.3.0.tar.gz", hash = "sha256:8a3ac2fe199929b7f342bbc74f5f86f01a4e7d324811be02ea6474851e73e5ad"}, -] - [[package]] name = "urllib3" -version = "1.26.20" +version = "2.5.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"}, - {file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"}, + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, ] [package.extras] -brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "usb-devices" @@ -3498,42 +3357,42 @@ files = [ [[package]] name = "uv" -version = "0.6.10" +version = "0.7.1" description = "An extremely fast Python package and project manager, written in Rust." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "uv-0.6.10-py3-none-linux_armv6l.whl", hash = "sha256:06932d36f1afaf611522a6a7ec361dac48dc67a1147d24e9eadee9703b15faaf"}, - {file = "uv-0.6.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e5c2ba1922c47a245d7393465fcee942df5a8bd8b80489a7b8860ba9d60102f9"}, - {file = "uv-0.6.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd8a4bcfd33a0dcae3fc0936bff8602f74e5719cf839e3df233059a0b8c8330d"}, - {file = "uv-0.6.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:4dd20c47898c15ebd4b5f48101062ea248e32513bfc61fc04bc822abfe39ce8a"}, - {file = "uv-0.6.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:950c9cd7b75f67e25760d2f43ad4b0ee3f8c6724fe0a9cf9eff948b3044b6a6d"}, - {file = "uv-0.6.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acca1dca7be342b2b8e26e509aa07c3144cb009788140eee045da2aad6a0c6fe"}, - {file = "uv-0.6.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:13ac09945976dc0df0edde7e4ba3a46107036a114117c8ff84916e55216c2e32"}, - {file = "uv-0.6.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:145e75b99d6b7bdce8e454a851cfcd5605ff0491d568244c66fa75ca6b071bd6"}, - {file = "uv-0.6.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666d9fe312c810bba77633dbd463dc85f5a6a0d07905726a014dc53d07c774d9"}, - {file = "uv-0.6.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b98e8884093cbfb1a1cc3f855aa22f97ec8da1a87e0e761800e165d4f9224a45"}, - {file = "uv-0.6.10-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:e8a8a75cf34c0814c1eabdbe651741d44fb125a6dcbe159b2da02871bbfdec7e"}, - {file = "uv-0.6.10-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:5260f52386e217615553f2f42740ce2f64ba439ff0fd502dc5b06250eb8ae613"}, - {file = "uv-0.6.10-py3-none-musllinux_1_1_i686.whl", hash = "sha256:603aebbaf6be938120c73fd36e9fd85f5e1b671d3d4638b3086f478e2bb423d9"}, - {file = "uv-0.6.10-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d1f1bc7d94a4a7fdd75142be71b6bf2d7e01282f322721da185d711f065d7b80"}, - {file = "uv-0.6.10-py3-none-win32.whl", hash = "sha256:df6560256b93441c70ea2c062975bce2307a32de280f103cedb8db4a0f542348"}, - {file = "uv-0.6.10-py3-none-win_amd64.whl", hash = "sha256:d795721fdd32e0471c952b7cb02a030657b6e67625fe836f4df14a3ae4aa4921"}, - {file = "uv-0.6.10-py3-none-win_arm64.whl", hash = "sha256:5188dc7041f4166bf64182d76c32c873f750259b6e4621a1400c26ebeea8c8dd"}, - {file = "uv-0.6.10.tar.gz", hash = "sha256:cbbb03deb30af457cd93ad299ee5c3258ade3d900b4dee1af936c8a6d87d5bcb"}, + {file = "uv-0.7.1-py3-none-linux_armv6l.whl", hash = "sha256:ea2024e6a9daeea3ff6cab8ad4afe3b2aa0be9e07bad57646a749896e58648ad"}, + {file = "uv-0.7.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d9c0c70bd3734cdae20cf22889a0394307a86451bb7c9126f0542eb998dd1472"}, + {file = "uv-0.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5526f68ce9a5ba35ef13a14d144dc834b4940bd460fedc55f8313f9b7534b63c"}, + {file = "uv-0.7.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:1d6f914601b769ad0f9a090573e2dc4365e0eaeb377d09cd74c5d47c97002c20"}, + {file = "uv-0.7.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c5572a2b1d6dbf1cbff315e55931f891d8706ef5ed76e94a7d5e6e6dae075b3a"}, + {file = "uv-0.7.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53eabd3aabc774d01da7836c58675c3e5cafd4285540e846debddfd056345d2c"}, + {file = "uv-0.7.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6bbf096970de17be0c2a1e28f24ebddaad9ad4d0f8d8f75364149cdde75d7462"}, + {file = "uv-0.7.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c94cb14377c0efa65eb0267cfebfb5212729dc73fd61e4897e38839e3e72d763"}, + {file = "uv-0.7.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7025c9ba6f6f3d842a2b2915a579ff87eda901736105ee0379653bb4ff6b50d2"}, + {file = "uv-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b503d808310a978453bb91a448ffaf61542b192127c30be136443debac9cdaa"}, + {file = "uv-0.7.1-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:57690b6e3b946dcf8b7b5836806d632f1a0d7667eae7af1302da812dbb7be7e5"}, + {file = "uv-0.7.1-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:bf54fab715d6eb2332ff3276f80fddc6ee9e7faf29669d4bfb1918dd53ffc408"}, + {file = "uv-0.7.1-py3-none-musllinux_1_1_i686.whl", hash = "sha256:877145523c348344c6fa2651559e9555dc4210730ad246afb4dd3414424afb3d"}, + {file = "uv-0.7.1-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:ef8765771785a56b2e5485f3c6f9ec04cbd2c077be2fe1f2786ded5710e33c0d"}, + {file = "uv-0.7.1-py3-none-win32.whl", hash = "sha256:2220b942b2eb8a0c5cc91af5d57c2eef7a25053037f9f311e85a2d5dd9154f88"}, + {file = "uv-0.7.1-py3-none-win_amd64.whl", hash = "sha256:425064544f1e20b014447cf523e04e891bf6962e60dd25f495724b271f8911e0"}, + {file = "uv-0.7.1-py3-none-win_arm64.whl", hash = "sha256:7239a0ffd4695300a3b6d2004ab664e80be7ef2c46b677b0f47d6409affe2212"}, + {file = "uv-0.7.1.tar.gz", hash = "sha256:40a15f1fc73df852d7655530e5768e29dc7227ab25d9baeb711a8dde9e7f8234"}, ] [[package]] name = "virtualenv" -version = "20.31.2" +version = "20.32.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11"}, - {file = "virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af"}, + {file = "virtualenv-20.32.0-py3-none-any.whl", hash = "sha256:2c310aecb62e5aa1b06103ed7c2977b81e042695de2697d01017ff0f1034af56"}, + {file = "virtualenv-20.32.0.tar.gz", hash = "sha256:886bf75cadfdc964674e6e33eb74d787dff31ca314ceace03ca5810620f4ecf0"}, ] [package.dependencies] @@ -3559,14 +3418,14 @@ files = [ [[package]] name = "voluptuous-openapi" -version = "0.0.6" +version = "0.1.0" description = "Convert voluptuous schemas to OpenAPI Schema object" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "voluptuous_openapi-0.0.6-py3-none-any.whl", hash = "sha256:3561bbe5f46483f4cd9f631a0bd4a3ac3d7d74bab24f41bcd09b52501f712d5e"}, - {file = "voluptuous_openapi-0.0.6.tar.gz", hash = "sha256:4078c2acef23e04ceeab1ba58252590fcdc3ba6e3ed34521e8595374ab4de884"}, + {file = "voluptuous_openapi-0.1.0-py3-none-any.whl", hash = "sha256:c3aac740286d368c90a99e007d55ddca7fcddf790d218c60ee0eeec2fcd3db2b"}, + {file = "voluptuous_openapi-0.1.0.tar.gz", hash = "sha256:84bc44107c472ba8782f7a4cb342d19d155d5fe7f92367f092cd96cc850ff1b7"}, ] [package.dependencies] @@ -3866,189 +3725,211 @@ all = ["winrt-Windows.Foundation.Collections[all] (>=3.2.1.0,<3.3.0.0)", "winrt- [[package]] name = "yarl" -version = "1.18.3" +version = "1.20.1" description = "Yet another URL library" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, - {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, - {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, - {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, - {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, - {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, - {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, - {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, - {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, - {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, - {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, - {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, - {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, + {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4"}, + {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a"}, + {file = "yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13"}, + {file = "yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8"}, + {file = "yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e"}, + {file = "yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773"}, + {file = "yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004"}, + {file = "yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5"}, + {file = "yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1"}, + {file = "yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7"}, + {file = "yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e"}, + {file = "yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d"}, + {file = "yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e42ba79e2efb6845ebab49c7bf20306c4edf74a0b20fc6b2ccdd1a219d12fad3"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41493b9b7c312ac448b7f0a42a089dffe1d6e6e981a2d76205801a023ed26a2b"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5a5928ff5eb13408c62a968ac90d43f8322fd56d87008b8f9dabf3c0f6ee983"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30c41ad5d717b3961b2dd785593b67d386b73feca30522048d37298fee981805"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:59febc3969b0781682b469d4aca1a5cab7505a4f7b85acf6db01fa500fa3f6ba"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2b6fb3622b7e5bf7a6e5b679a69326b4279e805ed1699d749739a61d242449e"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:749d73611db8d26a6281086f859ea7ec08f9c4c56cec864e52028c8b328db723"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9427925776096e664c39e131447aa20ec738bdd77c049c48ea5200db2237e000"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff70f32aa316393eaf8222d518ce9118148eddb8a53073c2403863b41033eed5"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c7ddf7a09f38667aea38801da8b8d6bfe81df767d9dfc8c88eb45827b195cd1c"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57edc88517d7fc62b174fcfb2e939fbc486a68315d648d7e74d07fac42cec240"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dab096ce479d5894d62c26ff4f699ec9072269d514b4edd630a393223f45a0ee"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14a85f3bd2d7bb255be7183e5d7d6e70add151a98edf56a770d6140f5d5f4010"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c89b5c792685dd9cd3fa9761c1b9f46fc240c2a3265483acc1565769996a3f8"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:69e9b141de5511021942a6866990aea6d111c9042235de90e08f94cf972ca03d"}, + {file = "yarl-1.20.1-cp39-cp39-win32.whl", hash = "sha256:b5f307337819cdfdbb40193cad84978a029f847b0a357fbe49f712063cfc4f06"}, + {file = "yarl-1.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:eae7bfe2069f9c1c5b05fc7fe5d612e5bbc089a39309904ee8b829e322dcad00"}, + {file = "yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77"}, + {file = "yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -propcache = ">=0.2.0" +propcache = ">=0.2.1" [[package]] name = "zeroconf" -version = "0.146.0" +version = "0.147.0" description = "A pure python implementation of multicast DNS service discovery" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "zeroconf-0.146.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b5e243aea14ba78cb8cde3b835d031bbf1ceb7ab9113b720bf5977c0e03335d"}, - {file = "zeroconf-0.146.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:68d1162cc3a803424dc02ef4bf0010a6ffc10433c1f66b84432b310a2a3567f1"}, - {file = "zeroconf-0.146.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06af1a06731b32ac31a9e296b7316464199511d5c8641bc01e7db0a67b590a84"}, - {file = "zeroconf-0.146.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:2b45488494db640fc3633d80f3f9ac8e65f50fb57dd4094d34c9fbd1caa865e9"}, - {file = "zeroconf-0.146.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b081ee58508fba527f79bf0dee17e1aa18c9511101b7c2732696b364c7315f34"}, - {file = "zeroconf-0.146.0-cp310-cp310-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c043a7eb64c381a43d2c1b9bd1ce1643eab1b301e86dfb942e318dddd37288b"}, - {file = "zeroconf-0.146.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ca098696dd9dad6cda78e401965cb863424781a50f768deba80e20a03bbf3c82"}, - {file = "zeroconf-0.146.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:94833bcd486a2dcc4e9151c612a63111f09936d93017c8ae3962b406ffd5a29b"}, - {file = "zeroconf-0.146.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:38cc4a7016a5700893f040c6fe92b89be71d83960138bba3e017295546eaea14"}, - {file = "zeroconf-0.146.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9e54c996e752be52f94b075e3df5732f1f7b35a2e314054d1d9a599d047ffcde"}, - {file = "zeroconf-0.146.0-cp310-cp310-win32.whl", hash = "sha256:79b13cf61ffe4e1a6ec3ea6d435ff297e87a81108c54be658e0e4794a8cbd1be"}, - {file = "zeroconf-0.146.0-cp310-cp310-win_amd64.whl", hash = "sha256:f1586ad6b3d1099c67386a30a3d1562615c84e0aa826d55adcaf38f9369d0be9"}, - {file = "zeroconf-0.146.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1b13f84b52f50ac5d1c5e849ce05bfb238d3260dfa053a05574d43d481f3ae95"}, - {file = "zeroconf-0.146.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ca7370091b2e060a5263f8208c150123a5f8648750b8decd27f3f7634e2e872"}, - {file = "zeroconf-0.146.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df3b0fe03fa142aef8b133ca50887212f12e91155c05b1a7461da961f7e5e456"}, - {file = "zeroconf-0.146.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b836ba5f9763c25bccd28c6a75db666ee9fe2982d8b10b0c3f182846a236c6d7"}, - {file = "zeroconf-0.146.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b57fe79aea8986ceb1ec6edf07647ee4211d08ae8189fcbfdb803f0b6a53ac"}, - {file = "zeroconf-0.146.0-cp311-cp311-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3a73eb7dbca8830d5b1ca8f645ef6fa48613132372a4fa24721761c84c89f92"}, - {file = "zeroconf-0.146.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eee9e454826e92f80693d6d3b3f171df61fccd13d5a49a439a3c5c6b37fcec41"}, - {file = "zeroconf-0.146.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:b041ce5993dc931fdc819babf706534950d09ccc9b59044d2fb8838bd607ac4a"}, - {file = "zeroconf-0.146.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c69d3ea479b36660efdab534cf5ca48f9d3e26d540be5c7051f3ca129968bb1"}, - {file = "zeroconf-0.146.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1e083eb3cc580aaac1c546d13d473dbc67dd96251e487a2ee76788fd444878f"}, - {file = "zeroconf-0.146.0-cp311-cp311-win32.whl", hash = "sha256:1c6d03baa781e206a41341ef5ca7a482a8541f18fce2766d5f960e844b36b556"}, - {file = "zeroconf-0.146.0-cp311-cp311-win_amd64.whl", hash = "sha256:e0c0bbf504dc88aa453705d0c2a966182461c4d0b73da12698672f3310f20334"}, - {file = "zeroconf-0.146.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9fbd7f6bfd421d28561657463795a8a4487fa2adecb872b5f19f04edcb9c3b3"}, - {file = "zeroconf-0.146.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2972be542d6ae32ef715f899ad2bb3fdee877c42fd4a9bb148033b4ccaca6a08"}, - {file = "zeroconf-0.146.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:459542edd64b276296da5776cf86de5a7d1529f25038fc8a93a8a70b014f2671"}, - {file = "zeroconf-0.146.0-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:8517c68576a3fece27882ff5743e69620ffc5a973b3d8ed21a28210b52da95d5"}, - {file = "zeroconf-0.146.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a63b901281619bab0106c993c80ed1db534e38d1c57d5553806f3430467d493"}, - {file = "zeroconf-0.146.0-cp312-cp312-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:85291bab82fe11df5c410152f410ab86ca3dae27327222530027ec7edf878dea"}, - {file = "zeroconf-0.146.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:14443655df3b4fe7510eefe49f5b1385db57ac1fd7ab2aabb36e18cc614e0158"}, - {file = "zeroconf-0.146.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7f794cd616ffb2c0588286bc33e3cb2df9f9bd277cd93b714050639b3d7564e5"}, - {file = "zeroconf-0.146.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e3ab0015afb0189cb80f115ffd5985f9bfab29e73bb073d4a9cb0a21ff5c9dc9"}, - {file = "zeroconf-0.146.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6534b6acf6db2dd1888053dbece9ce330d951c3bd98fbe27f28d6bc29311b64f"}, - {file = "zeroconf-0.146.0-cp312-cp312-win32.whl", hash = "sha256:3361cd796898b244e638439e155576a8551b85c15ae1332eaefcd1b8ec447393"}, - {file = "zeroconf-0.146.0-cp312-cp312-win_amd64.whl", hash = "sha256:eac992020f1b0a10fb9facd18e9e65baf4c0dd5a0a9c56f95c8868f5befa61e5"}, - {file = "zeroconf-0.146.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:faec552163f3007247ef9713fc817627d89844a782da8c1479b11ea3d3370684"}, - {file = "zeroconf-0.146.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0fc7b22e33b9d5d81b5aee58af6447fc1cf9b11e04dc2a04e1a5d00b3ae4d23a"}, - {file = "zeroconf-0.146.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6e24daeeb926f8c7d426c46082224786e26aa5b4ce9fb573133e52ff8bae81"}, - {file = "zeroconf-0.146.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:9a798ea22c24a4148364f85b46ab33541072715bf8abccae2e3fd0c069f5808f"}, - {file = "zeroconf-0.146.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97a536e5b3d694e342bc908149342db2aae08a6f56466db63b6dffc26d2399ae"}, - {file = "zeroconf-0.146.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f97a09c01424e2356c41b39f7c2fb7a743623c2d413a082e861030e28090aebb"}, - {file = "zeroconf-0.146.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:55c2a0087847d5c8bc00cc1e85cb1d048e8b70b09b4e949a2b763f33389819bb"}, - {file = "zeroconf-0.146.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b87d01dc8d7d10b929cc63330cf2e0f726f105a57e8d86df5d946b93a0e6280f"}, - {file = "zeroconf-0.146.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f844214eed7b66c1db3ea4ab2dddf0d84b91c340d83b2721656f70efb8588ae4"}, - {file = "zeroconf-0.146.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cf9e85463a4fdeed8c5ea3b13e4a6c6de924d90b8b0982021e7331632f80192e"}, - {file = "zeroconf-0.146.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fc1dd03301d370c21a8c5fbbe0a6a54a068a08384fa673d596c3f2424153aeca"}, - {file = "zeroconf-0.146.0-cp313-cp313-win32.whl", hash = "sha256:b4e70e77a67b3f39e91b5c02df82ab49a54bfc4edb1aa5779e404a711938c5af"}, - {file = "zeroconf-0.146.0-cp313-cp313-win_amd64.whl", hash = "sha256:5274ba298d2edd5d02bb3937181a1e82deef773075b04374eac149bd40fccd96"}, - {file = "zeroconf-0.146.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e90dc0dab0c5731294921f9513d52d490679c09d328cff8bf9903d91dbf1d257"}, - {file = "zeroconf-0.146.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5f66735042567b88d54501120a14c176315068c5138fcbcabe72153156d212e1"}, - {file = "zeroconf-0.146.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96f51b6748b2c9ec60b92dbbf30f5b4c74e6c742a5e294cb8255661ea7f32ef5"}, - {file = "zeroconf-0.146.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:591b4bb2669e4eb440c0fe6499bc8e5e679a674d59fe77e6f3b556f58ddc8fe2"}, - {file = "zeroconf-0.146.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98bcadb66cb57d7c2afe220c61f5a0344fa78003ca38146950dd9ea8ee6649d0"}, - {file = "zeroconf-0.146.0-cp39-cp39-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d151573caa6dfa26b83ca4e88a1907a35a9838ebe4e29917e79d0bf3b255947"}, - {file = "zeroconf-0.146.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc36173cadf0a25e7095d69a69eaf321955ac72d59e29a1f2630ce3ef1c84af2"}, - {file = "zeroconf-0.146.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8eb27f0c0271bcff3d2bb6e269a053777bd8cbe73f6fb3f6ae6a43f8b2db4000"}, - {file = "zeroconf-0.146.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:160ff56eca3a695fdb55e9d9e954b4f750ccb6294dfa8838eba923fd841a3b5e"}, - {file = "zeroconf-0.146.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6ebd4734dc7c14ee4ded96d5ca4064693463118c538c2583fd070b8b406956da"}, - {file = "zeroconf-0.146.0-cp39-cp39-win32.whl", hash = "sha256:8ad8fbb68ae8b03144af1bdd1f4832d5c72b9d9c6e5db5a517f20c9bd4cbd69b"}, - {file = "zeroconf-0.146.0-cp39-cp39-win_amd64.whl", hash = "sha256:f7b4ca975e5ad064ed8dbb19534fbc2182b7babb71e4d7abf30ad63688e91d1f"}, - {file = "zeroconf-0.146.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8f6956c79e22c412306f0d159d3217e4eb2483ea3ed481d44be2bdd07ad8c039"}, - {file = "zeroconf-0.146.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa49921b9ec1cd98144c4b5f7316480022c821dee5aec82ecfeb8eb13ccd9225"}, - {file = "zeroconf-0.146.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b444e41e92c30634066ea445ed129c9efd48302043b58cee10625e59fedd6304"}, - {file = "zeroconf-0.146.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:91c2dad3ba6a5a8d3db7649d0b4cc87ced057da002f40256cba6202a1802630f"}, - {file = "zeroconf-0.146.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c21a1c32f42e164dabb2fa8775be2bc5f1a59c2aa71d4b47820fa961e92a8c"}, - {file = "zeroconf-0.146.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:25fd97a2bde52c700d2586ecc584e03c1211e91a2cbf23f074d90c2e06cfc084"}, - {file = "zeroconf-0.146.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:26588c06cc42062b5414e1a770c233f4a3bcbd324c8247a7f9a761abc7978a6b"}, - {file = "zeroconf-0.146.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:20bef1e28bb8c0ad1e42c07e197786a5237fd66a63390da030f0cebce9ecc6e1"}, - {file = "zeroconf-0.146.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a27d48625d2ccc2cf43a78a7086e633721d6a0b2ede4c32a5ba48a4f0e5a08e"}, - {file = "zeroconf-0.146.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a8f66a5fd32862c94e61f2cb35315270210f137a98d753193f698eb94db0bc37"}, - {file = "zeroconf-0.146.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf699d0504cfce3c7926cab1862392ee646ae58ebcce85c474868d4d50cca68"}, - {file = "zeroconf-0.146.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:afb429917b41ac9d7d4cf5a0ac88e266cc963533069655b8838b62a3d605a5d8"}, - {file = "zeroconf-0.146.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:eea459c7c46196548cc60eab287be8eb55fcaddb56bc2eaf566d1dd809085dac"}, - {file = "zeroconf-0.146.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8232ed02a0a2d67ed211e1ded0a17fa6981ad81b3609d9537342c41b9f049eb1"}, - {file = "zeroconf-0.146.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae690c27a5aa37523e990fed76ffcc736c41fbe3a9c865a7498396a1ba91655a"}, - {file = "zeroconf-0.146.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:bfb729e9d940d118b75bc1ed41624960942ac72c242a35c1795dfa819aae690c"}, - {file = "zeroconf-0.146.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1d34ef4c93d352f57dba89785a2524bb738c8d07b0a0ed585bb3bc234489336"}, - {file = "zeroconf-0.146.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2aec447536391c305c8afba84d912ebcc2b60bb90d1f210c007e764207853105"}, - {file = "zeroconf-0.146.0.tar.gz", hash = "sha256:a48010a1931acdba5b26e99326464788daeef96dcb7b9a44d1832352f76da49c"}, + {file = "zeroconf-0.147.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:de0e1439c90df08fbb59d07445904aa9cb0ed3c548bb2f89a8a7bb3fa50071cd"}, + {file = "zeroconf-0.147.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2b8776e5e3ba7f19578a6baffa231f148390156a231eb17924c30e192ec9b00"}, + {file = "zeroconf-0.147.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a80cf348e8a1c597a427b500cf5327adf1a1402b010c84ba78b39ea7d3d7598"}, + {file = "zeroconf-0.147.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:8014da8e9d1efa04df8091c60bc8e23a25d6374b2f99f2ba515ca8d7d6d9b271"}, + {file = "zeroconf-0.147.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a6c359af0ff3ac50812c9bdbeb006279bb4c401d721f1f22651522f73237295"}, + {file = "zeroconf-0.147.0-cp310-cp310-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d6e3d598bff4c07b61e7be89a56aa75ef3e2e2a6622881b76a0d06ef527fc39"}, + {file = "zeroconf-0.147.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ecb83e1b27eb8a9f14bc5458b4f87594d24d5f206dbaefae93021a702a311905"}, + {file = "zeroconf-0.147.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f8cb0b47eb18f2340505f5106adc2dc698a131785c6e0e6ca56f9f5c09ef6469"}, + {file = "zeroconf-0.147.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7204d4d41ef95021acc3ff7a7d3266558ea2032a167a3591c4fb570cc64b522c"}, + {file = "zeroconf-0.147.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a37e54a991e9e7203650f7884a44097616bed9c050f19db50316abda409ab208"}, + {file = "zeroconf-0.147.0-cp310-cp310-win32.whl", hash = "sha256:df1dfdf49fcff8bacc7d490eeafeb3d74aea5588f78a459b76994b7acf3fe513"}, + {file = "zeroconf-0.147.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f0d3c119e77ec960d03ad5b92e651e5cc8c49d5521cbd58a561f8db709c79cc"}, + {file = "zeroconf-0.147.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f36096616f89f3aec678613316014e3a35e293c3c2e26466695d91688c49a34"}, + {file = "zeroconf-0.147.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:abb3f45ce14fdbcf70d2cb711714553e20e704cc2d86988125936d853f01c132"}, + {file = "zeroconf-0.147.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f511b32c1693f5f76acea9ce7add629ed62071f001929d818bea09aaa2c2969"}, + {file = "zeroconf-0.147.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:6269129298004531b0b809a32bfe82865e8641f7940647c33a0b9c9e36012187"}, + {file = "zeroconf-0.147.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed2b6369a50e4a27667a6c80011ff276d63d205f8ccf5771f9fceddb0c9ce6b4"}, + {file = "zeroconf-0.147.0-cp311-cp311-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:02205731db993193034b0f5cc5108e2cf2c580e445ff401be05ea80aeb762c7c"}, + {file = "zeroconf-0.147.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5bd0984a2f457d399e414622941cce30bb52bd9bcbfc0594a266ed724a030469"}, + {file = "zeroconf-0.147.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e4a1ccbbbeb3c5e1867f38aee18647245069ca01572f6e9188d549f294f2ac77"}, + {file = "zeroconf-0.147.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9f2b7f930407403f9813525537a78613510d9c394a11328cafb8bb46f060d89e"}, + {file = "zeroconf-0.147.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7b6ee515a76bb983b26590eda099d57fede043f3b753427ff9dc4e1c7405395"}, + {file = "zeroconf-0.147.0-cp311-cp311-win32.whl", hash = "sha256:3dec7640d85362d70a2e4c89e34e0c865f41c00073378597afdac0a2e146b061"}, + {file = "zeroconf-0.147.0-cp311-cp311-win_amd64.whl", hash = "sha256:5c8962eb8c829fd22bbda2ec23443e6e14e6f44adf2a823da0f074a941d8b8e7"}, + {file = "zeroconf-0.147.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89542174ec4f1e86ba428cab19a33c77378dcac0ee37577df8859af849cf736e"}, + {file = "zeroconf-0.147.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0086b8c280fc3410fa887a0da68cc6dc5a7d1da8a57157f6c7e4acb029674ce9"}, + {file = "zeroconf-0.147.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04018f48c38fa174af8e2c6cd00e6fb8a9a7269a187ba1f52cf32c14f2ddd941"}, + {file = "zeroconf-0.147.0-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:71a5690ad94a8b5809bb3888e3c30de943458b9fb751730fa9a60e580d1b47ca"}, + {file = "zeroconf-0.147.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34b5f1f472eadd090232af6b52c16c417359d9541e7bb31afbde3a0e33e55594"}, + {file = "zeroconf-0.147.0-cp312-cp312-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:213b9ebdb5876d7b30515e2850d250625ac1a5c54b022a0fb407ea25af39251f"}, + {file = "zeroconf-0.147.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:10e75e41160f376b7b43a242ffeee5803878fd31d30991eb60cd1d0949373d51"}, + {file = "zeroconf-0.147.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d7b488d1a74bac55080a9cadb6b8690f0aefa89ae8130485557bc53ba866d445"}, + {file = "zeroconf-0.147.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a3f6d9c6c226a7fd6669584dfcb8160a60b8711f00229a8d7347451447b220e2"}, + {file = "zeroconf-0.147.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:137d83815347e0ede605f9d7a0d5253f95d62a9872f291a123679c4a01e016bb"}, + {file = "zeroconf-0.147.0-cp312-cp312-win32.whl", hash = "sha256:1ae71afd284f07d9a46acf69674efef283c039f5e326250c29578e0605f7dac6"}, + {file = "zeroconf-0.147.0-cp312-cp312-win_amd64.whl", hash = "sha256:e66b2044a626f20bc4ddab92de662b4f4bce8e4f1e85672d88186c9e776505a1"}, + {file = "zeroconf-0.147.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1deedbedea7402754b3a1a05a2a1c881443451ccd600b2a7f979e97dd9fcbe6d"}, + {file = "zeroconf-0.147.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5c57d551e65a2a9b6333b685e3b074601f6e85762e4b4a490c663f1f2e215b24"}, + {file = "zeroconf-0.147.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:095bdb0cd369355ff919e3be930991b38557baaa8292d82f4a4a8567a3944f05"}, + {file = "zeroconf-0.147.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:8ae0fe0bb947b3a128af586c76a16b5a7d027daa65e67637b042c745f9b136c4"}, + {file = "zeroconf-0.147.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cbeea4d8d0c4f6eb5a82099d53f5729b628685039a44c1a84422080f8ec5b0d"}, + {file = "zeroconf-0.147.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:728f82417800c5c5dd3298f65cf7a8fef1707123b457d3832dbdf17d38f68840"}, + {file = "zeroconf-0.147.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:a2dc9ae96cd49b50d651a78204aafe9f41e907122dc98e719be5376b4dddec6f"}, + {file = "zeroconf-0.147.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9570ab3203cc4bd3ad023737ef4339558cdf1f33a5d45d76ed3fe77e5fa5f57"}, + {file = "zeroconf-0.147.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:fd783d9bac258e79d07e2bd164c1962b8f248579392b5078fd607e7bb6760b53"}, + {file = "zeroconf-0.147.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b4acc76063cc379774db407dce0263616518bb5135057eb5eeafc447b3c05a81"}, + {file = "zeroconf-0.147.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:acc5334cb6cb98db3917bf9a3d6b6b7fdd205f8a74fd6f4b885abb4f61098857"}, + {file = "zeroconf-0.147.0-cp313-cp313-win32.whl", hash = "sha256:7c52c523aa756e67bf18d46db298a5964291f7d868b4a970163432e7d745b992"}, + {file = "zeroconf-0.147.0-cp313-cp313-win_amd64.whl", hash = "sha256:60f623af0e45fba69f5fe80d7b300c913afe7928fb43f4b9757f0f76f80f0d82"}, + {file = "zeroconf-0.147.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a5b570c0697144876bf54ff9d87dc46f5f7c8b2709702b7182b99b363e37e301"}, + {file = "zeroconf-0.147.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12a24145231b26d1e6d7ded60984f8f32e2b17fe4f9a824be26b7622b875bc12"}, + {file = "zeroconf-0.147.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf73a1a202a02f2e4810eb582f054104bff1a29a550ce0819c5fc6dfafe50f94"}, + {file = "zeroconf-0.147.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:aa55888411404cc7ff1c6822ace733680172a02931eb20561afda94d06342c4f"}, + {file = "zeroconf-0.147.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5291a5f26d961cfc0cd22905187a0627d07913e566783191f97a5a49dec9fc32"}, + {file = "zeroconf-0.147.0-cp39-cp39-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:930b434ee3471430f3938f129979926a13c5ee1802ad6fb51383314f7193d33d"}, + {file = "zeroconf-0.147.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4add353da94e067fd3a4fdb47e9be64bd451bc7bc2234d74775514bde5d8096c"}, + {file = "zeroconf-0.147.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8c0a1c69ef9ff5aab6acdf33b892a45d5ca2f96af11fd53891a43ec816ab6c25"}, + {file = "zeroconf-0.147.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:743fff2187da3d9501606555b1cf27699c24c36b9f1a6f02c168033034c5c22e"}, + {file = "zeroconf-0.147.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9a629b63f8f80a32121c4832264c23fbc6cec4e15200d4fd8e715257c06d84b1"}, + {file = "zeroconf-0.147.0-cp39-cp39-win32.whl", hash = "sha256:600b2a2453e7877b45c55d0c011e24f9eb7b75d71eee8a302e9b8b55e878b62b"}, + {file = "zeroconf-0.147.0-cp39-cp39-win_amd64.whl", hash = "sha256:34d40e09a7e4aff294ce086a63c5133c4d683b0165054af07c15035af1718829"}, + {file = "zeroconf-0.147.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8a2ceada07a6e89d7000e19826598a2fe013192e7a752637c1232cbc6041f434"}, + {file = "zeroconf-0.147.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:60b548b8b58f4f7435f96e4a8bed0ffedc6023ebd9e30872d3e71e3f5d8bd8e3"}, + {file = "zeroconf-0.147.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7edafeb07c88398d6c2f01ce6810c566199d5d50c9da7ac93e9f0da1d34b7c8"}, + {file = "zeroconf-0.147.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b39f83ff516ad764bda67ad242ef85481d1653d85bd4bc98cc62070bb086789c"}, + {file = "zeroconf-0.147.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abe4c6da969c64419e30ca83368475d97ae57421edb2ec86e5c2baa8f659bad5"}, + {file = "zeroconf-0.147.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8ec79d8693874f0dda108be48f56bdd343ddb9a469d629a796f853ba0865f07e"}, + {file = "zeroconf-0.147.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b89c62ea0220235da8b353958ea8340d62ed820dca34be0ff08146674a93168b"}, + {file = "zeroconf-0.147.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4fd6848de32756ec34531ea9b3cf1988c9115b7d8363687d3ffaa2cdba244d4"}, + {file = "zeroconf-0.147.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0f51b5e363c137291a56688898fe284c5f99f52b7f8a1528ebe9d81e8daeecf"}, + {file = "zeroconf-0.147.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:de84c8e09a49009ff44fb1146bfd2380545cde2a9f5ebfa7038afc578b187b2a"}, + {file = "zeroconf-0.147.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81ea55950ace20a93ce1ef684b111498cb212e06cc190a311a572d42a49809fc"}, + {file = "zeroconf-0.147.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f0e1e1abe27ab81bbaaac2e4d94f9e817e64128ab03ba5909462d1f4cc560bc5"}, + {file = "zeroconf-0.147.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6883f1b39ef1fea628e1ad027c4e5ed5058582d1453ea0f8dee5f7afd421b228"}, + {file = "zeroconf-0.147.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0c1157a7500145224b2606ca1efe393afa9879133acf40b1b428dfa5503581a"}, + {file = "zeroconf-0.147.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f815a2202a4fdc66bd6cf81e4cd55657fb903b5f748455f6b9ca1702fb7d559"}, + {file = "zeroconf-0.147.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:5f139fcf33fa166779b959185c46feae5c82dc86b09a8ee77484d1bd4155a87f"}, + {file = "zeroconf-0.147.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:536f5f07d2f2d5c872dc6acc8e8a560254c2a5874eba45165dc5deb14a49cc19"}, + {file = "zeroconf-0.147.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:760d9b318e6ba311054348719f3e9ea33f678afbbf9e9585d7993638bba12220"}, + {file = "zeroconf-0.147.0.tar.gz", hash = "sha256:f517375de6bf2041df826130da41dc7a3e8772176d3076a5da58854c7d2e8d7a"}, ] [package.dependencies] @@ -4056,5 +3937,5 @@ ifaddr = ">=0.1.7" [metadata] lock-version = "2.1" -python-versions = ">=3.13,<3.14" -content-hash = "0f20d66928107e07c91618b279c0ad933c380d2e5265e722c8c5d7c63c1b5652" +python-versions = ">=3.13.2,<3.14" +content-hash = "30503a59bb012df7290e80b58beaabd3cade6046a70f3d3087088d2a33d12e30" diff --git a/pyproject.toml b/pyproject.toml index 1deeacb20..d228027b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ version = "0.0.0" [tool.poetry.dependencies] homeassistant = "2025.7.0" -python = ">=3.13,<3.14" +python = ">=3.13.2,<3.14" [tool.poetry.group.dev.dependencies] pre-commit = "4.2.0" From dba4e829904e50a28b46d9e159c3868ae72eddae Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 27 Jul 2025 09:51:26 +0000 Subject: [PATCH 005/235] Change to hub integration type --- custom_components/battery_notes/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/manifest.json b/custom_components/battery_notes/manifest.json index 5092f9959..8e8e3da36 100644 --- a/custom_components/battery_notes/manifest.json +++ b/custom_components/battery_notes/manifest.json @@ -6,7 +6,7 @@ ], "config_flow": true, "documentation": "https://andrew-codechimp.github.io/HA-Battery-Notes/", - "integration_type": "device", + "integration_type": "hub", "iot_class": "calculated", "issue_tracker": "https://github.com/andrew-codechimp/ha-battery-notes/issues", "version": "2.0.0-dev" From f9e9460567b9b40e17fbe96b3df505e0121ac18f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 31 Jul 2025 09:26:29 +0000 Subject: [PATCH 006/235] WIP --- .../battery_notes/config_flow.py | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 40e5c71cb..59dd28b64 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -14,6 +14,8 @@ from homeassistant.config_entries import ( ConfigEntry, ConfigFlowResult, + ConfigSubentry, + ConfigSubentryData, ConfigSubentryFlow, OptionsFlow, SubentryFlowResult, @@ -147,6 +149,7 @@ async def async_step_integration_discovery( "model_id": discovery_info[CONF_MODEL_ID], } + return await self.async_step_device(discovery_info) async def async_step_user( @@ -391,10 +394,34 @@ async def async_step_battery( assert device_entry title = device_entry.name_by_user or device_entry.name - return self.async_create_entry( - title=str(title), - data=self.data, - ) + # return self.async_create_entry( + # title=str(title), + # data=self.data, + # ) + + + config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] + # Create a subentry + subentry = ConfigSubentry() + await self.hass.config_entries.async_add_subentry(config_entry, subentry) + + + # config_flow_result: ConfigFlowResult = await self.async_step_user( + # discovered_data + # ) + + # subentries: list[ConfigSubentryData] = [] + + # subentry: ConfigSubentryData = ConfigSubentryData( + # data={CONF_CHAT_ID: chat_id}, + # subentry_type=CONF_ALLOWED_CHAT_IDS, + # title=f"{chat_name} ({chat_id})", + # unique_id=str(chat_id), + # ) + # subentries.append(subentry) + + + return self.async_abort(reason="created_sub_entry") return self.async_show_form( step_id="battery", From 437552fbb64e3fb6448302d14104217c4f608556 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 31 Jul 2025 14:34:55 +0000 Subject: [PATCH 007/235] Start of new config flow --- .../battery_notes/config_flow.py | 258 +++++++++++++++++- custom_components/battery_notes/manifest.json | 4 +- 2 files changed, 257 insertions(+), 5 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 59dd28b64..26b9b7686 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -43,6 +43,7 @@ CONF_SOURCE_ENTITY_ID, DOMAIN, ) +from .const import NAME as APP_NAME from .coordinator import MY_KEY from .library import Library, ModelInfo from .library_updater import LibraryUpdater @@ -159,7 +160,20 @@ async def async_step_user( # pylint: disable=unused-argument """Handle a flow initialized by the user.""" - return self.async_show_menu(step_id="user", menu_options=["device", "entity"]) + return self.async_create_entry( + title=APP_NAME, + data={}, + options={}, + ) + + # async def async_step_user( + # self, + # user_input: dict | None = None, + # ) -> ConfigFlowResult: + # # pylint: disable=unused-argument + # """Handle a flow initialized by the user.""" + + # return self.async_show_menu(step_id="user", menu_options=["device", "entity"]) async def async_step_device( self, @@ -475,7 +489,8 @@ async def async_step_battery( class BatteryNotesSubentryFlowHandler(ConfigSubentryFlow): """Flow for managing Battery Notes subentries.""" - options: dict[str, Any] + data: dict[str, Any] + model_info: ModelInfo | None = None @property def _is_new(self) -> bool: @@ -487,8 +502,245 @@ async def async_step_user( ) -> SubentryFlowResult: """Add a subentry.""" - return await self.async_step_init() + return self.async_show_menu(step_id="user", menu_options=["device", "entity"]) + + async def async_step_device( + self, + user_input: dict | None = None, + ) -> ConfigFlowResult: + """Handle a flow for a device or discovery.""" + errors: dict[str, str] = {} + device_battery_details = None + + if user_input is not None: + self.data = user_input + + device_id = user_input[CONF_DEVICE_ID] + + library_updater = LibraryUpdater(self.hass) + if await library_updater.time_to_update_library(1): + await library_updater.get_library_updates() + + device_registry = dr.async_get(self.hass) + device_entry = device_registry.async_get(device_id) + + if device_entry and device_entry.manufacturer and device_entry.model: + _LOGGER.debug( + "Looking up device %s %s %s %s", + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry) or "", + device_entry.hw_version, + ) + + self.model_info = ModelInfo( + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry), + device_entry.hw_version, + ) + + library = Library(self.hass) + await library.load_libraries() + + # Set defaults if not found in library + self.data[CONF_BATTERY_QUANTITY] = 1 + + device_battery_details = await library.get_device_battery_details( + self.model_info + ) + + if device_battery_details and not device_battery_details.is_manual: + _LOGGER.debug( + "Found device %s %s %s %s", + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry) or "", + device_entry.hw_version, + ) + self.data[CONF_BATTERY_TYPE] = device_battery_details.battery_type + + self.data[CONF_BATTERY_QUANTITY] = ( + device_battery_details.battery_quantity + ) + + if device_battery_details and device_battery_details.is_manual: + return await self.async_step_manual() + + return await self.async_step_battery() + + schema = DEVICE_SCHEMA + # If show_all_devices = is specified and true, don't filter + domain_config = self.hass.data.get(MY_KEY) + if domain_config and domain_config.show_all_devices: + schema = DEVICE_SCHEMA_ALL + + return self.async_show_form( + step_id="device", + data_schema=schema, + errors=errors, + last_step=False, + ) + + async def async_step_entity( + self, + user_input: dict | None = None, + ) -> ConfigFlowResult: + """Handle a flow for a device or discovery.""" + errors: dict[str, str] = {} + device_battery_details = None + + if user_input is not None: + self.data = user_input + + source_entity_id = user_input[CONF_SOURCE_ENTITY_ID] + self.data[CONF_SOURCE_ENTITY_ID] = source_entity_id + entity_registry = er.async_get(self.hass) + entity_entry = entity_registry.async_get(source_entity_id) + + # Default battery quantity if not found in library lookup + self.data[CONF_BATTERY_QUANTITY] = 1 + + if entity_entry: + if entity_entry.device_id: + self.data[CONF_DEVICE_ID] = entity_entry.device_id + + library_updater = LibraryUpdater(self.hass) + if await library_updater.time_to_update_library(1): + await library_updater.get_library_updates() + + device_registry = dr.async_get(self.hass) + device_entry = device_registry.async_get(entity_entry.device_id) + + if ( + device_entry + and device_entry.manufacturer + and device_entry.model + ): + _LOGGER.debug( + "Looking up device %s %s %s %s", + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry) or "", + device_entry.hw_version, + ) + + self.model_info = ModelInfo( + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry), + device_entry.hw_version, + ) + + library = Library(self.hass) + await library.load_libraries() + + device_battery_details = ( + await library.get_device_battery_details(self.model_info) + ) + + if ( + device_battery_details + and not device_battery_details.is_manual + ): + _LOGGER.debug( + "Found device %s %s %s %s", + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry) or "", + device_entry.hw_version, + ) + self.data[CONF_BATTERY_TYPE] = ( + device_battery_details.battery_type + ) + + self.data[CONF_BATTERY_QUANTITY] = ( + device_battery_details.battery_quantity + ) + + if device_battery_details and device_battery_details.is_manual: + return await self.async_step_manual() + return await self.async_step_battery() + else: + # No entity_registry entry, must be a config.yaml entity which we can't support + errors["base"] = "unconfigurable_entity" + + schema = ENTITY_SCHEMA_ALL + + return self.async_show_form( + step_id="entity", + data_schema=schema, + errors=errors, + last_step=False, + ) + + async def async_step_manual(self, user_input: dict[str, Any] | None = None): + """Second step in config flow to add the battery type.""" + errors: dict[str, str] = {} + if user_input is not None: + return await self.async_step_battery() + + return self.async_show_form( + step_id="manual", + data_schema=None, + last_step=False, + errors=errors, + ) + + async def async_step_battery( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Second step in config flow to add the battery type.""" + errors: dict[str, str] = {} + if user_input is not None: + self.data[CONF_BATTERY_TYPE] = user_input[CONF_BATTERY_TYPE] + self.data[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) + self.data[CONF_BATTERY_LOW_THRESHOLD] = int( + user_input[CONF_BATTERY_LOW_THRESHOLD] + ) + self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input.get( + CONF_BATTERY_LOW_TEMPLATE, None + ) + self.data[CONF_FILTER_OUTLIERS] = user_input.get(CONF_FILTER_OUTLIERS, False) + + source_entity_id = self.data.get(CONF_SOURCE_ENTITY_ID, None) + device_id = self.data.get(CONF_DEVICE_ID, None) + + entity_entry = None + device_entry = None + + if source_entity_id: + entity_registry = er.async_get(self.hass) + entity_entry = entity_registry.async_get(source_entity_id) + source_entity_domain, source_object_id = split_entity_id( + source_entity_id + ) + if entity_entry: + entity_unique_id = entity_entry.unique_id or entity_entry.entity_id + else: + entity_unique_id = source_object_id + unique_id = f"bn_{entity_unique_id}" + else: + device_registry = dr.async_get(self.hass) + assert device_id + device_entry = device_registry.async_get(device_id) + unique_id = f"bn_{device_id}" + + await self.async_set_unique_id(unique_id) + self._abort_if_unique_id_configured() + if CONF_NAME in self.data: + title = self.data.get(CONF_NAME) + elif source_entity_id and entity_entry: + title = entity_entry.name or entity_entry.original_name + else: + assert device_entry + title = device_entry.name_by_user or device_entry.name + + return self.async_create_entry( + title=str(title), + data=self.data, + ) class OptionsFlowHandler(OptionsFlow): """Handle an option flow for BatteryNotes.""" diff --git a/custom_components/battery_notes/manifest.json b/custom_components/battery_notes/manifest.json index 8e8e3da36..10ebc1fb1 100644 --- a/custom_components/battery_notes/manifest.json +++ b/custom_components/battery_notes/manifest.json @@ -6,8 +6,8 @@ ], "config_flow": true, "documentation": "https://andrew-codechimp.github.io/HA-Battery-Notes/", - "integration_type": "hub", + "integration_type": "service", "iot_class": "calculated", "issue_tracker": "https://github.com/andrew-codechimp/ha-battery-notes/issues", - "version": "2.0.0-dev" + "version": "3.0.0-dev" } \ No newline at end of file From 5129ee1ff048afb31500d6b1ef5365d49c6d197a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 31 Jul 2025 14:54:42 +0000 Subject: [PATCH 008/235] Refactor BatteryNotes integration to handle subentries and remove unused config flow steps --- custom_components/battery_notes/__init__.py | 7 +- .../battery_notes/config_flow.py | 127 +----------------- 2 files changed, 6 insertions(+), 128 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index bfa090f1f..3d8e4de09 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -160,8 +160,11 @@ async def async_setup_entry( store=data.store, ) - coordinator = BatteryNotesCoordinator(hass, config_entry) - config_entry.runtime_data.coordinator = coordinator + for subentry in config_entry.subentries.values(): + if subentry.subentry_type == "battery_note": + #TODO: Change coordinator to take subentry data + coordinator = BatteryNotesCoordinator(hass, config_entry) + config_entry.runtime_data.coordinator = coordinator await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 26b9b7686..93c556f52 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -166,15 +166,6 @@ async def async_step_user( options={}, ) - # async def async_step_user( - # self, - # user_input: dict | None = None, - # ) -> ConfigFlowResult: - # # pylint: disable=unused-argument - # """Handle a flow initialized by the user.""" - - # return self.async_show_menu(step_id="user", menu_options=["device", "entity"]) - async def async_step_device( self, user_input: dict | None = None, @@ -253,111 +244,6 @@ async def async_step_device( last_step=False, ) - async def async_step_entity( - self, - user_input: dict | None = None, - ) -> ConfigFlowResult: - """Handle a flow for a device or discovery.""" - errors: dict[str, str] = {} - device_battery_details = None - - if user_input is not None: - self.data = user_input - - source_entity_id = user_input[CONF_SOURCE_ENTITY_ID] - self.data[CONF_SOURCE_ENTITY_ID] = source_entity_id - entity_registry = er.async_get(self.hass) - entity_entry = entity_registry.async_get(source_entity_id) - - # Default battery quantity if not found in library lookup - self.data[CONF_BATTERY_QUANTITY] = 1 - - if entity_entry: - if entity_entry.device_id: - self.data[CONF_DEVICE_ID] = entity_entry.device_id - - library_updater = LibraryUpdater(self.hass) - if await library_updater.time_to_update_library(1): - await library_updater.get_library_updates() - - device_registry = dr.async_get(self.hass) - device_entry = device_registry.async_get(entity_entry.device_id) - - if ( - device_entry - and device_entry.manufacturer - and device_entry.model - ): - _LOGGER.debug( - "Looking up device %s %s %s %s", - device_entry.manufacturer, - device_entry.model, - get_device_model_id(device_entry) or "", - device_entry.hw_version, - ) - - self.model_info = ModelInfo( - device_entry.manufacturer, - device_entry.model, - get_device_model_id(device_entry), - device_entry.hw_version, - ) - - library = Library(self.hass) - await library.load_libraries() - - device_battery_details = ( - await library.get_device_battery_details(self.model_info) - ) - - if ( - device_battery_details - and not device_battery_details.is_manual - ): - _LOGGER.debug( - "Found device %s %s %s %s", - device_entry.manufacturer, - device_entry.model, - get_device_model_id(device_entry) or "", - device_entry.hw_version, - ) - self.data[CONF_BATTERY_TYPE] = ( - device_battery_details.battery_type - ) - - self.data[CONF_BATTERY_QUANTITY] = ( - device_battery_details.battery_quantity - ) - - if device_battery_details and device_battery_details.is_manual: - return await self.async_step_manual() - return await self.async_step_battery() - else: - # No entity_registry entry, must be a config.yaml entity which we can't support - errors["base"] = "unconfigurable_entity" - - schema = ENTITY_SCHEMA_ALL - - return self.async_show_form( - step_id="entity", - data_schema=schema, - errors=errors, - last_step=False, - ) - - async def async_step_manual(self, user_input: dict[str, Any] | None = None): - """Second step in config flow to add the battery type.""" - errors: dict[str, str] = {} - if user_input is not None: - return await self.async_step_battery() - - return self.async_show_form( - step_id="manual", - data_schema=None, - last_step=False, - errors=errors, - ) - async def async_step_battery( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: @@ -416,7 +302,7 @@ async def async_step_battery( config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] # Create a subentry - subentry = ConfigSubentry() + subentry = ConfigSubentry(subentry_type="battery_note", data=self.data, title=str(title), unique_id=unique_id) await self.hass.config_entries.async_add_subentry(config_entry, subentry) @@ -424,17 +310,6 @@ async def async_step_battery( # discovered_data # ) - # subentries: list[ConfigSubentryData] = [] - - # subentry: ConfigSubentryData = ConfigSubentryData( - # data={CONF_CHAT_ID: chat_id}, - # subentry_type=CONF_ALLOWED_CHAT_IDS, - # title=f"{chat_name} ({chat_id})", - # unique_id=str(chat_id), - # ) - # subentries.append(subentry) - - return self.async_abort(reason="created_sub_entry") return self.async_show_form( From 7348066e09a0b2771636960620bce782a1541937 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 11:09:00 +0000 Subject: [PATCH 009/235] Main options flow --- custom_components/battery_notes/__init__.py | 20 +- .../battery_notes/config_flow.py | 294 ++++++++++++++---- .../battery_notes/translations/en.json | 39 +++ 3 files changed, 279 insertions(+), 74 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 3d8e4de09..822399336 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -136,11 +136,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: await library_updater.copy_schema() await library_updater.get_library_updates(startup=True) - if domain_config.enable_autodiscovery: - discovery_manager = DiscoveryManager(hass, domain_config) - await discovery_manager.start_discovery() - else: - _LOGGER.debug("Auto discovery disabled") + # if domain_config.enable_autodiscovery: + # discovery_manager = DiscoveryManager(hass, domain_config) + # await discovery_manager.start_discovery() + # else: + # _LOGGER.debug("Auto discovery disabled") # Register custom services async_setup_services(hass) @@ -160,11 +160,11 @@ async def async_setup_entry( store=data.store, ) - for subentry in config_entry.subentries.values(): - if subentry.subentry_type == "battery_note": - #TODO: Change coordinator to take subentry data - coordinator = BatteryNotesCoordinator(hass, config_entry) - config_entry.runtime_data.coordinator = coordinator + # for subentry in config_entry.subentries.values(): + # if subentry.subentry_type == "battery_note": + # #TODO: Change coordinator to take subentry data + # coordinator = BatteryNotesCoordinator(hass, config_entry) + # config_entry.runtime_data.coordinator = coordinator await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 93c556f52..1bb350bc9 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -26,21 +26,37 @@ Platform, ) from homeassistant.core import callback, split_entity_id +from homeassistant.data_entry_flow import AbortFlow, section from homeassistant.helpers import selector +from homeassistant.helpers.selector import ( + SelectSelector, + SelectSelectorConfig, + TextSelector, + TextSelectorConfig, + TextSelectorType, +) from homeassistant.helpers.typing import DiscoveryInfoType from .common import get_device_model_id from .const import ( + CONF_BATTERY_INCREASE_THRESHOLD, CONF_BATTERY_LOW_TEMPLATE, CONF_BATTERY_LOW_THRESHOLD, CONF_BATTERY_QUANTITY, CONF_BATTERY_TYPE, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD, CONF_DEVICE_NAME, + CONF_ENABLE_AUTODISCOVERY, + CONF_ENABLE_REPLACED, CONF_FILTER_OUTLIERS, + CONF_HIDE_BATTERY, CONF_MANUFACTURER, CONF_MODEL, CONF_MODEL_ID, + CONF_ROUND_BATTERY, + CONF_SHOW_ALL_DEVICES, CONF_SOURCE_ENTITY_ID, + CONF_USER_LIBRARY, DOMAIN, ) from .const import NAME as APP_NAME @@ -160,12 +176,22 @@ async def async_step_user( # pylint: disable=unused-argument """Handle a flow initialized by the user.""" - return self.async_create_entry( - title=APP_NAME, - data={}, - options={}, + if self._async_current_entries(): + return self.async_abort(reason="already_configured") + + if user_input is not None: + return self.async_create_entry( + title=APP_NAME, + data={}, + options={}, + ) + + self._set_confirm_only() + return self.async_show_form( + step_id="user", ) + async def async_step_device( self, user_input: dict | None = None, @@ -617,20 +643,184 @@ async def async_step_battery( data=self.data, ) +#TODO: Change this to be sub entry options flow +# class OptionsFlowHandler(OptionsFlow): +# """Handle an option flow for BatteryNotes.""" + +# model_info: ModelInfo | None = None + +# def __init__(self) -> None: +# """Initialize options flow.""" +# self.current_config: dict +# self.source_device_id: str +# self.name: str +# self.battery_type: str +# self.battery_quantity: int +# self.battery_low_template: str +# self.filter_outliers: bool + +# async def async_step_init( +# self, +# user_input: dict[str, Any] | None = None, +# ) -> ConfigFlowResult: +# """Handle options flow.""" +# errors = {} +# self.current_config = dict(self.config_entry.data) +# self.source_device_id = self.current_config.get(CONF_DEVICE_ID) # type: ignore +# self.name = str(self.current_config.get(CONF_NAME) or "") +# self.battery_type = str(self.current_config.get(CONF_BATTERY_TYPE) or "") +# self.battery_quantity = int(self.current_config.get(CONF_BATTERY_QUANTITY) or 1) +# self.battery_low_template = str( +# self.current_config.get(CONF_BATTERY_LOW_TEMPLATE) or "" +# ) +# self.filter_outliers = bool( +# self.current_config.get(CONF_FILTER_OUTLIERS) or False +# ) + +# if self.source_device_id: +# device_registry = dr.async_get(self.hass) +# device_entry = device_registry.async_get(self.source_device_id) + +# if not device_entry: +# errors["base"] = "orphaned_battery_note" +# else: +# if device_entry and device_entry.manufacturer and device_entry.model: +# _LOGGER.debug( +# "Looking up device %s %s %s %s", +# device_entry.manufacturer, +# device_entry.model, +# get_device_model_id(device_entry) or "", +# device_entry.hw_version, +# ) + +# self.model_info = ModelInfo( +# device_entry.manufacturer, +# device_entry.model, +# get_device_model_id(device_entry), +# device_entry.hw_version, +# ) + +# schema = self.build_options_schema() +# if user_input is not None: +# user_input[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) +# user_input[CONF_BATTERY_LOW_THRESHOLD] = int( +# user_input[CONF_BATTERY_LOW_THRESHOLD] +# ) +# # user_input[CONF_BATTERY_LOW_TEMPLATE] = user_input.get(CONF_BATTERY_LOW_TEMPLATE, None) +# errors = await self.save_options(user_input, schema) +# if not errors: +# return self.async_create_entry(title="", data={}) + +# return self.async_show_form( +# step_id="init", +# description_placeholders={ +# "manufacturer": self.model_info.manufacturer if self.model_info else "", +# "model": self.model_info.model if self.model_info else "", +# "model_id": ( +# str(self.model_info.model_id or "") if self.model_info else "" +# ), +# "hw_version": ( +# str(self.model_info.hw_version or "") if self.model_info else "" +# ), +# }, +# data_schema=schema, +# errors=errors, +# ) + +# async def save_options( +# self, +# user_input: dict[str, Any], +# schema: vol.Schema, +# ) -> dict: +# """Save options, and return errors when validation fails.""" +# errors = {} + +# device_registry = dr.async_get(self.hass) +# device_entry = device_registry.async_get( +# str(self.config_entry.data.get(CONF_DEVICE_ID)) +# ) + +# source_entity_id = self.config_entry.data.get(CONF_SOURCE_ENTITY_ID, None) + +# entity_entry: er.RegistryEntry | None = None +# if source_entity_id: +# entity_registry = er.async_get(self.hass) +# entity_entry = entity_registry.async_get(source_entity_id) +# if not entity_entry: +# errors["base"] = "orphaned_battery_note" +# return errors +# else: +# if not device_entry: +# errors["base"] = "orphaned_battery_note" +# return errors + +# title: Any = "" +# if CONF_NAME in user_input: +# title = user_input.get(CONF_NAME) +# elif source_entity_id and entity_entry: +# title = entity_entry.name or entity_entry.original_name +# elif device_entry: +# title = device_entry.name_by_user or device_entry.name + +# self._process_user_input(user_input, schema) +# self.hass.config_entries.async_update_entry( +# self.config_entry, +# title=title, +# data=self.current_config, +# ) +# return {} + +# def _process_user_input( +# self, +# user_input: dict[str, Any], +# schema: vol.Schema, +# ) -> None: +# """Process the provided user input against the schema.""" +# for key in schema.schema: +# if isinstance(key, vol.Marker): +# key = key.schema +# if key in user_input: +# self.current_config[key] = user_input.get(key) +# elif key in self.current_config: +# self.current_config.pop(key) + +# def build_options_schema(self) -> vol.Schema: +# """Build the options schema.""" +# data_schema = vol.Schema( +# { +# vol.Optional(CONF_NAME): selector.TextSelector( +# selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), +# ), +# vol.Required(CONF_BATTERY_TYPE): selector.TextSelector( +# selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), +# ), +# vol.Required(CONF_BATTERY_QUANTITY): selector.NumberSelector( +# selector.NumberSelectorConfig( +# min=1, max=100, mode=selector.NumberSelectorMode.BOX +# ), +# ), +# vol.Required(CONF_BATTERY_LOW_THRESHOLD): selector.NumberSelector( +# selector.NumberSelectorConfig( +# min=0, max=99, mode=selector.NumberSelectorMode.BOX +# ), +# ), +# vol.Optional(CONF_BATTERY_LOW_TEMPLATE): selector.TemplateSelector(), +# vol.Optional(CONF_FILTER_OUTLIERS): selector.BooleanSelector(), +# } +# ) + +# return _fill_schema_defaults( +# data_schema, +# self.current_config, +# ) + class OptionsFlowHandler(OptionsFlow): """Handle an option flow for BatteryNotes.""" - model_info: ModelInfo | None = None - def __init__(self) -> None: """Initialize options flow.""" self.current_config: dict - self.source_device_id: str self.name: str - self.battery_type: str - self.battery_quantity: int - self.battery_low_template: str - self.filter_outliers: bool async def async_step_init( self, @@ -650,52 +840,19 @@ async def async_step_init( self.current_config.get(CONF_FILTER_OUTLIERS) or False ) - if self.source_device_id: - device_registry = dr.async_get(self.hass) - device_entry = device_registry.async_get(self.source_device_id) - - if not device_entry: - errors["base"] = "orphaned_battery_note" - else: - if device_entry and device_entry.manufacturer and device_entry.model: - _LOGGER.debug( - "Looking up device %s %s %s %s", - device_entry.manufacturer, - device_entry.model, - get_device_model_id(device_entry) or "", - device_entry.hw_version, - ) - - self.model_info = ModelInfo( - device_entry.manufacturer, - device_entry.model, - get_device_model_id(device_entry), - device_entry.hw_version, - ) - schema = self.build_options_schema() - if user_input is not None: - user_input[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) - user_input[CONF_BATTERY_LOW_THRESHOLD] = int( - user_input[CONF_BATTERY_LOW_THRESHOLD] - ) - # user_input[CONF_BATTERY_LOW_TEMPLATE] = user_input.get(CONF_BATTERY_LOW_TEMPLATE, None) - errors = await self.save_options(user_input, schema) - if not errors: - return self.async_create_entry(title="", data={}) + # if user_input is not None: + # user_input[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) + # user_input[CONF_BATTERY_LOW_THRESHOLD] = int( + # user_input[CONF_BATTERY_LOW_THRESHOLD] + # ) + # # user_input[CONF_BATTERY_LOW_TEMPLATE] = user_input.get(CONF_BATTERY_LOW_TEMPLATE, None) + # errors = await self.save_options(user_input, schema) + # if not errors: + # return self.async_create_entry(title="", data={}) return self.async_show_form( step_id="init", - description_placeholders={ - "manufacturer": self.model_info.manufacturer if self.model_info else "", - "model": self.model_info.model if self.model_info else "", - "model_id": ( - str(self.model_info.model_id or "") if self.model_info else "" - ), - "hw_version": ( - str(self.model_info.hw_version or "") if self.model_info else "" - ), - }, data_schema=schema, errors=errors, ) @@ -761,27 +918,36 @@ def build_options_schema(self) -> vol.Schema: """Build the options schema.""" data_schema = vol.Schema( { - vol.Optional(CONF_NAME): selector.TextSelector( - selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), - ), - vol.Required(CONF_BATTERY_TYPE): selector.TextSelector( - selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), - ), - vol.Required(CONF_BATTERY_QUANTITY): selector.NumberSelector( + vol.Required(CONF_SHOW_ALL_DEVICES): selector.BooleanSelector(), + vol.Required(CONF_HIDE_BATTERY): selector.BooleanSelector(), + vol.Required(CONF_ROUND_BATTERY): selector.BooleanSelector(), + vol.Required(CONF_DEFAULT_BATTERY_LOW_THRESHOLD): selector.NumberSelector( selector.NumberSelectorConfig( - min=1, max=100, mode=selector.NumberSelectorMode.BOX + min=0, max=99, mode=selector.NumberSelectorMode.BOX ), ), - vol.Required(CONF_BATTERY_LOW_THRESHOLD): selector.NumberSelector( + vol.Required(CONF_BATTERY_INCREASE_THRESHOLD): selector.NumberSelector( selector.NumberSelectorConfig( min=0, max=99, mode=selector.NumberSelectorMode.BOX ), ), - vol.Optional(CONF_BATTERY_LOW_TEMPLATE): selector.TemplateSelector(), - vol.Optional(CONF_FILTER_OUTLIERS): selector.BooleanSelector(), + + vol.Required("advanced_settings"): section( + vol.Schema( + { + vol.Required("autodiscovery"): selector.BooleanSelector(), + vol.Required("enable_replaced"): selector.BooleanSelector(), + vol.Optional("user_library"): selector.TextSelector(), + } + ), + {"collapsed": True}, + ) } ) + return data_schema + + #TODO: Fix fill schema return _fill_schema_defaults( data_schema, self.current_config, diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index d5a47d07a..45c7e0476 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -80,6 +80,45 @@ } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", + "unknown": "Unknown error occurred." + } + }, + "battery_note_options": { "step": { "init": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", From ffdbb9de557baabb66fe2569bcbd7bfcf2be8c38 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 11:10:24 +0000 Subject: [PATCH 010/235] Remove obsolete error --- custom_components/battery_notes/translations/en.json | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 45c7e0476..8a578c8a2 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -114,7 +114,6 @@ } }, "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", "unknown": "Unknown error occurred." } }, From 5c6fa504cd90e6939b757636b0834e4536ed094c Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 11:54:51 +0000 Subject: [PATCH 011/235] Add advanced settings to options schema and update translations --- .../battery_notes/config_flow.py | 205 +++++------------- custom_components/battery_notes/const.py | 1 + .../battery_notes/translations/en.json | 4 +- 3 files changed, 56 insertions(+), 154 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 1bb350bc9..4e54b4e42 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -39,6 +39,7 @@ from .common import get_device_model_id from .const import ( + CONF_ADVANCED_SETTINGS, CONF_BATTERY_INCREASE_THRESHOLD, CONF_BATTERY_LOW_TEMPLATE, CONF_BATTERY_LOW_THRESHOLD, @@ -57,6 +58,8 @@ CONF_SHOW_ALL_DEVICES, CONF_SOURCE_ENTITY_ID, CONF_USER_LIBRARY, + DEFAULT_BATTERY_INCREASE_THRESHOLD, + DEFAULT_BATTERY_LOW_THRESHOLD, DOMAIN, ) from .const import NAME as APP_NAME @@ -68,6 +71,35 @@ CONFIG_VERSION = 3 +OPTIONS_SCHEMA = vol.Schema( + { + vol.Required(CONF_SHOW_ALL_DEVICES): selector.BooleanSelector(), + vol.Required(CONF_HIDE_BATTERY): selector.BooleanSelector(), + vol.Required(CONF_ROUND_BATTERY): selector.BooleanSelector(), + vol.Required(CONF_DEFAULT_BATTERY_LOW_THRESHOLD): selector.NumberSelector( + selector.NumberSelectorConfig( + min=0, max=99, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Required(CONF_BATTERY_INCREASE_THRESHOLD): selector.NumberSelector( + selector.NumberSelectorConfig( + min=0, max=99, mode=selector.NumberSelectorMode.BOX + ), + ), + + vol.Required(CONF_ADVANCED_SETTINGS): section( + vol.Schema( + { + vol.Required(CONF_ENABLE_AUTODISCOVERY): selector.BooleanSelector(), + vol.Required(CONF_ENABLE_REPLACED): selector.BooleanSelector(), + vol.Optional(CONF_USER_LIBRARY): selector.TextSelector(), + } + ), + {"collapsed": True}, + ) + } +) + DEVICE_SCHEMA_ALL = vol.Schema( { vol.Required(CONF_DEVICE_ID): selector.DeviceSelector(), @@ -183,7 +215,18 @@ async def async_step_user( return self.async_create_entry( title=APP_NAME, data={}, - options={}, + options={ + CONF_SHOW_ALL_DEVICES: False, + CONF_HIDE_BATTERY: False, + CONF_ROUND_BATTERY: False, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, + CONF_ADVANCED_SETTINGS: { + CONF_ENABLE_AUTODISCOVERY: True, + CONF_ENABLE_REPLACED: True, + CONF_USER_LIBRARY: "", + } + } ) self._set_confirm_only() @@ -815,162 +858,20 @@ async def async_step_battery( # ) class OptionsFlowHandler(OptionsFlow): - """Handle an option flow for BatteryNotes.""" - - def __init__(self) -> None: - """Initialize options flow.""" - self.current_config: dict - self.name: str + """Options flow.""" async def async_step_init( - self, - user_input: dict[str, Any] | None = None, + self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: - """Handle options flow.""" - errors = {} - self.current_config = dict(self.config_entry.data) - self.source_device_id = self.current_config.get(CONF_DEVICE_ID) # type: ignore - self.name = str(self.current_config.get(CONF_NAME) or "") - self.battery_type = str(self.current_config.get(CONF_BATTERY_TYPE) or "") - self.battery_quantity = int(self.current_config.get(CONF_BATTERY_QUANTITY) or 1) - self.battery_low_template = str( - self.current_config.get(CONF_BATTERY_LOW_TEMPLATE) or "" - ) - self.filter_outliers = bool( - self.current_config.get(CONF_FILTER_OUTLIERS) or False - ) + """Manage the options.""" - schema = self.build_options_schema() - # if user_input is not None: - # user_input[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) - # user_input[CONF_BATTERY_LOW_THRESHOLD] = int( - # user_input[CONF_BATTERY_LOW_THRESHOLD] - # ) - # # user_input[CONF_BATTERY_LOW_TEMPLATE] = user_input.get(CONF_BATTERY_LOW_TEMPLATE, None) - # errors = await self.save_options(user_input, schema) - # if not errors: - # return self.async_create_entry(title="", data={}) + if user_input is not None: + return self.async_create_entry(data=user_input) return self.async_show_form( step_id="init", - data_schema=schema, - errors=errors, - ) - - async def save_options( - self, - user_input: dict[str, Any], - schema: vol.Schema, - ) -> dict: - """Save options, and return errors when validation fails.""" - errors = {} - - device_registry = dr.async_get(self.hass) - device_entry = device_registry.async_get( - str(self.config_entry.data.get(CONF_DEVICE_ID)) - ) - - source_entity_id = self.config_entry.data.get(CONF_SOURCE_ENTITY_ID, None) - - entity_entry: er.RegistryEntry | None = None - if source_entity_id: - entity_registry = er.async_get(self.hass) - entity_entry = entity_registry.async_get(source_entity_id) - if not entity_entry: - errors["base"] = "orphaned_battery_note" - return errors - else: - if not device_entry: - errors["base"] = "orphaned_battery_note" - return errors - - title: Any = "" - if CONF_NAME in user_input: - title = user_input.get(CONF_NAME) - elif source_entity_id and entity_entry: - title = entity_entry.name or entity_entry.original_name - elif device_entry: - title = device_entry.name_by_user or device_entry.name - - self._process_user_input(user_input, schema) - self.hass.config_entries.async_update_entry( - self.config_entry, - title=title, - data=self.current_config, - ) - return {} - - def _process_user_input( - self, - user_input: dict[str, Any], - schema: vol.Schema, - ) -> None: - """Process the provided user input against the schema.""" - for key in schema.schema: - if isinstance(key, vol.Marker): - key = key.schema - if key in user_input: - self.current_config[key] = user_input.get(key) - elif key in self.current_config: - self.current_config.pop(key) - - def build_options_schema(self) -> vol.Schema: - """Build the options schema.""" - data_schema = vol.Schema( - { - vol.Required(CONF_SHOW_ALL_DEVICES): selector.BooleanSelector(), - vol.Required(CONF_HIDE_BATTERY): selector.BooleanSelector(), - vol.Required(CONF_ROUND_BATTERY): selector.BooleanSelector(), - vol.Required(CONF_DEFAULT_BATTERY_LOW_THRESHOLD): selector.NumberSelector( - selector.NumberSelectorConfig( - min=0, max=99, mode=selector.NumberSelectorMode.BOX - ), - ), - vol.Required(CONF_BATTERY_INCREASE_THRESHOLD): selector.NumberSelector( - selector.NumberSelectorConfig( - min=0, max=99, mode=selector.NumberSelectorMode.BOX - ), - ), - - vol.Required("advanced_settings"): section( - vol.Schema( - { - vol.Required("autodiscovery"): selector.BooleanSelector(), - vol.Required("enable_replaced"): selector.BooleanSelector(), - vol.Optional("user_library"): selector.TextSelector(), - } - ), - {"collapsed": True}, - ) - } - ) - - return data_schema - - #TODO: Fix fill schema - return _fill_schema_defaults( - data_schema, - self.current_config, + data_schema=self.add_suggested_values_to_schema( + OPTIONS_SCHEMA, + self.config_entry.options, + ), ) - - -def _fill_schema_defaults( - data_schema: vol.Schema, - options: dict[str, str], -) -> vol.Schema: - """Make a copy of the schema with suggested values set to saved options.""" - schema = {} - for key, val in data_schema.schema.items(): - new_key = key - if key in options and isinstance(key, vol.Marker): - if ( - isinstance(key, vol.Optional) - and callable(key.default) - and key.default() - ): - new_key = vol.Optional(key.schema, default=options.get(key)) # type: ignore - else: - new_key = copy.copy(key) - new_key.description = {"suggested_value": options.get(key)} # type: ignore - schema[new_key] = val - return vol.Schema(schema) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index bb0058299..c559a2f62 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -54,6 +54,7 @@ CONF_ROUND_BATTERY = "round_battery" CONF_BATTERY_LOW_TEMPLATE = "battery_low_template" CONF_FILTER_OUTLIERS = "filter_outliers" +CONF_ADVANCED_SETTINGS = "advanced_settings" DATA_CONFIGURED_ENTITIES = "configured_entities" DATA_DISCOVERED_ENTITIES = "discovered_entities" diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 8a578c8a2..61ce2a3b4 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -100,12 +100,12 @@ "advanced_settings": { "name": "Advanced settings", "data": { - "autodiscovery": "Auto discovery", + "enable_autodiscovery": "Auto discovery", "enable_replaced": "Enable battery replaced", "user_library": "User library" }, "data_description": { - "autodiscovery": "Auto discovery of devices that are in the library.", + "enable_autodiscovery": "Auto discovery of devices that are in the library.", "enable_replaced": "Enable the battery replaced button on each battery note.", "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." } From 03eb4c5433e34a409aef06e222575c4509413ad8 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 12:59:12 +0000 Subject: [PATCH 012/235] Import config yaml --- custom_components/battery_notes/__init__.py | 68 +++++++++++++------ .../battery_notes/config_flow.py | 45 ++++++++++-- custom_components/battery_notes/const.py | 2 + .../battery_notes/translations/en.json | 4 ++ 4 files changed, 95 insertions(+), 24 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 822399336..009b6e1e8 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,10 +8,14 @@ import logging import re +from typing import Any import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import ConfigEntry +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.const import ( + CONF_SOURCE, +) from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv @@ -21,6 +25,7 @@ from .config_flow import CONFIG_VERSION from .const import ( + CONF_ADVANCED_SETTINGS, CONF_BATTERY_INCREASE_THRESHOLD, CONF_BATTERY_QUANTITY, CONF_BATTERY_TYPE, @@ -111,25 +116,37 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: store = await async_get_registry(hass) domain_config = BatteryNotesDomainConfig( - enable_autodiscovery=config.get(DOMAIN, {}).get( - CONF_ENABLE_AUTODISCOVERY, True - ), - show_all_devices=config.get(DOMAIN, {}).get(CONF_SHOW_ALL_DEVICES, False), - enable_replaced=config.get(DOMAIN, {}).get(CONF_ENABLE_REPLACED, True), - hide_battery=config.get(DOMAIN, {}).get(CONF_HIDE_BATTERY, False), - round_battery=config.get(DOMAIN, {}).get(CONF_ROUND_BATTERY, False), - default_battery_low_threshold=config.get(DOMAIN, {}).get( - CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD - ), - battery_increased_threshod=config.get(DOMAIN, {}).get( - CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD - ), - library_url=config.get(DOMAIN, {}).get(CONF_LIBRARY_URL, DEFAULT_LIBRARY_URL), - schema_url=config.get(DOMAIN, {}).get(CONF_SCHEMA_URL, DEFAULT_SCHEMA_URL), + library_url=DEFAULT_LIBRARY_URL, + schema_url=DEFAULT_SCHEMA_URL, user_library=config.get(DOMAIN, {}).get(CONF_USER_LIBRARY, ""), store=store, ) + yaml_domain_config: list[dict[str, Any]] | None = config.get(DOMAIN) + if yaml_domain_config: + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, + context={CONF_SOURCE: SOURCE_IMPORT}, + data={ + CONF_SHOW_ALL_DEVICES: yaml_domain_config.get(CONF_SHOW_ALL_DEVICES, False), + CONF_HIDE_BATTERY: yaml_domain_config.get(CONF_HIDE_BATTERY, False), + CONF_ROUND_BATTERY: yaml_domain_config.get(CONF_ROUND_BATTERY, False), + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: yaml_domain_config.get( + CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD + ), + CONF_BATTERY_INCREASE_THRESHOLD: yaml_domain_config.get( + CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD + ), + CONF_ADVANCED_SETTINGS: { + CONF_ENABLE_AUTODISCOVERY: yaml_domain_config.get(CONF_ENABLE_AUTODISCOVERY, True), + CONF_ENABLE_REPLACED: yaml_domain_config.get(CONF_ENABLE_REPLACED, True), + CONF_USER_LIBRARY: yaml_domain_config.get(CONF_USER_LIBRARY, ""), + }, + } + ) + ) + hass.data[MY_KEY] = domain_config library_updater = LibraryUpdater(hass) @@ -153,11 +170,22 @@ async def async_setup_entry( ) -> bool: """Set up a config entry.""" - data = hass.data[MY_KEY] - assert data.store + domain_config = hass.data[MY_KEY] + assert domain_config.store + + domain_config.show_all_devices = config_entry.options[CONF_SHOW_ALL_DEVICES] + domain_config.hide_battery = config_entry.options[CONF_HIDE_BATTERY] + domain_config.round_battery = config_entry.options[CONF_ROUND_BATTERY] + domain_config.default_battery_low_threshold = config_entry.options[CONF_DEFAULT_BATTERY_LOW_THRESHOLD] + domain_config.battery_increased_threshod = config_entry.options[CONF_BATTERY_INCREASE_THRESHOLD] + + domain_config.enable_autodiscovery = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_ENABLE_AUTODISCOVERY] + domain_config.enable_replaced = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_ENABLE_REPLACED] + domain_config.user_library = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_USER_LIBRARY] + config_entry.runtime_data = BatteryNotesData( - domain_config=data, - store=data.store, + domain_config=domain_config, + store=domain_config.store, ) # for subentry in config_entry.subentries.values(): diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 4e54b4e42..5cf789035 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -28,6 +28,7 @@ from homeassistant.core import callback, split_entity_id from homeassistant.data_entry_flow import AbortFlow, section from homeassistant.helpers import selector +from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.selector import ( SelectSelector, SelectSelectorConfig, @@ -61,6 +62,7 @@ DEFAULT_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD, DOMAIN, + ISSUE_DEPRECATED_YAML, ) from .const import NAME as APP_NAME from .coordinator import MY_KEY @@ -201,6 +203,34 @@ async def async_step_integration_discovery( return await self.async_step_device(discovery_info) + # triggered by async_setup() from __init__.py + async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult: + """Handle import of config entry from configuration.yaml.""" + + try: + config_flow_result: ConfigFlowResult = await self.async_step_user( + import_data + ) + except AbortFlow: + # this happens if the config entry is already imported + + async_create_issue( + self.hass, + DOMAIN, + ISSUE_DEPRECATED_YAML, + is_fixable=False, + issue_domain=DOMAIN, + severity=IssueSeverity.WARNING, + translation_key=ISSUE_DEPRECATED_YAML, + translation_placeholders={ + "domain": DOMAIN, + "integration_title": APP_NAME, + }, + ) + raise + else: + return config_flow_result + async def async_step_user( self, user_input: dict | None = None, @@ -212,10 +242,9 @@ async def async_step_user( return self.async_abort(reason="already_configured") if user_input is not None: - return self.async_create_entry( - title=APP_NAME, - data={}, - options={ + if len(user_input) == 0: + # Init defaults + options = { CONF_SHOW_ALL_DEVICES: False, CONF_HIDE_BATTERY: False, CONF_ROUND_BATTERY: False, @@ -227,6 +256,14 @@ async def async_step_user( CONF_USER_LIBRARY: "", } } + else: + # From import + options = user_input + + return self.async_create_entry( + title=APP_NAME, + data={}, + options=options ) self._set_confirm_only() diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index c559a2f62..34f729fd1 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -94,6 +94,8 @@ WINDOW_SIZE_UNIT_NUMBER_EVENTS = 1 WINDOW_SIZE_UNIT_TIME = 2 +ISSUE_DEPRECATED_YAML = "deprecated_yaml" + SERVICE_BATTERY_REPLACED_SCHEMA = vol.Schema( { vol.Optional(ATTR_DEVICE_ID): cv.string, diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 61ce2a3b4..8e9309c2e 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -258,6 +258,10 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." } } } \ No newline at end of file From 72304992ba6b5a760a3801d90d65b96103b05e92 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 13:27:44 +0000 Subject: [PATCH 013/235] Raise issue on deprecated yaml --- .../battery_notes/config_flow.py | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 5cf789035..058fd072b 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -13,6 +13,7 @@ from homeassistant.components.sensor.const import SensorDeviceClass from homeassistant.config_entries import ( ConfigEntry, + ConfigFlow, ConfigFlowResult, ConfigSubentry, ConfigSubentryData, @@ -26,7 +27,7 @@ Platform, ) from homeassistant.core import callback, split_entity_id -from homeassistant.data_entry_flow import AbortFlow, section +from homeassistant.data_entry_flow import AbortFlow, FlowResultType, section from homeassistant.helpers import selector from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.selector import ( @@ -207,29 +208,25 @@ async def async_step_integration_discovery( async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult: """Handle import of config entry from configuration.yaml.""" - try: - config_flow_result: ConfigFlowResult = await self.async_step_user( - import_data - ) - except AbortFlow: - # this happens if the config entry is already imported - - async_create_issue( - self.hass, - DOMAIN, - ISSUE_DEPRECATED_YAML, - is_fixable=False, - issue_domain=DOMAIN, - severity=IssueSeverity.WARNING, - translation_key=ISSUE_DEPRECATED_YAML, - translation_placeholders={ - "domain": DOMAIN, - "integration_title": APP_NAME, - }, - ) - raise - else: - return config_flow_result + config_flow_result: ConfigFlowResult = await self.async_step_user( + import_data + ) + + async_create_issue( + self.hass, + DOMAIN, + ISSUE_DEPRECATED_YAML, + is_fixable=False, + issue_domain=DOMAIN, + severity=IssueSeverity.WARNING, + translation_key=ISSUE_DEPRECATED_YAML, + translation_placeholders={ + "domain": DOMAIN, + "integration_title": APP_NAME, + }, + ) + + return config_flow_result async def async_step_user( self, From 64308003bc50b84bca59c871aba9530f459b7e83 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 13:40:11 +0000 Subject: [PATCH 014/235] Reorder options below flow --- .../battery_notes/config_flow.py | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 058fd072b..52ca594e8 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -464,6 +464,25 @@ async def async_step_battery( errors=errors, ) +class OptionsFlowHandler(OptionsFlow): + """Options flow.""" + + async def async_step_init( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Manage the options.""" + + if user_input is not None: + return self.async_create_entry(data=user_input) + + return self.async_show_form( + step_id="init", + data_schema=self.add_suggested_values_to_schema( + OPTIONS_SCHEMA, + self.config_entry.options, + ), + ) + class BatteryNotesSubentryFlowHandler(ConfigSubentryFlow): """Flow for managing Battery Notes subentries.""" @@ -891,21 +910,3 @@ async def async_step_battery( # self.current_config, # ) -class OptionsFlowHandler(OptionsFlow): - """Options flow.""" - - async def async_step_init( - self, user_input: dict[str, Any] | None = None - ) -> ConfigFlowResult: - """Manage the options.""" - - if user_input is not None: - return self.async_create_entry(data=user_input) - - return self.async_show_form( - step_id="init", - data_schema=self.add_suggested_values_to_schema( - OPTIONS_SCHEMA, - self.config_entry.options, - ), - ) From ec4db44a3ca4bcf007df292bcbd8f7b99d2d6ef8 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 13:43:12 +0000 Subject: [PATCH 015/235] Move discovery to setup_entry --- custom_components/battery_notes/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 009b6e1e8..9eb4bf734 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -153,12 +153,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: await library_updater.copy_schema() await library_updater.get_library_updates(startup=True) - # if domain_config.enable_autodiscovery: - # discovery_manager = DiscoveryManager(hass, domain_config) - # await discovery_manager.start_discovery() - # else: - # _LOGGER.debug("Auto discovery disabled") - # Register custom services async_setup_services(hass) @@ -198,6 +192,12 @@ async def async_setup_entry( config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) + if domain_config.enable_autodiscovery: + discovery_manager = DiscoveryManager(hass, domain_config) + await discovery_manager.start_discovery() + else: + _LOGGER.debug("Auto discovery disabled") + return True From 7a551d598083006d1e0388345529685ef7d2bd23 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 13:49:46 +0000 Subject: [PATCH 016/235] Add subentry coordinators --- custom_components/battery_notes/__init__.py | 11 ++++++----- custom_components/battery_notes/coordinator.py | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 9eb4bf734..fb3c7deba 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -182,11 +182,12 @@ async def async_setup_entry( store=domain_config.store, ) - # for subentry in config_entry.subentries.values(): - # if subentry.subentry_type == "battery_note": - # #TODO: Change coordinator to take subentry data - # coordinator = BatteryNotesCoordinator(hass, config_entry) - # config_entry.runtime_data.coordinator = coordinator + for subentry in config_entry.subentries.values(): + if subentry.subentry_type == "battery_note": + #TODO: Change coordinator to take subentry data + coordinator = BatteryNotesCoordinator(hass, config_entry) + config_entry.runtime_data.coordinator = coordinator + config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 8912aa058..25d35e6f3 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -90,6 +90,7 @@ class BatteryNotesData: domain_config: BatteryNotesDomainConfig store: BatteryNotesStorage coordinator: BatteryNotesCoordinator | None = None + subentry_coordinators: dict[str, BatteryNotesCoordinator] = None class BatteryNotesCoordinator(DataUpdateCoordinator[None]): From 725fa24a96774fa75f2982d3474c49de85b9ac93 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 14:02:24 +0000 Subject: [PATCH 017/235] Hard code library & schema urls --- custom_components/battery_notes/__init__.py | 17 +---------------- custom_components/battery_notes/const.py | 2 -- custom_components/battery_notes/coordinator.py | 4 ---- .../battery_notes/library_updater.py | 16 ++++++---------- 4 files changed, 7 insertions(+), 32 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index fb3c7deba..68fd87250 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -33,15 +33,11 @@ CONF_ENABLE_AUTODISCOVERY, CONF_ENABLE_REPLACED, CONF_HIDE_BATTERY, - CONF_LIBRARY_URL, CONF_ROUND_BATTERY, - CONF_SCHEMA_URL, CONF_SHOW_ALL_DEVICES, CONF_USER_LIBRARY, DEFAULT_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD, - DEFAULT_LIBRARY_URL, - DEFAULT_SCHEMA_URL, DOMAIN, MIN_HA_VERSION, PLATFORMS, @@ -84,14 +80,6 @@ CONF_BATTERY_INCREASE_THRESHOLD, default=DEFAULT_BATTERY_INCREASE_THRESHOLD, ): cv.positive_int, - vol.Optional( - CONF_LIBRARY_URL, - default=DEFAULT_LIBRARY_URL, - ): cv.string, - vol.Optional( - CONF_SCHEMA_URL, - default=DEFAULT_SCHEMA_URL, - ): cv.string, }, ), ), @@ -116,8 +104,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: store = await async_get_registry(hass) domain_config = BatteryNotesDomainConfig( - library_url=DEFAULT_LIBRARY_URL, - schema_url=DEFAULT_SCHEMA_URL, user_library=config.get(DOMAIN, {}).get(CONF_USER_LIBRARY, ""), store=store, ) @@ -307,6 +293,7 @@ async def async_migrate_entry( domain_config = hass.data[MY_KEY] + #TODO: change this to run config flow import options = { CONF_ENABLE_AUTODISCOVERY: domain_config.enable_autodiscovery, CONF_SHOW_ALL_DEVICES: domain_config.show_all_devices, @@ -315,8 +302,6 @@ async def async_migrate_entry( CONF_ROUND_BATTERY: domain_config.round_battery, CONF_DEFAULT_BATTERY_LOW_THRESHOLD: domain_config.default_battery_low_threshold, CONF_BATTERY_INCREASE_THRESHOLD: domain_config.battery_increased_threshod, - CONF_LIBRARY_URL: domain_config.library_url, - CONF_SCHEMA_URL: domain_config.schema_url, } _migrate_base_entry = ConfigEntry( diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 34f729fd1..ec19adaf5 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -44,8 +44,6 @@ CONF_MODEL_ID = "model_id" CONF_MANUFACTURER = "manufacturer" CONF_DEVICE_NAME = "device_name" -CONF_LIBRARY_URL = "library_url" -CONF_SCHEMA_URL = "schema_url" CONF_SHOW_ALL_DEVICES = "show_all_devices" CONF_ENABLE_REPLACED = "enable_replaced" CONF_DEFAULT_BATTERY_LOW_THRESHOLD = "default_battery_low_threshold" diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 25d35e6f3..dab877fca 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -49,8 +49,6 @@ CONF_SOURCE_ENTITY_ID, DEFAULT_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD, - DEFAULT_LIBRARY_URL, - DEFAULT_SCHEMA_URL, DOMAIN, EVENT_BATTERY_INCREASED, EVENT_BATTERY_THRESHOLD, @@ -73,8 +71,6 @@ class BatteryNotesDomainConfig: round_battery: bool = False default_battery_low_threshold: int = DEFAULT_BATTERY_LOW_THRESHOLD battery_increased_threshod: int = DEFAULT_BATTERY_INCREASE_THRESHOLD - library_url: str = DEFAULT_LIBRARY_URL - schema_url: str = DEFAULT_SCHEMA_URL library_last_update: datetime | None = None user_library: str = "" store: BatteryNotesStorage | None = None diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index a23bd305c..d7f921e6c 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -18,6 +18,9 @@ from homeassistant.helpers.event import async_track_utc_time_change from homeassistant.helpers.storage import STORAGE_DIR +from .const import ( + DEFAULT_LIBRARY_URL, +) from .coordinator import MY_KEY, BatteryNotesDomainConfig from .discovery import DiscoveryManager @@ -42,10 +45,7 @@ def __init__(self, hass: HomeAssistant): if not domain_config: domain_config = BatteryNotesDomainConfig() - library_url = domain_config.library_url - schema_url = domain_config.schema_url - - self._client = LibraryUpdaterClient(library_url=library_url, schema_url=schema_url, session=async_get_clientsession(hass)) + self._client = LibraryUpdaterClient(session=async_get_clientsession(hass)) # Fire the library check every 24 hours from just before now refresh_time = datetime.now() - timedelta(hours=0, minutes=1) @@ -161,19 +161,15 @@ class LibraryUpdaterClient: def __init__( self, - library_url: str, - schema_url: str, session: aiohttp.ClientSession, ) -> None: """Client to get latest library file from GitHub.""" - self._library_url = library_url - self._schema_url = schema_url self._session = session async def async_get_data(self) -> Any: """Get data from the API.""" - _LOGGER.debug(f"Updating library from {self._library_url}") - return await self._api_wrapper(method="get", url=self._library_url) + _LOGGER.debug(f"Updating library from {DEFAULT_LIBRARY_URL}") + return await self._api_wrapper(method="get", url=DEFAULT_LIBRARY_URL) async def _api_wrapper( self, From 6db3a1855e7b69e97815c8d72efd3af18a5917a1 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 14:07:42 +0000 Subject: [PATCH 018/235] Default migrate base entry --- custom_components/battery_notes/__init__.py | 43 +++++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 68fd87250..d1e32b9b7 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -88,6 +88,7 @@ ) _migrate_base_entry: ConfigEntry = None +_yaml_domain_config: list[dict[str, Any]] | None = None async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Integration setup.""" @@ -291,18 +292,36 @@ async def async_migrate_entry( "No existing V3 config entry found, creating a new one for migration" ) - domain_config = hass.data[MY_KEY] - - #TODO: change this to run config flow import - options = { - CONF_ENABLE_AUTODISCOVERY: domain_config.enable_autodiscovery, - CONF_SHOW_ALL_DEVICES: domain_config.show_all_devices, - CONF_ENABLE_REPLACED: domain_config.enable_replaced, - CONF_HIDE_BATTERY: domain_config.hide_battery, - CONF_ROUND_BATTERY: domain_config.round_battery, - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: domain_config.default_battery_low_threshold, - CONF_BATTERY_INCREASE_THRESHOLD: domain_config.battery_increased_threshod, - } + if _yaml_domain_config: + options={ + CONF_SHOW_ALL_DEVICES: _yaml_domain_config.get(CONF_SHOW_ALL_DEVICES, False), + CONF_HIDE_BATTERY: _yaml_domain_config.get(CONF_HIDE_BATTERY, False), + CONF_ROUND_BATTERY: _yaml_domain_config.get(CONF_ROUND_BATTERY, False), + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: _yaml_domain_config.get( + CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD + ), + CONF_BATTERY_INCREASE_THRESHOLD: _yaml_domain_config.get( + CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD + ), + CONF_ADVANCED_SETTINGS: { + CONF_ENABLE_AUTODISCOVERY: _yaml_domain_config.get(CONF_ENABLE_AUTODISCOVERY, True), + CONF_ENABLE_REPLACED: _yaml_domain_config.get(CONF_ENABLE_REPLACED, True), + CONF_USER_LIBRARY: _yaml_domain_config.get(CONF_USER_LIBRARY, ""), + }, + } + else: + options={ + CONF_SHOW_ALL_DEVICES: False, + CONF_HIDE_BATTERY: False, + CONF_ROUND_BATTERY: False, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, + CONF_ADVANCED_SETTINGS: { + CONF_ENABLE_AUTODISCOVERY: True, + CONF_ENABLE_REPLACED: True, + CONF_USER_LIBRARY: "", + }, + } _migrate_base_entry = ConfigEntry( domain=DOMAIN, From c1d7908ca16ae09f53f1578fda07db2bed7f6ab4 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 14:51:16 +0000 Subject: [PATCH 019/235] Add device sub entry --- .../battery_notes/config_flow.py | 58 ++++++++++++++++--- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 52ca594e8..99374e3d3 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -723,9 +723,6 @@ async def async_step_battery( device_entry = device_registry.async_get(device_id) unique_id = f"bn_{device_id}" - await self.async_set_unique_id(unique_id) - self._abort_if_unique_id_configured() - if CONF_NAME in self.data: title = self.data.get(CONF_NAME) elif source_entity_id and entity_entry: @@ -734,10 +731,57 @@ async def async_step_battery( assert device_entry title = device_entry.name_by_user or device_entry.name - return self.async_create_entry( - title=str(title), - data=self.data, - ) + return self.async_create_entry(title=str(title), data=self.data, unique_id=unique_id) + + return self.async_show_form( + step_id="battery", + description_placeholders={ + "manufacturer": self.model_info.manufacturer if self.model_info else "", + "model": self.model_info.model if self.model_info else "", + "model_id": ( + str(self.model_info.model_id or "") if self.model_info else "" + ), + "hw_version": ( + str(self.model_info.hw_version or "") if self.model_info else "" + ), + }, + data_schema=vol.Schema( + { + vol.Required( + CONF_BATTERY_TYPE, + default=self.data.get(CONF_BATTERY_TYPE), + ): selector.TextSelector( + selector.TextSelectorConfig( + type=selector.TextSelectorType.TEXT + ), + ), + vol.Required( + CONF_BATTERY_QUANTITY, + default=int(self.data.get(CONF_BATTERY_QUANTITY, 1)), + ): selector.NumberSelector( + selector.NumberSelectorConfig( + min=1, max=100, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Required( + CONF_BATTERY_LOW_THRESHOLD, + default=int(self.data.get(CONF_BATTERY_LOW_THRESHOLD, 0)), + ): selector.NumberSelector( + selector.NumberSelectorConfig( + min=0, max=99, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Optional( + CONF_BATTERY_LOW_TEMPLATE + ): selector.TemplateSelector(), + vol.Optional( + CONF_FILTER_OUTLIERS, + default=False): selector.BooleanSelector(), + } + ), + errors=errors, + ) + #TODO: Change this to be sub entry options flow # class OptionsFlowHandler(OptionsFlow): From 244e2fcb229b9dd8cc923963d87331470950f800 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 14:59:37 +0000 Subject: [PATCH 020/235] Temp remove device setup --- custom_components/battery_notes/__init__.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index d1e32b9b7..293f507c0 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -169,16 +169,17 @@ async def async_setup_entry( store=domain_config.store, ) - for subentry in config_entry.subentries.values(): - if subentry.subentry_type == "battery_note": - #TODO: Change coordinator to take subentry data - coordinator = BatteryNotesCoordinator(hass, config_entry) - config_entry.runtime_data.coordinator = coordinator - config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator + #TODO: Get this working + # for subentry in config_entry.subentries.values(): + # if subentry.subentry_type == "battery_note": + # #TODO: Change coordinator to take subentry data + # coordinator = BatteryNotesCoordinator(hass, config_entry) + # config_entry.runtime_data.coordinator = coordinator + # config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator - await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) + # await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) - config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) + # config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) if domain_config.enable_autodiscovery: discovery_manager = DiscoveryManager(hass, domain_config) From d3b22d80b95b2d5e02829eda016ed375307b07de Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 15:12:46 +0000 Subject: [PATCH 021/235] WIP --- custom_components/battery_notes/config_flow.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 99374e3d3..468882347 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -723,6 +723,9 @@ async def async_step_battery( device_entry = device_registry.async_get(device_id) unique_id = f"bn_{device_id}" + #TODO: Check if unique_id already exists + # self.async_abort(reason="already_configured") + if CONF_NAME in self.data: title = self.data.get(CONF_NAME) elif source_entity_id and entity_entry: @@ -782,6 +785,15 @@ async def async_step_battery( errors=errors, ) + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> SubentryFlowResult: + """User flow to modify an existing location.""" + # Retrieve the parent config entry for reference. + # config_entry = self._get_reconfigure_entry() + # # Retrieve the specific subentry targeted for update. + # config_subentry = self._get_reconfigure_subentry() + # ... #TODO: Change this to be sub entry options flow # class OptionsFlowHandler(OptionsFlow): From f29f8dfdf8458fd4bcb381767a8efe9fe3b8db22 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 15:20:35 +0000 Subject: [PATCH 022/235] Add duplicate check on sub entries --- custom_components/battery_notes/config_flow.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 468882347..db5028a6f 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -723,8 +723,12 @@ async def async_step_battery( device_entry = device_registry.async_get(device_id) unique_id = f"bn_{device_id}" - #TODO: Check if unique_id already exists - # self.async_abort(reason="already_configured") + # Check if unique_id already exists + config_entry = self._get_entry() + for existing_subentry in config_entry.subentries.values(): + if existing_subentry.unique_id == unique_id: + _LOGGER.debug("Subentry with unique_id %s already exists", unique_id) + return self.async_abort(reason="already_configured") if CONF_NAME in self.data: title = self.data.get(CONF_NAME) From f627317b0015351b170625642870d6f70a2eeb3b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 15:31:38 +0000 Subject: [PATCH 023/235] Add sub entry reconfigure --- custom_components/battery_notes/config_flow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index db5028a6f..c913a677a 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -794,9 +794,9 @@ async def async_step_reconfigure( ) -> SubentryFlowResult: """User flow to modify an existing location.""" # Retrieve the parent config entry for reference. - # config_entry = self._get_reconfigure_entry() + config_entry = self._get_entry() # # Retrieve the specific subentry targeted for update. - # config_subentry = self._get_reconfigure_subentry() + config_subentry = self._get_reconfigure_subentry() # ... #TODO: Change this to be sub entry options flow From 92dc72a114dc5fb6ae39109ba53d43e72d59a915 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 15:46:30 +0000 Subject: [PATCH 024/235] Fix discovery add subentry --- custom_components/battery_notes/config_flow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index c913a677a..f379edfa7 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -406,8 +406,7 @@ async def async_step_battery( config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] # Create a subentry subentry = ConfigSubentry(subentry_type="battery_note", data=self.data, title=str(title), unique_id=unique_id) - await self.hass.config_entries.async_add_subentry(config_entry, subentry) - + self.hass.config_entries.async_add_subentry(config_entry, subentry) # config_flow_result: ConfigFlowResult = await self.async_step_user( # discovered_data From 237e130b13c2510b1a646e91128ad27cf3903169 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 16:05:28 +0000 Subject: [PATCH 025/235] Add discovery strings --- .../battery_notes/translations/en.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 8e9309c2e..8c0cd1ffa 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -4,6 +4,25 @@ "user": { "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", "title": "Setup Battery Notes" + }, + "battery": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "Battery type", + "battery_quantity": "Battery quantity", + "battery_low_threshold": "Battery low threshold", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 will use the global default threshold", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Device manual configuration" } }, "abort": { From 6b133aa9b5a2196ccac5313b4162f87a09708cf8 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 16:09:58 +0000 Subject: [PATCH 026/235] Remove unused discovery strings --- custom_components/battery_notes/translations/en.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 8c0cd1ffa..12f4518f2 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -19,10 +19,6 @@ "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" } }, "abort": { From 2484b7892e20d075cf6ccfd48ee2ca5cb394a902 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 1 Aug 2025 16:36:44 +0000 Subject: [PATCH 027/235] Comments --- custom_components/battery_notes/config_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index f379edfa7..a074d9175 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -791,7 +791,7 @@ async def async_step_battery( async def async_step_reconfigure( self, user_input: dict[str, Any] | None = None ) -> SubentryFlowResult: - """User flow to modify an existing location.""" + """User flow to modify an existing battery note.""" # Retrieve the parent config entry for reference. config_entry = self._get_entry() # # Retrieve the specific subentry targeted for update. From 85ba27d014a017f4dbec45a58d0295a235e8be97 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 2 Aug 2025 16:41:22 +0000 Subject: [PATCH 028/235] Work on reconfigure battery note --- .../battery_notes/config_flow.py | 127 +++++++++++++++++- .../battery_notes/translations/en.json | 20 ++- 2 files changed, 142 insertions(+), 5 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index a074d9175..cbdbaa147 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -13,6 +13,7 @@ from homeassistant.components.sensor.const import SensorDeviceClass from homeassistant.config_entries import ( ConfigEntry, + ConfigEntryState, ConfigFlow, ConfigFlowResult, ConfigSubentry, @@ -688,6 +689,7 @@ async def async_step_battery( ) -> ConfigFlowResult: """Second step in config flow to add the battery type.""" errors: dict[str, str] = {} + if user_input is not None: self.data[CONF_BATTERY_TYPE] = user_input[CONF_BATTERY_TYPE] self.data[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) @@ -730,7 +732,7 @@ async def async_step_battery( return self.async_abort(reason="already_configured") if CONF_NAME in self.data: - title = self.data.get(CONF_NAME) + title = self.data.pop(CONF_NAME) elif source_entity_id and entity_entry: title = entity_entry.name or entity_entry.original_name else: @@ -792,11 +794,108 @@ async def async_step_reconfigure( self, user_input: dict[str, Any] | None = None ) -> SubentryFlowResult: """User flow to modify an existing battery note.""" - # Retrieve the parent config entry for reference. + errors: dict[str, str] = {} + config_entry = self._get_entry() - # # Retrieve the specific subentry targeted for update. config_subentry = self._get_reconfigure_subentry() - # ... + + if user_input is not None: + self.data[CONF_BATTERY_TYPE] = user_input[CONF_BATTERY_TYPE] + self.data[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) + self.data[CONF_BATTERY_LOW_THRESHOLD] = int( + user_input[CONF_BATTERY_LOW_THRESHOLD] + ) + if user_input[CONF_BATTERY_LOW_TEMPLATE] == "": + self.data[CONF_BATTERY_LOW_TEMPLATE] = None + else: + self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input[CONF_BATTERY_LOW_TEMPLATE] + self.data[CONF_FILTER_OUTLIERS] = user_input.get(CONF_FILTER_OUTLIERS, False) + + # Update the subentry with new data + # config_subentry.data.update(self.data) + # config_subentry.title = self.data.get(CONF_NAME, config_subentry.title) + + # Save the updated subentry + new_title = user_input.pop(CONF_NAME) + + # self.hass.config_entries.async_update_subentry( + # entry=config_entry, + # subentry=config_subentry, + # data=user_input, + # title=new_title) + + return self.async_update_and_abort( + self._get_entry(), + self._get_reconfigure_subentry(), + title=new_title, + data=self.data, + ) + + self.data = config_subentry.data.copy() + + self.source_device_id = self.data.get(CONF_DEVICE_ID) + + if self.source_device_id: + device_registry = dr.async_get(self.hass) + device_entry = device_registry.async_get(self.source_device_id) + + if not device_entry: + errors["base"] = "orphaned_battery_note" + else: + if device_entry and device_entry.manufacturer and device_entry.model: + _LOGGER.debug( + "Looking up device %s %s %s %s", + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry) or "", + device_entry.hw_version, + ) + + self.model_info = ModelInfo( + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry), + device_entry.hw_version, + ) + + data_schema = vol.Schema( + { + vol.Optional(CONF_NAME, default=config_entry.title): selector.TextSelector( + selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), + ), + vol.Required(CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE]): selector.TextSelector( + selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), + ), + vol.Required(CONF_BATTERY_QUANTITY, default=self.data[CONF_BATTERY_QUANTITY]): selector.NumberSelector( + selector.NumberSelectorConfig( + min=1, max=100, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data[CONF_BATTERY_LOW_THRESHOLD]): selector.NumberSelector( + selector.NumberSelectorConfig( + min=0, max=99, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Optional(CONF_BATTERY_LOW_TEMPLATE, default=self.data.get(CONF_BATTERY_LOW_TEMPLATE, "")): selector.TemplateSelector(), + vol.Optional(CONF_FILTER_OUTLIERS, default=self.data.get(CONF_FILTER_OUTLIERS, False)): selector.BooleanSelector(), + } + ) + + return self.async_show_form( + step_id="reconfigure", + description_placeholders={ + "manufacturer": self.model_info.manufacturer if self.model_info else "", + "model": self.model_info.model if self.model_info else "", + "model_id": ( + str(self.model_info.model_id or "") if self.model_info else "" + ), + "hw_version": ( + str(self.model_info.hw_version or "") if self.model_info else "" + ), + }, + data_schema=data_schema, + errors=errors, + ) #TODO: Change this to be sub entry options flow # class OptionsFlowHandler(OptionsFlow): @@ -969,3 +1068,23 @@ async def async_step_reconfigure( # self.current_config, # ) +def _fill_schema_defaults( + data_schema: vol.Schema, + options: dict[str, Any], +) -> vol.Schema: + """Make a copy of the schema with suggested values set to saved options.""" + schema = {} + for key, val in data_schema.schema.items(): + new_key = key + if key in options and isinstance(key, vol.Marker): + if ( + isinstance(key, vol.Optional) + and callable(key.default) + and key.default() + ): + new_key = vol.Optional(key.schema, default=options.get(key)) # type: ignore + else: + new_key = copy.copy(key) + new_key.description = {"suggested_value": options.get(key)} # type: ignore + schema[new_key] = val + return vol.Schema(schema) \ No newline at end of file diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 12f4518f2..2ae8bf237 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -83,6 +83,23 @@ "manual": { "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", "title": "Device manual configuration" + }, + "reconfigure": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "name": "Name", + "battery_type": "Battery type", + "battery_quantity": "Battery quantity", + "battery_low_threshold": "Battery low threshold", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Leaving blank will take the name from the source device", + "battery_low_threshold": "0 will use the global default threshold", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } } }, "abort": { @@ -90,7 +107,8 @@ }, "error": { "unknown": "Unknown error occurred.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." + "unconfigurable_entity": "It is not possible to add this entity to Battery Notes.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." } } }, From 6c9cdeb185f35974fd3ad22b143e92a4303115f1 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 2 Aug 2025 17:18:12 +0000 Subject: [PATCH 029/235] Fix template in reconfigure --- .../battery_notes/config_flow.py | 67 +++++++++++++------ 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index cbdbaa147..501a282fa 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -805,7 +805,7 @@ async def async_step_reconfigure( self.data[CONF_BATTERY_LOW_THRESHOLD] = int( user_input[CONF_BATTERY_LOW_THRESHOLD] ) - if user_input[CONF_BATTERY_LOW_TEMPLATE] == "": + if user_input.get(CONF_BATTERY_LOW_TEMPLATE, "") == "": self.data[CONF_BATTERY_LOW_TEMPLATE] = None else: self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input[CONF_BATTERY_LOW_TEMPLATE] @@ -858,28 +858,53 @@ async def async_step_reconfigure( device_entry.hw_version, ) - data_schema = vol.Schema( - { - vol.Optional(CONF_NAME, default=config_entry.title): selector.TextSelector( - selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), - ), - vol.Required(CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE]): selector.TextSelector( - selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), - ), - vol.Required(CONF_BATTERY_QUANTITY, default=self.data[CONF_BATTERY_QUANTITY]): selector.NumberSelector( - selector.NumberSelectorConfig( - min=1, max=100, mode=selector.NumberSelectorMode.BOX + if self.data.get(CONF_BATTERY_LOW_TEMPLATE, None) is None: + data_schema = vol.Schema( + { + vol.Optional(CONF_NAME, default=config_entry.title): selector.TextSelector( + selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), ), - ), - vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data[CONF_BATTERY_LOW_THRESHOLD]): selector.NumberSelector( - selector.NumberSelectorConfig( - min=0, max=99, mode=selector.NumberSelectorMode.BOX + vol.Required(CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE]): selector.TextSelector( + selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), ), - ), - vol.Optional(CONF_BATTERY_LOW_TEMPLATE, default=self.data.get(CONF_BATTERY_LOW_TEMPLATE, "")): selector.TemplateSelector(), - vol.Optional(CONF_FILTER_OUTLIERS, default=self.data.get(CONF_FILTER_OUTLIERS, False)): selector.BooleanSelector(), - } - ) + vol.Required(CONF_BATTERY_QUANTITY, default=self.data[CONF_BATTERY_QUANTITY]): selector.NumberSelector( + selector.NumberSelectorConfig( + min=1, max=100, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data[CONF_BATTERY_LOW_THRESHOLD]): selector.NumberSelector( + selector.NumberSelectorConfig( + min=0, max=99, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Optional(CONF_BATTERY_LOW_TEMPLATE): selector.TemplateSelector(), + vol.Optional(CONF_FILTER_OUTLIERS, default=self.data.get(CONF_FILTER_OUTLIERS, False)): selector.BooleanSelector(), + } + ) + else: + data_schema = vol.Schema( + { + vol.Optional(CONF_NAME, default=config_entry.title): selector.TextSelector( + selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), + ), + vol.Required(CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE]): selector.TextSelector( + selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), + ), + vol.Required(CONF_BATTERY_QUANTITY, default=self.data[CONF_BATTERY_QUANTITY]): selector.NumberSelector( + selector.NumberSelectorConfig( + min=1, max=100, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data[CONF_BATTERY_LOW_THRESHOLD]): selector.NumberSelector( + selector.NumberSelectorConfig( + min=0, max=99, mode=selector.NumberSelectorMode.BOX + ), + ), + vol.Optional(CONF_BATTERY_LOW_TEMPLATE, default=self.data.get(CONF_BATTERY_LOW_TEMPLATE, None)): selector.TemplateSelector(), + vol.Optional(CONF_FILTER_OUTLIERS, default=self.data.get(CONF_FILTER_OUTLIERS, False)): selector.BooleanSelector(), + } + ) + return self.async_show_form( step_id="reconfigure", From 09ab9d19bd086881897c148e2e18abf1690edbb8 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 3 Aug 2025 09:01:10 +0000 Subject: [PATCH 030/235] Discovery sub entry check --- custom_components/battery_notes/config_flow.py | 9 +++++++-- custom_components/battery_notes/translations/en.json | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 501a282fa..baf07de5b 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -192,8 +192,13 @@ async def async_step_integration_discovery( _LOGGER.debug("Starting discovery flow: %s", discovery_info) unique_id = f"bn_{discovery_info[CONF_DEVICE_ID]}" - await self.async_set_unique_id(unique_id) - self._abort_if_unique_id_configured() + + # Check if unique_id already exists as sub entry + config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] + for existing_subentry in config_entry.subentries.values(): + if existing_subentry.unique_id == unique_id: + _LOGGER.debug("Subentry with unique_id %s already exists", unique_id) + return self.async_abort(reason="already_configured") self.context["title_placeholders"] = { "name": discovery_info[CONF_DEVICE_NAME], diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 2ae8bf237..3b1175a3f 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -22,7 +22,8 @@ } }, "abort": { - "already_configured": "Integration is already configured" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { "unknown": "Unknown error occurred." From 2a9450ce213f820ab00c9dd35242ebe193d18be9 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 3 Aug 2025 09:05:08 +0000 Subject: [PATCH 031/235] Tidy up old code within config_flow --- .../battery_notes/config_flow.py | 216 +----------------- 1 file changed, 2 insertions(+), 214 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index baf07de5b..74e14c068 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -2,7 +2,6 @@ from __future__ import annotations -import copy import logging from typing import Any @@ -13,11 +12,8 @@ from homeassistant.components.sensor.const import SensorDeviceClass from homeassistant.config_entries import ( ConfigEntry, - ConfigEntryState, - ConfigFlow, ConfigFlowResult, ConfigSubentry, - ConfigSubentryData, ConfigSubentryFlow, OptionsFlow, SubentryFlowResult, @@ -28,16 +24,9 @@ Platform, ) from homeassistant.core import callback, split_entity_id -from homeassistant.data_entry_flow import AbortFlow, FlowResultType, section +from homeassistant.data_entry_flow import section from homeassistant.helpers import selector from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue -from homeassistant.helpers.selector import ( - SelectSelector, - SelectSelectorConfig, - TextSelector, - TextSelectorConfig, - TextSelectorType, -) from homeassistant.helpers.typing import DiscoveryInfoType from .common import get_device_model_id @@ -403,21 +392,12 @@ async def async_step_battery( assert device_entry title = device_entry.name_by_user or device_entry.name - # return self.async_create_entry( - # title=str(title), - # data=self.data, - # ) - - config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] + # Create a subentry subentry = ConfigSubentry(subentry_type="battery_note", data=self.data, title=str(title), unique_id=unique_id) self.hass.config_entries.async_add_subentry(config_entry, subentry) - # config_flow_result: ConfigFlowResult = await self.async_step_user( - # discovered_data - # ) - return self.async_abort(reason="created_sub_entry") return self.async_show_form( @@ -926,195 +906,3 @@ async def async_step_reconfigure( data_schema=data_schema, errors=errors, ) - -#TODO: Change this to be sub entry options flow -# class OptionsFlowHandler(OptionsFlow): -# """Handle an option flow for BatteryNotes.""" - -# model_info: ModelInfo | None = None - -# def __init__(self) -> None: -# """Initialize options flow.""" -# self.current_config: dict -# self.source_device_id: str -# self.name: str -# self.battery_type: str -# self.battery_quantity: int -# self.battery_low_template: str -# self.filter_outliers: bool - -# async def async_step_init( -# self, -# user_input: dict[str, Any] | None = None, -# ) -> ConfigFlowResult: -# """Handle options flow.""" -# errors = {} -# self.current_config = dict(self.config_entry.data) -# self.source_device_id = self.current_config.get(CONF_DEVICE_ID) # type: ignore -# self.name = str(self.current_config.get(CONF_NAME) or "") -# self.battery_type = str(self.current_config.get(CONF_BATTERY_TYPE) or "") -# self.battery_quantity = int(self.current_config.get(CONF_BATTERY_QUANTITY) or 1) -# self.battery_low_template = str( -# self.current_config.get(CONF_BATTERY_LOW_TEMPLATE) or "" -# ) -# self.filter_outliers = bool( -# self.current_config.get(CONF_FILTER_OUTLIERS) or False -# ) - -# if self.source_device_id: -# device_registry = dr.async_get(self.hass) -# device_entry = device_registry.async_get(self.source_device_id) - -# if not device_entry: -# errors["base"] = "orphaned_battery_note" -# else: -# if device_entry and device_entry.manufacturer and device_entry.model: -# _LOGGER.debug( -# "Looking up device %s %s %s %s", -# device_entry.manufacturer, -# device_entry.model, -# get_device_model_id(device_entry) or "", -# device_entry.hw_version, -# ) - -# self.model_info = ModelInfo( -# device_entry.manufacturer, -# device_entry.model, -# get_device_model_id(device_entry), -# device_entry.hw_version, -# ) - -# schema = self.build_options_schema() -# if user_input is not None: -# user_input[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) -# user_input[CONF_BATTERY_LOW_THRESHOLD] = int( -# user_input[CONF_BATTERY_LOW_THRESHOLD] -# ) -# # user_input[CONF_BATTERY_LOW_TEMPLATE] = user_input.get(CONF_BATTERY_LOW_TEMPLATE, None) -# errors = await self.save_options(user_input, schema) -# if not errors: -# return self.async_create_entry(title="", data={}) - -# return self.async_show_form( -# step_id="init", -# description_placeholders={ -# "manufacturer": self.model_info.manufacturer if self.model_info else "", -# "model": self.model_info.model if self.model_info else "", -# "model_id": ( -# str(self.model_info.model_id or "") if self.model_info else "" -# ), -# "hw_version": ( -# str(self.model_info.hw_version or "") if self.model_info else "" -# ), -# }, -# data_schema=schema, -# errors=errors, -# ) - -# async def save_options( -# self, -# user_input: dict[str, Any], -# schema: vol.Schema, -# ) -> dict: -# """Save options, and return errors when validation fails.""" -# errors = {} - -# device_registry = dr.async_get(self.hass) -# device_entry = device_registry.async_get( -# str(self.config_entry.data.get(CONF_DEVICE_ID)) -# ) - -# source_entity_id = self.config_entry.data.get(CONF_SOURCE_ENTITY_ID, None) - -# entity_entry: er.RegistryEntry | None = None -# if source_entity_id: -# entity_registry = er.async_get(self.hass) -# entity_entry = entity_registry.async_get(source_entity_id) -# if not entity_entry: -# errors["base"] = "orphaned_battery_note" -# return errors -# else: -# if not device_entry: -# errors["base"] = "orphaned_battery_note" -# return errors - -# title: Any = "" -# if CONF_NAME in user_input: -# title = user_input.get(CONF_NAME) -# elif source_entity_id and entity_entry: -# title = entity_entry.name or entity_entry.original_name -# elif device_entry: -# title = device_entry.name_by_user or device_entry.name - -# self._process_user_input(user_input, schema) -# self.hass.config_entries.async_update_entry( -# self.config_entry, -# title=title, -# data=self.current_config, -# ) -# return {} - -# def _process_user_input( -# self, -# user_input: dict[str, Any], -# schema: vol.Schema, -# ) -> None: -# """Process the provided user input against the schema.""" -# for key in schema.schema: -# if isinstance(key, vol.Marker): -# key = key.schema -# if key in user_input: -# self.current_config[key] = user_input.get(key) -# elif key in self.current_config: -# self.current_config.pop(key) - -# def build_options_schema(self) -> vol.Schema: -# """Build the options schema.""" -# data_schema = vol.Schema( -# { -# vol.Optional(CONF_NAME): selector.TextSelector( -# selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), -# ), -# vol.Required(CONF_BATTERY_TYPE): selector.TextSelector( -# selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), -# ), -# vol.Required(CONF_BATTERY_QUANTITY): selector.NumberSelector( -# selector.NumberSelectorConfig( -# min=1, max=100, mode=selector.NumberSelectorMode.BOX -# ), -# ), -# vol.Required(CONF_BATTERY_LOW_THRESHOLD): selector.NumberSelector( -# selector.NumberSelectorConfig( -# min=0, max=99, mode=selector.NumberSelectorMode.BOX -# ), -# ), -# vol.Optional(CONF_BATTERY_LOW_TEMPLATE): selector.TemplateSelector(), -# vol.Optional(CONF_FILTER_OUTLIERS): selector.BooleanSelector(), -# } -# ) - -# return _fill_schema_defaults( -# data_schema, -# self.current_config, -# ) - -def _fill_schema_defaults( - data_schema: vol.Schema, - options: dict[str, Any], -) -> vol.Schema: - """Make a copy of the schema with suggested values set to saved options.""" - schema = {} - for key, val in data_schema.schema.items(): - new_key = key - if key in options and isinstance(key, vol.Marker): - if ( - isinstance(key, vol.Optional) - and callable(key.default) - and key.default() - ): - new_key = vol.Optional(key.schema, default=options.get(key)) # type: ignore - else: - new_key = copy.copy(key) - new_key.description = {"suggested_value": options.get(key)} # type: ignore - schema[new_key] = val - return vol.Schema(schema) \ No newline at end of file From 39c1e51da460acc4a6c425c7cdebdfcbc70a0d6a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 3 Aug 2025 09:16:09 +0000 Subject: [PATCH 032/235] WIP --- custom_components/battery_notes/__init__.py | 2 +- custom_components/battery_notes/coordinator.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 293f507c0..7651a24ed 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -173,7 +173,7 @@ async def async_setup_entry( # for subentry in config_entry.subentries.values(): # if subentry.subentry_type == "battery_note": # #TODO: Change coordinator to take subentry data - # coordinator = BatteryNotesCoordinator(hass, config_entry) + # coordinator = BatteryNotesCoordinator(hass, config_entry, subentry) # config_entry.runtime_data.coordinator = coordinator # config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index dab877fca..ca210704f 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -11,7 +11,7 @@ from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import SensorDeviceClass -from homeassistant.config_entries import ConfigEntry +from homeassistant.config_entries import ConfigEntry, ConfigSubentry from homeassistant.const import ( CONF_DEVICE_ID, PERCENTAGE, @@ -116,6 +116,7 @@ def __init__( self, hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, + subentry: ConfigSubentry ): """Initialize.""" super().__init__(hass, _LOGGER, config_entry=config_entry, name=DOMAIN) @@ -123,6 +124,7 @@ def __init__( self.reset_jobs: list[CALLBACK_TYPE] = [] self.config_entry = config_entry + self.subentry = subentry self.device_id = config_entry.data.get(CONF_DEVICE_ID, None) self.source_entity_id = config_entry.data.get(CONF_SOURCE_ENTITY_ID, None) From bc3ae37af31a781b38479a56701b149c7361546d Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 3 Aug 2025 14:54:21 +0000 Subject: [PATCH 033/235] WIP --- custom_components/battery_notes/__init__.py | 26 ++- .../battery_notes/binary_sensor.py | 3 +- custom_components/battery_notes/button.py | 1 + .../battery_notes/coordinator.py | 46 ++--- custom_components/battery_notes/sensor.py | 177 +++++++++--------- custom_components/battery_notes/services.yaml | 2 - 6 files changed, 133 insertions(+), 122 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 7651a24ed..bc7adda3c 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,13 +8,14 @@ import logging import re -from typing import Any +from typing import Any, Final import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import ( CONF_SOURCE, + Platform, ) from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback @@ -169,17 +170,22 @@ async def async_setup_entry( store=domain_config.store, ) - #TODO: Get this working - # for subentry in config_entry.subentries.values(): - # if subentry.subentry_type == "battery_note": - # #TODO: Change coordinator to take subentry data - # coordinator = BatteryNotesCoordinator(hass, config_entry, subentry) - # config_entry.runtime_data.coordinator = coordinator - # config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator - + # TODO: Get this working + config_entry.runtime_data.subentry_coordinators = {} + for subentry in config_entry.subentries.values(): + if subentry.subentry_type == "battery_note": + coordinator = BatteryNotesCoordinator(hass, config_entry, subentry) + config_entry.runtime_data.coordinator = coordinator + config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator + + #TODO: Change back to real platforms once all completed + TEMP_PLATFORMS: Final = [ + Platform.SENSOR, + ] + await hass.config_entries.async_forward_entry_setups(config_entry, TEMP_PLATFORMS) # await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) - # config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) + config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) if domain_config.enable_autodiscovery: discovery_manager = DiscoveryManager(hass, domain_config) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index e78168141..a8bf1642a 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -133,7 +133,6 @@ async def async_setup_entry( entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) - device_id = config_entry.data.get(CONF_DEVICE_ID) async def async_registry_updated( event: Event[er.EventEntityRegistryUpdatedData], @@ -165,11 +164,13 @@ async def async_registry_updated( device_id, remove_config_entry_id=config_entry.entry_id ) + device_id = config_entry.data.get(CONF_DEVICE_ID) coordinator = config_entry.runtime_data.coordinator assert(coordinator) config_entry.async_on_unload( async_track_entity_registry_updated_event( + #TODO: This doesnt look right, should be entity_id hass, config_entry.entry_id, async_registry_updated ) ) diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index e7d523d56..bba0afbba 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -132,6 +132,7 @@ async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData] config_entry.async_on_unload( async_track_entity_registry_updated_event( + #TODO: This doesnt look right, should be entity_id hass, config_entry.entry_id, async_registry_updated ) ) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index ca210704f..807bb0f5f 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -86,7 +86,7 @@ class BatteryNotesData: domain_config: BatteryNotesDomainConfig store: BatteryNotesStorage coordinator: BatteryNotesCoordinator | None = None - subentry_coordinators: dict[str, BatteryNotesCoordinator] = None + subentry_coordinators: dict[str, BatteryNotesCoordinator] | None = None class BatteryNotesCoordinator(DataUpdateCoordinator[None]): @@ -126,34 +126,34 @@ def __init__( self.config_entry = config_entry self.subentry = subentry - self.device_id = config_entry.data.get(CONF_DEVICE_ID, None) - self.source_entity_id = config_entry.data.get(CONF_SOURCE_ENTITY_ID, None) + self.device_id = self.subentry.data.get(CONF_DEVICE_ID, None) + self.source_entity_id = self.subentry.data.get(CONF_SOURCE_ENTITY_ID, None) self._link_device() assert(self.device_name) - self.battery_type = cast(str, self.config_entry.data.get(CONF_BATTERY_TYPE)) + self.battery_type = cast(str, self.subentry.data.get(CONF_BATTERY_TYPE)) try: self.battery_quantity = cast( - int, self.config_entry.data.get(CONF_BATTERY_QUANTITY) + int, self.subentry.data.get(CONF_BATTERY_QUANTITY) ) except ValueError: self.battery_quantity = 1 self.battery_low_threshold = int( - self.config_entry.data.get(CONF_BATTERY_LOW_THRESHOLD, 0) + self.subentry.data.get(CONF_BATTERY_LOW_THRESHOLD, 0) ) if hasattr(self.config_entry, "runtime_data"): if self.battery_low_threshold == 0: self.battery_low_threshold = self.config_entry.runtime_data.domain_config.default_battery_low_threshold - self.battery_low_template = self.config_entry.data.get( + self.battery_low_template = self.subentry.data.get( CONF_BATTERY_LOW_TEMPLATE ) - if config_entry.data.get(CONF_FILTER_OUTLIERS, False): + if self.subentry.data.get(CONF_FILTER_OUTLIERS, False): self._outlier_filter = LowOutlierFilter(window_size=3, radius=80) _LOGGER.debug("Outlier filter enabled") @@ -212,9 +212,9 @@ def _link_device(self) -> bool: ir.async_create_issue( self.hass, DOMAIN, - f"missing_device_{self.config_entry.entry_id}", + f"missing_device_{self.subentry.subentry_id}", data={ - "entry_id": self.config_entry.entry_id, + "entry_id": self.subentry.subentry_id, "device_id": self.device_id, "source_entity_id": self.source_entity_id, }, @@ -222,13 +222,13 @@ def _link_device(self) -> bool: severity=ir.IssueSeverity.WARNING, translation_key="missing_device", translation_placeholders={ - "name": self.config_entry.title, + "name": self.subentry.title, }, ) _LOGGER.warning( "%s is orphaned, unable to find entity %s", - self.config_entry.entry_id, + self.subentry.subentry_id, self.source_entity_id, ) return False @@ -253,12 +253,12 @@ def _link_device(self) -> bool: self.device_name = ( device_entry.name_by_user or device_entry.name - or self.config_entry.title + or self.subentry.title ) else: - self.device_name = self.config_entry.title + self.device_name = self.subentry.title else: - self.device_name = self.config_entry.title + self.device_name = self.subentry.title else: for entity in entity_registry.entities.values(): @@ -299,17 +299,17 @@ def _link_device(self) -> bool: device_entry = device_registry.async_get(self.device_id) if device_entry: self.device_name = ( - device_entry.name_by_user or device_entry.name or self.config_entry.title + device_entry.name_by_user or device_entry.name or self.subentry.title ) else: - self.device_name = self.config_entry.title + self.device_name = self.subentry.title ir.async_create_issue( self.hass, DOMAIN, - f"missing_device_{self.config_entry.entry_id}", + f"missing_device_{self.subentry.subentry_id}", data={ - "entry_id": self.config_entry.entry_id, + "entry_id": self.subentry.subentry_id, "device_id": self.device_id, "source_entity_id": self.source_entity_id, }, @@ -317,13 +317,13 @@ def _link_device(self) -> bool: severity=ir.IssueSeverity.WARNING, translation_key="missing_device", translation_placeholders={ - "name": self.config_entry.title, + "name": self.subentry.title, }, ) _LOGGER.warning( "%s is orphaned, unable to find device %s", - self.config_entry.entry_id, + self.subentry.subentry_id, self.device_id, ) return False @@ -333,8 +333,8 @@ def _link_device(self) -> bool: @property def fake_device(self) -> bool: """Return if an actual device registry entry.""" - if self.config_entry.data.get(CONF_SOURCE_ENTITY_ID, None): - if self.config_entry.data.get(CONF_DEVICE_ID, None) is None: + if self.subentry.data.get(CONF_SOURCE_ENTITY_ID, None): + if self.subentry.data.get(CONF_DEVICE_ID, None) is None: return True return False diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 8c2242e2a..7ad3609a2 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -126,110 +126,115 @@ async def async_setup_entry( entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) - device_id = config_entry.data.get(CONF_DEVICE_ID, None) + for subentry in config_entry.subentries.values(): + if subentry.subentry_type != "battery_note": + continue - async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData]) -> None: - """Handle entity registry update.""" - data = event.data - if data["action"] == "remove": - await hass.config_entries.async_remove(config_entry.entry_id) + device_id = subentry.data.get(CONF_DEVICE_ID, None) - if data["action"] != "update": - return + coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) + assert(coordinator) - if "entity_id" in data["changes"]: - # Entity_id replaced, reload the config entry - await hass.config_entries.async_reload(config_entry.entry_id) + if not coordinator.fake_device: + device_id = async_add_to_device(hass, config_entry) - if device_id and "device_id" in data["changes"]: - # If the tracked battery note is no longer in the device, remove our config entry - # from the device - if ( - not (entity_entry := entity_registry.async_get(data["entity_id"])) - or not device_registry.async_get(device_id) - or entity_entry.device_id == device_id - ): - # No need to do any cleanup + if not device_id: return - device_registry.async_update_device( - device_id, remove_config_entry_id=config_entry.entry_id - ) - - config_entry.async_on_unload( - async_track_entity_registry_updated_event( - hass, config_entry.entry_id, async_registry_updated - ) - ) + await coordinator.async_refresh() - coordinator = config_entry.runtime_data.coordinator - assert(coordinator) + domain_config = hass.data[MY_KEY] - if not coordinator.fake_device: - device_id = async_add_to_device(hass, config_entry) + battery_plus_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="_battery_plus", + key="battery_plus", + translation_key="battery_plus", + device_class=SensorDeviceClass.BATTERY, + suggested_display_precision=0 if domain_config.round_battery else 1, + ) - if not device_id: - return + type_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix + key="battery_type", + translation_key="battery_type", + entity_category=EntityCategory.DIAGNOSTIC, + ) - await coordinator.async_refresh() + last_replaced_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="_battery_last_replaced", + key="battery_last_replaced", + translation_key="battery_last_replaced", + entity_category=EntityCategory.DIAGNOSTIC, + device_class=SensorDeviceClass.TIMESTAMP, + entity_registry_enabled_default=domain_config.enable_replaced, + ) - domain_config = hass.data[MY_KEY] + entities = [ + BatteryNotesTypeSensor( + hass, + config_entry, + coordinator, + type_sensor_entity_description, + f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", + ), + BatteryNotesLastReplacedSensor( + hass, + config_entry, + coordinator, + last_replaced_sensor_entity_description, + f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", + ), + ] + + if coordinator.wrapped_battery is not None: + entities.append( + BatteryNotesBatteryPlusSensor( + hass, + config_entry, + coordinator, + battery_plus_sensor_entity_description, + f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", + domain_config.enable_replaced, + domain_config.round_battery, + ) + ) - battery_plus_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="_battery_plus", - key="battery_plus", - translation_key="battery_plus", - device_class=SensorDeviceClass.BATTERY, - suggested_display_precision=0 if domain_config.round_battery else 1, - ) + async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData]) -> None: + """Handle entity registry update.""" + data = event.data + if data["action"] == "remove": + await hass.config_entries.async_remove(config_entry.entry_id) - type_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix - key="battery_type", - translation_key="battery_type", - entity_category=EntityCategory.DIAGNOSTIC, - ) + if data["action"] != "update": + return - last_replaced_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="_battery_last_replaced", - key="battery_last_replaced", - translation_key="battery_last_replaced", - entity_category=EntityCategory.DIAGNOSTIC, - device_class=SensorDeviceClass.TIMESTAMP, - entity_registry_enabled_default=domain_config.enable_replaced, - ) + if "entity_id" in data["changes"]: + # Entity_id replaced, reload the config entry + await hass.config_entries.async_reload(config_entry.entry_id) + + if device_id and "device_id" in data["changes"]: + # If the tracked battery note is no longer in the device, remove our config entry + # from the device + if ( + not (entity_entry := entity_registry.async_get(data["entity_id"])) + or not device_registry.async_get(device_id) + or entity_entry.device_id == device_id + ): + # No need to do any cleanup + return + + device_registry.async_update_device( + device_id, remove_config_entry_id=config_entry.entry_id + ) - entities = [ - BatteryNotesTypeSensor( - hass, - config_entry, - coordinator, - type_sensor_entity_description, - f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", - ), - BatteryNotesLastReplacedSensor( - hass, - config_entry, - coordinator, - last_replaced_sensor_entity_description, - f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", - ), - ] - - if coordinator.wrapped_battery is not None: - entities.append( - BatteryNotesBatteryPlusSensor( - hass, - config_entry, - coordinator, - battery_plus_sensor_entity_description, - f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", - domain_config.enable_replaced, - domain_config.round_battery, + config_entry.async_on_unload( + async_track_entity_registry_updated_event( + #TODO: This doesnt look right, should be entity_id + hass, config_entry.entry_id, async_registry_updated ) ) - async_add_entities(entities) + async_add_entities(entities) async def async_setup_platform( diff --git a/custom_components/battery_notes/services.yaml b/custom_components/battery_notes/services.yaml index a8ea6e709..ae24c7973 100644 --- a/custom_components/battery_notes/services.yaml +++ b/custom_components/battery_notes/services.yaml @@ -8,8 +8,6 @@ set_battery_replaced: required: false selector: device: - filter: - - integration: battery_notes source_entity_id: name: Entity description: "Entity that has had its battery replaced (only used for entity associated battery notes)." From ff2db834f169da1f1577ca78b11587172a491a26 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 3 Aug 2025 17:09:31 +0000 Subject: [PATCH 034/235] WIP --- custom_components/battery_notes/__init__.py | 3 +- custom_components/battery_notes/sensor.py | 222 +++++++++++--------- 2 files changed, 129 insertions(+), 96 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index bc7adda3c..bf0147240 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -12,7 +12,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigSubentry from homeassistant.const import ( CONF_SOURCE, Platform, @@ -175,7 +175,6 @@ async def async_setup_entry( for subentry in config_entry.subentries.values(): if subentry.subentry_type == "battery_note": coordinator = BatteryNotesCoordinator(hass, config_entry, subentry) - config_entry.runtime_data.coordinator = coordinator config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator #TODO: Change back to real platforms once all completed diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 7ad3609a2..dfbe34473 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -17,7 +17,7 @@ SensorEntityDescription, SensorStateClass, ) -from homeassistant.config_entries import ConfigEntry +from homeassistant.config_entries import ConfigEntry, ConfigSubentry from homeassistant.const import ( CONF_DEVICE_ID, CONF_NAME, @@ -35,6 +35,10 @@ from homeassistant.helpers import ( entity_registry as er, ) +from homeassistant.helpers.device import ( + async_entity_id_to_device_id, + async_remove_stale_devices_links_keep_entity_device, +) from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_registry import ( @@ -102,11 +106,11 @@ class BatteryNotesSensorEntityDescription( @callback -def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry) -> str | None: +def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry, subentry: ConfigSubentry) -> str | None: """Add our config entry to the device.""" device_registry = dr.async_get(hass) - device_id = entry.data.get(CONF_DEVICE_ID) + device_id = subentry.data.get(CONF_DEVICE_ID) if device_id: if device_registry.async_get(device_id): @@ -129,112 +133,125 @@ async def async_setup_entry( for subentry in config_entry.subentries.values(): if subentry.subentry_type != "battery_note": continue + await _setup_battery_note_subentry(hass, config_entry, subentry, async_add_entities) - device_id = subentry.data.get(CONF_DEVICE_ID, None) +async def _setup_battery_note_subentry( + hass: HomeAssistant, + config_entry: BatteryNotesConfigEntry, + subentry: ConfigSubentry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up a battery_note subentry.""" + entity_registry = er.async_get(hass) + device_registry = dr.async_get(hass) - coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) - assert(coordinator) + device_id = subentry.data.get(CONF_DEVICE_ID, None) - if not coordinator.fake_device: - device_id = async_add_to_device(hass, config_entry) + coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) + assert(coordinator) - if not device_id: - return + if not coordinator.fake_device: + device_id = async_add_to_device(hass, config_entry, subentry) - await coordinator.async_refresh() + if not device_id: + return - domain_config = hass.data[MY_KEY] + await coordinator.async_refresh() - battery_plus_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="_battery_plus", - key="battery_plus", - translation_key="battery_plus", - device_class=SensorDeviceClass.BATTERY, - suggested_display_precision=0 if domain_config.round_battery else 1, - ) + domain_config = hass.data[MY_KEY] - type_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix - key="battery_type", - translation_key="battery_type", - entity_category=EntityCategory.DIAGNOSTIC, - ) + battery_plus_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="_battery_plus", + key="battery_plus", + translation_key="battery_plus", + device_class=SensorDeviceClass.BATTERY, + suggested_display_precision=0 if domain_config.round_battery else 1, + ) - last_replaced_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="_battery_last_replaced", - key="battery_last_replaced", - translation_key="battery_last_replaced", - entity_category=EntityCategory.DIAGNOSTIC, - device_class=SensorDeviceClass.TIMESTAMP, - entity_registry_enabled_default=domain_config.enable_replaced, - ) + type_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix + key="battery_type", + translation_key="battery_type", + entity_category=EntityCategory.DIAGNOSTIC, + ) - entities = [ - BatteryNotesTypeSensor( - hass, - config_entry, - coordinator, - type_sensor_entity_description, - f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", - ), - BatteryNotesLastReplacedSensor( + last_replaced_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="_battery_last_replaced", + key="battery_last_replaced", + translation_key="battery_last_replaced", + entity_category=EntityCategory.DIAGNOSTIC, + device_class=SensorDeviceClass.TIMESTAMP, + entity_registry_enabled_default=domain_config.enable_replaced, + ) + + entities = [] + # entities = [ + # BatteryNotesTypeSensor( + # hass, + # config_entry, + # coordinator, + # type_sensor_entity_description, + # f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", + # ), + # BatteryNotesLastReplacedSensor( + # hass, + # config_entry, + # coordinator, + # last_replaced_sensor_entity_description, + # f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", + # ), + # ] + + if coordinator.wrapped_battery is not None: + entities.append( + BatteryNotesBatteryPlusSensor( hass, config_entry, + subentry, coordinator, - last_replaced_sensor_entity_description, - f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", - ), - ] - - if coordinator.wrapped_battery is not None: - entities.append( - BatteryNotesBatteryPlusSensor( - hass, - config_entry, - coordinator, - battery_plus_sensor_entity_description, - f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", - domain_config.enable_replaced, - domain_config.round_battery, - ) + battery_plus_sensor_entity_description, + f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", + domain_config.enable_replaced, + domain_config.round_battery, ) + ) - async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData]) -> None: - """Handle entity registry update.""" - data = event.data - if data["action"] == "remove": - await hass.config_entries.async_remove(config_entry.entry_id) + async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData]) -> None: + """Handle entity registry update.""" + data = event.data + if data["action"] == "remove": + await hass.config_entries.async_remove(config_entry.entry_id) - if data["action"] != "update": - return + if data["action"] != "update": + return - if "entity_id" in data["changes"]: - # Entity_id replaced, reload the config entry - await hass.config_entries.async_reload(config_entry.entry_id) - - if device_id and "device_id" in data["changes"]: - # If the tracked battery note is no longer in the device, remove our config entry - # from the device - if ( - not (entity_entry := entity_registry.async_get(data["entity_id"])) - or not device_registry.async_get(device_id) - or entity_entry.device_id == device_id - ): - # No need to do any cleanup - return - - device_registry.async_update_device( - device_id, remove_config_entry_id=config_entry.entry_id - ) + if "entity_id" in data["changes"]: + # Entity_id replaced, reload the config entry + await hass.config_entries.async_reload(config_entry.entry_id) + + if device_id and "device_id" in data["changes"]: + # If the tracked battery note is no longer in the device, remove our config entry + # from the device + if ( + not (entity_entry := entity_registry.async_get(data["entity_id"])) + or not device_registry.async_get(device_id) + or entity_entry.device_id == device_id + ): + # No need to do any cleanup + return - config_entry.async_on_unload( - async_track_entity_registry_updated_event( - #TODO: This doesnt look right, should be entity_id - hass, config_entry.entry_id, async_registry_updated + device_registry.async_update_device( + device_id, remove_config_entry_id=config_entry.entry_id ) + + config_entry.async_on_unload( + async_track_entity_registry_updated_event( + #TODO: This doesnt look right, should be entity_id + hass, config_entry.entry_id, async_registry_updated ) + ) - async_add_entities(entities) + async_add_entities(entities) async def async_setup_platform( @@ -272,6 +289,7 @@ def __init__( self, hass: HomeAssistant, config_entry: ConfigEntry, + subentry: ConfigSubentry, coordinator: BatteryNotesCoordinator, description: BatteryNotesSensorEntityDescription, unique_id: str, @@ -284,8 +302,11 @@ def __init__( device_registry = dr.async_get(hass) self.config_entry = config_entry + self.subentry = subentry self.coordinator = coordinator + self.subentry_id = subentry.subentry_id + self._attr_has_entity_name = True if coordinator.source_entity_id and not coordinator.device_id: @@ -317,13 +338,26 @@ def __init__( self._device_id = coordinator.device_id self._source_entity_id = coordinator.source_entity_id - if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) - ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, + # if coordinator.device_id and ( + # device_entry := device_registry.async_get(coordinator.device_id) + # ): + # self._attr_device_info = DeviceInfo( + # connections=device_entry.connections, + # identifiers=device_entry.identifiers, + # ) + + if self.coordinator.device_id: + #TODO: Get this working, by getting any entity of the device and using it + self.device_entry = async_entity_id_to_device_id( + hass, + coordinator.source_entity_id, ) + else: + self.device_entry = async_entity_id_to_device_id( + hass, + coordinator.source_entity_id, + ) + entity_category = ( coordinator.wrapped_battery.entity_category if coordinator.wrapped_battery else None From 383dc37a963bd0762c07e4e668599aff626bb37b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 4 Aug 2025 09:20:48 +0100 Subject: [PATCH 035/235] WIP --- custom_components/battery_notes/__init__.py | 12 +- custom_components/battery_notes/const.py | 5 +- custom_components/battery_notes/sensor.py | 291 +++++++++----------- 3 files changed, 142 insertions(+), 166 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index bf0147240..7a2e61770 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -13,10 +13,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigSubentry -from homeassistant.const import ( - CONF_SOURCE, - Platform, -) +from homeassistant.const import CONF_SOURCE from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv @@ -177,12 +174,7 @@ async def async_setup_entry( coordinator = BatteryNotesCoordinator(hass, config_entry, subentry) config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator - #TODO: Change back to real platforms once all completed - TEMP_PLATFORMS: Final = [ - Platform.SENSOR, - ] - await hass.config_entries.async_forward_entry_setups(config_entry, TEMP_PLATFORMS) - # await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) + await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index ec19adaf5..1b6e66056 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -108,8 +108,9 @@ } ) +#TODO: Change back to all platforms once all completed PLATFORMS: Final = [ Platform.BUTTON, - Platform.SENSOR, - Platform.BINARY_SENSOR, + # Platform.SENSOR, + # Platform.BINARY_SENSOR, ] diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index dfbe34473..b82bd7d45 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -185,36 +185,36 @@ async def _setup_battery_note_subentry( ) entities = [] - # entities = [ - # BatteryNotesTypeSensor( - # hass, - # config_entry, - # coordinator, - # type_sensor_entity_description, - # f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", - # ), - # BatteryNotesLastReplacedSensor( - # hass, - # config_entry, - # coordinator, - # last_replaced_sensor_entity_description, - # f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", - # ), - # ] - - if coordinator.wrapped_battery is not None: - entities.append( - BatteryNotesBatteryPlusSensor( - hass, - config_entry, - subentry, - coordinator, - battery_plus_sensor_entity_description, - f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", - domain_config.enable_replaced, - domain_config.round_battery, - ) - ) + entities = [ + BatteryNotesTypeSensor( + hass, + config_entry, + coordinator, + type_sensor_entity_description, + f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", + ), + # BatteryNotesLastReplacedSensor( + # hass, + # config_entry, + # coordinator, + # last_replaced_sensor_entity_description, + # f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", + # ), + ] + + # if coordinator.wrapped_battery is not None: + # entities.append( + # BatteryNotesBatteryPlusSensor( + # hass, + # config_entry, + # subentry, + # coordinator, + # battery_plus_sensor_entity_description, + # f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", + # domain_config.enable_replaced, + # domain_config.round_battery, + # ) + # ) async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData]) -> None: """Handle entity registry update.""" @@ -262,6 +262,106 @@ async def async_setup_platform( await async_setup_reload_service(hass, DOMAIN, PLATFORMS) +class BatteryNotesTypeSensor(RestoreSensor, SensorEntity): + """Represents a battery note type sensor.""" + + _attr_should_poll = False + entity_description: BatteryNotesSensorEntityDescription + _unrecorded_attributes = frozenset({ATTR_BATTERY_QUANTITY, ATTR_BATTERY_TYPE}) + + def __init__( + self, + hass, + config_entry: ConfigEntry, + coordinator: BatteryNotesCoordinator, + description: BatteryNotesSensorEntityDescription, + unique_id: str, + ) -> None: + # pylint: disable=unused-argument + """Initialize the sensor.""" + super().__init__() + + device_registry = dr.async_get(hass) + + self.coordinator = coordinator + + self._attr_has_entity_name = True + + if coordinator.source_entity_id and not coordinator.device_id: + self._attr_translation_placeholders = { + "device_name": coordinator.device_name + " " + } + self.entity_id = ( + f"sensor.{coordinator.device_name.lower()}_{description.key}" + ) + elif coordinator.source_entity_id and coordinator.device_id: + source_entity_domain, source_object_id = split_entity_id( + coordinator.source_entity_id + ) + self._attr_translation_placeholders = { + "device_name": coordinator.source_entity_name + " " + } + self.entity_id = f"sensor.{source_object_id}_{description.key}" + else: + self._attr_translation_placeholders = {"device_name": ""} + self.entity_id = ( + f"sensor.{coordinator.device_name.lower()}_{description.key}" + ) + + self.entity_description = description + self._attr_unique_id = unique_id + self._device_id = coordinator.device_id + self._source_entity_id = coordinator.source_entity_id + + if coordinator.device_id and ( + device_entry := device_registry.async_get(coordinator.device_id) + ): + self._attr_device_info = DeviceInfo( + connections=device_entry.connections, + identifiers=device_entry.identifiers, + ) + + self._battery_type = coordinator.battery_type + self._battery_quantity = coordinator.battery_quantity + + async def async_added_to_hass(self) -> None: + """Handle added to Hass.""" + await super().async_added_to_hass() + state = await self.async_get_last_sensor_data() + if state: + self._attr_native_value = state.native_value + + # Update entity options + registry = er.async_get(self.hass) + if registry.async_get(self.entity_id) is not None: + registry.async_update_entity_options( + self.entity_id, + DOMAIN, + { + "entity_id": self._attr_unique_id, + }, + ) + + @property + def native_value(self) -> str: + """Return the native value of the sensor.""" + return self.coordinator.battery_type_and_quantity + + @property + def extra_state_attributes(self) -> dict[str, Any] | None: + """Return the state attributes of the battery type.""" + + attrs = { + ATTR_BATTERY_QUANTITY: self.coordinator.battery_quantity, + ATTR_BATTERY_TYPE: self.coordinator.battery_type, + } + + super_attrs = super().extra_state_attributes + if super_attrs: + attrs.update(super_attrs) + return attrs + + class BatteryNotesBatteryPlusSensor( RestoreSensor, SensorEntity, CoordinatorEntity[BatteryNotesCoordinator] ): @@ -289,7 +389,6 @@ def __init__( self, hass: HomeAssistant, config_entry: ConfigEntry, - subentry: ConfigSubentry, coordinator: BatteryNotesCoordinator, description: BatteryNotesSensorEntityDescription, unique_id: str, @@ -302,11 +401,8 @@ def __init__( device_registry = dr.async_get(hass) self.config_entry = config_entry - self.subentry = subentry self.coordinator = coordinator - self.subentry_id = subentry.subentry_id - self._attr_has_entity_name = True if coordinator.source_entity_id and not coordinator.device_id: @@ -338,27 +434,14 @@ def __init__( self._device_id = coordinator.device_id self._source_entity_id = coordinator.source_entity_id - # if coordinator.device_id and ( - # device_entry := device_registry.async_get(coordinator.device_id) - # ): - # self._attr_device_info = DeviceInfo( - # connections=device_entry.connections, - # identifiers=device_entry.identifiers, - # ) - - if self.coordinator.device_id: - #TODO: Get this working, by getting any entity of the device and using it - self.device_entry = async_entity_id_to_device_id( - hass, - coordinator.source_entity_id, - ) - else: - self.device_entry = async_entity_id_to_device_id( - hass, - coordinator.source_entity_id, + if coordinator.device_id and ( + device_entry := device_registry.async_get(coordinator.device_id) + ): + self._attr_device_info = DeviceInfo( + connections=device_entry.connections, + identifiers=device_entry.identifiers, ) - entity_category = ( coordinator.wrapped_battery.entity_category if coordinator.wrapped_battery else None ) @@ -654,106 +737,6 @@ def native_value(self) -> StateType | Any | datetime: return self._attr_native_value -class BatteryNotesTypeSensor(RestoreSensor, SensorEntity): - """Represents a battery note type sensor.""" - - _attr_should_poll = False - entity_description: BatteryNotesSensorEntityDescription - _unrecorded_attributes = frozenset({ATTR_BATTERY_QUANTITY, ATTR_BATTERY_TYPE}) - - def __init__( - self, - hass, - config_entry: ConfigEntry, - coordinator: BatteryNotesCoordinator, - description: BatteryNotesSensorEntityDescription, - unique_id: str, - ) -> None: - # pylint: disable=unused-argument - """Initialize the sensor.""" - super().__init__() - - device_registry = dr.async_get(hass) - - self.coordinator = coordinator - - self._attr_has_entity_name = True - - if coordinator.source_entity_id and not coordinator.device_id: - self._attr_translation_placeholders = { - "device_name": coordinator.device_name + " " - } - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( - coordinator.source_entity_id - ) - self._attr_translation_placeholders = { - "device_name": coordinator.source_entity_name + " " - } - self.entity_id = f"sensor.{source_object_id}_{description.key}" - else: - self._attr_translation_placeholders = {"device_name": ""} - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - - self.entity_description = description - self._attr_unique_id = unique_id - self._device_id = coordinator.device_id - self._source_entity_id = coordinator.source_entity_id - - if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) - ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, - ) - - self._battery_type = coordinator.battery_type - self._battery_quantity = coordinator.battery_quantity - - async def async_added_to_hass(self) -> None: - """Handle added to Hass.""" - await super().async_added_to_hass() - state = await self.async_get_last_sensor_data() - if state: - self._attr_native_value = state.native_value - - # Update entity options - registry = er.async_get(self.hass) - if registry.async_get(self.entity_id) is not None: - registry.async_update_entity_options( - self.entity_id, - DOMAIN, - { - "entity_id": self._attr_unique_id, - }, - ) - - @property - def native_value(self) -> str: - """Return the native value of the sensor.""" - return self.coordinator.battery_type_and_quantity - - @property - def extra_state_attributes(self) -> dict[str, Any] | None: - """Return the state attributes of the battery type.""" - - attrs = { - ATTR_BATTERY_QUANTITY: self.coordinator.battery_quantity, - ATTR_BATTERY_TYPE: self.coordinator.battery_type, - } - - super_attrs = super().extra_state_attributes - if super_attrs: - attrs.update(super_attrs) - return attrs - - class BatteryNotesLastReplacedSensor( SensorEntity, CoordinatorEntity[BatteryNotesCoordinator] ): @@ -843,4 +826,4 @@ def _handle_coordinator_update(self) -> None: @property def native_value(self) -> datetime | None: """Return the native value of the sensor.""" - return self._native_value + return self._native_value \ No newline at end of file From a497982e000688bbc4baf6446916c51679e9046f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 4 Aug 2025 08:35:54 +0000 Subject: [PATCH 036/235] WIP --- custom_components/battery_notes/__init__.py | 1 - custom_components/battery_notes/const.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 7a2e61770..5376120ae 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,7 +8,6 @@ import logging import re -from typing import Any, Final import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 1b6e66056..90ddd0c8b 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -110,7 +110,7 @@ #TODO: Change back to all platforms once all completed PLATFORMS: Final = [ - Platform.BUTTON, - # Platform.SENSOR, + # Platform.BUTTON, + Platform.SENSOR, # Platform.BINARY_SENSOR, ] From fa9e4c97095b12957e841d8fd4b6ebd5acd6322d Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 4 Aug 2025 08:36:16 +0000 Subject: [PATCH 037/235] WIP --- custom_components/battery_notes/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 5376120ae..d19d3ad0a 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,6 +8,7 @@ import logging import re +from typing import Any import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion From 14f676f2dd7a320b79a957128be501c1b8b8027f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 4 Aug 2025 09:13:51 +0000 Subject: [PATCH 038/235] WIP --- custom_components/battery_notes/sensor.py | 53 +++++++++++++---------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index b82bd7d45..494d5cb81 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -36,6 +36,8 @@ entity_registry as er, ) from homeassistant.helpers.device import ( + #TODO: Add this when move to 2025.8 + # async_entity_id_to_device, async_entity_id_to_device_id, async_remove_stale_devices_links_keep_entity_device, ) @@ -105,20 +107,20 @@ class BatteryNotesSensorEntityDescription( _LOGGER = logging.getLogger(__name__) -@callback -def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry, subentry: ConfigSubentry) -> str | None: - """Add our config entry to the device.""" - device_registry = dr.async_get(hass) +# @callback +# def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry, subentry: ConfigSubentry) -> str | None: +# """Add our config entry to the device.""" +# device_registry = dr.async_get(hass) - device_id = subentry.data.get(CONF_DEVICE_ID) +# device_id = subentry.data.get(CONF_DEVICE_ID) - if device_id: - if device_registry.async_get(device_id): - device_registry.async_update_device( - device_id, add_config_entry_id=entry.entry_id - ) - return device_id - return None +# if device_id: +# if device_registry.async_get(device_id): +# device_registry.async_update_device( +# device_id, add_config_entry_id=entry.entry_id +# ) +# return device_id +# return None async def async_setup_entry( @@ -150,11 +152,10 @@ async def _setup_battery_note_subentry( coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) assert(coordinator) - if not coordinator.fake_device: - device_id = async_add_to_device(hass, config_entry, subentry) - - if not device_id: - return + # if not coordinator.fake_device: + # device_id = async_add_to_device(hass, config_entry, subentry) + # if not device_id: + # return await coordinator.async_refresh() @@ -189,6 +190,7 @@ async def _setup_battery_note_subentry( BatteryNotesTypeSensor( hass, config_entry, + subentry, coordinator, type_sensor_entity_description, f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", @@ -273,6 +275,7 @@ def __init__( self, hass, config_entry: ConfigEntry, + subentry: ConfigSubentry, coordinator: BatteryNotesCoordinator, description: BatteryNotesSensorEntityDescription, unique_id: str, @@ -313,13 +316,19 @@ def __init__( self._device_id = coordinator.device_id self._source_entity_id = coordinator.source_entity_id + # TODO: Replace this with new method of attached to device + # if coordinator.device_id and ( + # device_entry := device_registry.async_get(coordinator.device_id) + # ): + # self._attr_device_info = DeviceInfo( + # connections=device_entry.connections, + # identifiers=device_entry.identifiers, + # ) if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) + device_registry.async_get(coordinator.device_id) ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, - ) + self.device_entry = dr.async_get(hass).async_get(coordinator.device_id) + #TODO: If not a device_id but source_entity_id is attached to a device, use that and add self._battery_type = coordinator.battery_type self._battery_quantity = coordinator.battery_quantity From 59fee12ee2ced6b1d2d057fcbb06cb4894161c44 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 4 Aug 2025 10:10:43 +0000 Subject: [PATCH 039/235] WIP --- custom_components/battery_notes/sensor.py | 42 ++++++++++++++++++----- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 494d5cb81..a65107b16 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -42,7 +42,10 @@ async_remove_stale_devices_links_keep_entity_device, ) from homeassistant.helpers.entity import DeviceInfo, EntityCategory -from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.entity_platform import ( + AddConfigEntryEntitiesCallback, + AddEntitiesCallback, +) from homeassistant.helpers.entity_registry import ( EVENT_ENTITY_REGISTRY_UPDATED, ) @@ -126,7 +129,7 @@ class BatteryNotesSensorEntityDescription( async def async_setup_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, - async_add_entities: AddEntitiesCallback, + async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Initialize Battery Type config entry.""" entity_registry = er.async_get(hass) @@ -135,13 +138,38 @@ async def async_setup_entry( for subentry in config_entry.subentries.values(): if subentry.subentry_type != "battery_note": continue - await _setup_battery_note_subentry(hass, config_entry, subentry, async_add_entities) + + device_id = subentry.data.get(CONF_DEVICE_ID, None) + coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) + assert(coordinator) + + type_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix + key="battery_type", + translation_key="battery_type", + entity_category=EntityCategory.DIAGNOSTIC, + ) + + entities = [ + BatteryNotesTypeSensor( + hass, + config_entry, + subentry, + coordinator, + type_sensor_entity_description, + f"{config_entry.entry_id}{subentry.unique_id}{type_sensor_entity_description.unique_id_suffix}", + ), + ] + + async_add_entities(entities, config_subentry_id=subentry.subentry_id,) + + # await _setup_battery_note_subentry(hass, config_entry, subentry, async_add_entities) async def _setup_battery_note_subentry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, subentry: ConfigSubentry, - async_add_entities: AddEntitiesCallback, + async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up a battery_note subentry.""" entity_registry = er.async_get(hass) @@ -185,7 +213,6 @@ async def _setup_battery_note_subentry( entity_registry_enabled_default=domain_config.enable_replaced, ) - entities = [] entities = [ BatteryNotesTypeSensor( hass, @@ -253,7 +280,7 @@ async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData] ) ) - async_add_entities(entities) + async_add_entities(entities, config_subentry_id=subentry.subentry_id,) async def async_setup_platform( @@ -313,8 +340,6 @@ def __init__( self.entity_description = description self._attr_unique_id = unique_id - self._device_id = coordinator.device_id - self._source_entity_id = coordinator.source_entity_id # TODO: Replace this with new method of attached to device # if coordinator.device_id and ( @@ -340,6 +365,7 @@ async def async_added_to_hass(self) -> None: if state: self._attr_native_value = state.native_value + #TODO: Investigate why this is needed # Update entity options registry = er.async_get(self.hass) if registry.async_get(self.entity_id) is not None: From 53271fa2814c7c54529fca4c1a89db5fb5653ef7 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 4 Aug 2025 14:54:21 +0000 Subject: [PATCH 040/235] Temp old method to test sub entry --- custom_components/battery_notes/sensor.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index a65107b16..1f42589e5 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -342,18 +342,18 @@ def __init__( self._attr_unique_id = unique_id # TODO: Replace this with new method of attached to device - # if coordinator.device_id and ( - # device_entry := device_registry.async_get(coordinator.device_id) - # ): - # self._attr_device_info = DeviceInfo( - # connections=device_entry.connections, - # identifiers=device_entry.identifiers, - # ) if coordinator.device_id and ( - device_registry.async_get(coordinator.device_id) + device_entry := device_registry.async_get(coordinator.device_id) ): - self.device_entry = dr.async_get(hass).async_get(coordinator.device_id) - #TODO: If not a device_id but source_entity_id is attached to a device, use that and add + self._attr_device_info = DeviceInfo( + connections=device_entry.connections, + identifiers=device_entry.identifiers, + ) + # if coordinator.device_id and ( + # device_registry.async_get(coordinator.device_id) + # ): + # self.device_entry = dr.async_get(hass).async_get(coordinator.device_id) + # #TODO: If not a device_id but source_entity_id is attached to a device, use that and add self._battery_type = coordinator.battery_type self._battery_quantity = coordinator.battery_quantity From f20af3386f6a4a8809a1a89bc622a6268a8772c9 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 7 Aug 2025 13:26:38 +0000 Subject: [PATCH 041/235] Update Home Assistant version to 2025.8.0 in pyproject.toml and requirements.txt; adjust ruff version range. --- custom_components/battery_notes/const.py | 4 +- custom_components/battery_notes/sensor.py | 80 +- hacs.json | 2 +- poetry.lock | 1028 ++++++++++++--------- pyproject.toml | 2 +- requirements.txt | 4 +- 6 files changed, 654 insertions(+), 466 deletions(-) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 90ddd0c8b..7f036d21a 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -11,7 +11,7 @@ LOGGER: Logger = getLogger(__package__) -MIN_HA_VERSION = "2025.7.0" +MIN_HA_VERSION = "2025.8.0" manifestfile = Path(__file__).parent / "manifest.json" with open(file=manifestfile, encoding="UTF-8") as json_file: @@ -108,7 +108,7 @@ } ) -#TODO: Change back to all platforms once all completed +# TODO: Change back to all platforms once all completed PLATFORMS: Final = [ # Platform.BUTTON, Platform.SENSOR, diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 1f42589e5..127dd8d23 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -36,8 +36,7 @@ entity_registry as er, ) from homeassistant.helpers.device import ( - #TODO: Add this when move to 2025.8 - # async_entity_id_to_device, + async_entity_id_to_device, async_entity_id_to_device_id, async_remove_stale_devices_links_keep_entity_device, ) @@ -140,8 +139,10 @@ async def async_setup_entry( continue device_id = subentry.data.get(CONF_DEVICE_ID, None) - coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) - assert(coordinator) + coordinator = config_entry.runtime_data.subentry_coordinators.get( + subentry.subentry_id + ) + assert coordinator type_sensor_entity_description = BatteryNotesSensorEntityDescription( unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix @@ -161,10 +162,14 @@ async def async_setup_entry( ), ] - async_add_entities(entities, config_subentry_id=subentry.subentry_id,) + async_add_entities( + entities, + config_subentry_id=subentry.subentry_id, + ) # await _setup_battery_note_subentry(hass, config_entry, subentry, async_add_entities) + async def _setup_battery_note_subentry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, @@ -177,8 +182,10 @@ async def _setup_battery_note_subentry( device_id = subentry.data.get(CONF_DEVICE_ID, None) - coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) - assert(coordinator) + coordinator = config_entry.runtime_data.subentry_coordinators.get( + subentry.subentry_id + ) + assert coordinator # if not coordinator.fake_device: # device_id = async_add_to_device(hass, config_entry, subentry) @@ -245,7 +252,9 @@ async def _setup_battery_note_subentry( # ) # ) - async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData]) -> None: + async def async_registry_updated( + event: Event[er.EventEntityRegistryUpdatedData], + ) -> None: """Handle entity registry update.""" data = event.data if data["action"] == "remove": @@ -275,12 +284,17 @@ async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData] config_entry.async_on_unload( async_track_entity_registry_updated_event( - #TODO: This doesnt look right, should be entity_id - hass, config_entry.entry_id, async_registry_updated + # TODO: This doesnt look right, should be entity_id + hass, + config_entry.entry_id, + async_registry_updated, ) ) - async_add_entities(entities, config_subentry_id=subentry.subentry_id,) + async_add_entities( + entities, + config_subentry_id=subentry.subentry_id, + ) async def async_setup_platform( @@ -342,18 +356,16 @@ def __init__( self._attr_unique_id = unique_id # TODO: Replace this with new method of attached to device - if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) - ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, - ) # if coordinator.device_id and ( - # device_registry.async_get(coordinator.device_id) + # device_entry := device_registry.async_get(coordinator.device_id) # ): - # self.device_entry = dr.async_get(hass).async_get(coordinator.device_id) - # #TODO: If not a device_id but source_entity_id is attached to a device, use that and add + # self._attr_device_info = DeviceInfo( + # connections=device_entry.connections, + # identifiers=device_entry.identifiers, + # ) + if coordinator.device_id and (device_registry.async_get(coordinator.device_id)): + self.device_entry = device_registry.async_get(coordinator.device_id) + # TODO: If not a device_id but source_entity_id is attached to a device, use that and add self._battery_type = coordinator.battery_type self._battery_quantity = coordinator.battery_quantity @@ -365,7 +377,7 @@ async def async_added_to_hass(self) -> None: if state: self._attr_native_value = state.native_value - #TODO: Investigate why this is needed + # TODO: Investigate why this is needed # Update entity options registry = er.async_get(self.hass) if registry.async_get(self.entity_id) is not None: @@ -478,7 +490,9 @@ def __init__( ) entity_category = ( - coordinator.wrapped_battery.entity_category if coordinator.wrapped_battery else None + coordinator.wrapped_battery.entity_category + if coordinator.wrapped_battery + else None ) self._attr_entity_category = entity_category @@ -512,10 +526,18 @@ async def async_state_changed_listener( ] or not validate_is_float(wrapped_battery_state.state) ): - _LOGGER.debug("Sensor.py -> wrapped_battery_state: %s", wrapped_battery_state) + _LOGGER.debug( + "Sensor.py -> wrapped_battery_state: %s", wrapped_battery_state + ) if wrapped_battery_state: - _LOGGER.debug("Sensor.py -> wrapped_battery_state.state: <%s>", wrapped_battery_state.state) - _LOGGER.debug("Sensor.py -> validate_is_float: <%s>", validate_is_float(wrapped_battery_state.state)) + _LOGGER.debug( + "Sensor.py -> wrapped_battery_state.state: <%s>", + wrapped_battery_state.state, + ) + _LOGGER.debug( + "Sensor.py -> validate_is_float: <%s>", + validate_is_float(wrapped_battery_state.state), + ) self._attr_native_value = None self._attr_available = False @@ -588,7 +610,9 @@ async def _register_entity_id_change_listener( """Listen for battery entity_id changes and update battery_plus.""" @callback - async def _entity_rename_listener(event: Event[er.EventEntityRegistryUpdatedData]) -> None: + async def _entity_rename_listener( + event: Event[er.EventEntityRegistryUpdatedData], + ) -> None: """Handle renaming of the entity.""" new_entity_id = event.data["entity_id"] @@ -861,4 +885,4 @@ def _handle_coordinator_update(self) -> None: @property def native_value(self) -> datetime | None: """Return the native value of the sensor.""" - return self._native_value \ No newline at end of file + return self._native_value diff --git a/hacs.json b/hacs.json index 8cb5cee3f..b1fff2ebd 100644 --- a/hacs.json +++ b/hacs.json @@ -2,6 +2,6 @@ "name": "Battery Notes", "filename": "battery_notes.zip", "hide_default_branch": true, - "homeassistant": "2025.7.0", + "homeassistant": "2025.8.0", "zip_release": true } diff --git a/poetry.lock b/poetry.lock index de4222bad..a29ea1e78 100644 --- a/poetry.lock +++ b/poetry.lock @@ -73,103 +73,103 @@ dev = ["aiohttp (==3.11.18)", "aioresponses (==0.7.8)", "codespell (==2.4.1)", " [[package]] name = "aiohttp" -version = "3.12.13" +version = "3.12.15" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.12.13-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5421af8f22a98f640261ee48aae3a37f0c41371e99412d55eaf2f8a46d5dad29"}, - {file = "aiohttp-3.12.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fcda86f6cb318ba36ed8f1396a6a4a3fd8f856f84d426584392083d10da4de0"}, - {file = "aiohttp-3.12.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cd71c9fb92aceb5a23c4c39d8ecc80389c178eba9feab77f19274843eb9412d"}, - {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34ebf1aca12845066c963016655dac897651e1544f22a34c9b461ac3b4b1d3aa"}, - {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:893a4639694c5b7edd4bdd8141be296042b6806e27cc1d794e585c43010cc294"}, - {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:663d8ee3ffb3494502ebcccb49078faddbb84c1d870f9c1dd5a29e85d1f747ce"}, - {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0f8f6a85a0006ae2709aa4ce05749ba2cdcb4b43d6c21a16c8517c16593aabe"}, - {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1582745eb63df267c92d8b61ca655a0ce62105ef62542c00a74590f306be8cb5"}, - {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d59227776ee2aa64226f7e086638baa645f4b044f2947dbf85c76ab11dcba073"}, - {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06b07c418bde1c8e737d8fa67741072bd3f5b0fb66cf8c0655172188c17e5fa6"}, - {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9445c1842680efac0f81d272fd8db7163acfcc2b1436e3f420f4c9a9c5a50795"}, - {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:09c4767af0b0b98c724f5d47f2bf33395c8986995b0a9dab0575ca81a554a8c0"}, - {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3854fbde7a465318ad8d3fc5bef8f059e6d0a87e71a0d3360bb56c0bf87b18a"}, - {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2332b4c361c05ecd381edb99e2a33733f3db906739a83a483974b3df70a51b40"}, - {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1561db63fa1b658cd94325d303933553ea7d89ae09ff21cc3bcd41b8521fbbb6"}, - {file = "aiohttp-3.12.13-cp310-cp310-win32.whl", hash = "sha256:a0be857f0b35177ba09d7c472825d1b711d11c6d0e8a2052804e3b93166de1ad"}, - {file = "aiohttp-3.12.13-cp310-cp310-win_amd64.whl", hash = "sha256:fcc30ad4fb5cb41a33953292d45f54ef4066746d625992aeac33b8c681173178"}, - {file = "aiohttp-3.12.13-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c229b1437aa2576b99384e4be668af1db84b31a45305d02f61f5497cfa6f60c"}, - {file = "aiohttp-3.12.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04076d8c63471e51e3689c93940775dc3d12d855c0c80d18ac5a1c68f0904358"}, - {file = "aiohttp-3.12.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55683615813ce3601640cfaa1041174dc956d28ba0511c8cbd75273eb0587014"}, - {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:921bc91e602d7506d37643e77819cb0b840d4ebb5f8d6408423af3d3bf79a7b7"}, - {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e72d17fe0974ddeae8ed86db297e23dba39c7ac36d84acdbb53df2e18505a013"}, - {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0653d15587909a52e024a261943cf1c5bdc69acb71f411b0dd5966d065a51a47"}, - {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a77b48997c66722c65e157c06c74332cdf9c7ad00494b85ec43f324e5c5a9b9a"}, - {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6946bae55fd36cfb8e4092c921075cde029c71c7cb571d72f1079d1e4e013bc"}, - {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f95db8c8b219bcf294a53742c7bda49b80ceb9d577c8e7aa075612b7f39ffb7"}, - {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:03d5eb3cfb4949ab4c74822fb3326cd9655c2b9fe22e4257e2100d44215b2e2b"}, - {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6383dd0ffa15515283c26cbf41ac8e6705aab54b4cbb77bdb8935a713a89bee9"}, - {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6548a411bc8219b45ba2577716493aa63b12803d1e5dc70508c539d0db8dbf5a"}, - {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81b0fcbfe59a4ca41dc8f635c2a4a71e63f75168cc91026c61be665945739e2d"}, - {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a83797a0174e7995e5edce9dcecc517c642eb43bc3cba296d4512edf346eee2"}, - {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5734d8469a5633a4e9ffdf9983ff7cdb512524645c7a3d4bc8a3de45b935ac3"}, - {file = "aiohttp-3.12.13-cp311-cp311-win32.whl", hash = "sha256:fef8d50dfa482925bb6b4c208b40d8e9fa54cecba923dc65b825a72eed9a5dbd"}, - {file = "aiohttp-3.12.13-cp311-cp311-win_amd64.whl", hash = "sha256:9a27da9c3b5ed9d04c36ad2df65b38a96a37e9cfba6f1381b842d05d98e6afe9"}, - {file = "aiohttp-3.12.13-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0aa580cf80558557285b49452151b9c69f2fa3ad94c5c9e76e684719a8791b73"}, - {file = "aiohttp-3.12.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b103a7e414b57e6939cc4dece8e282cfb22043efd0c7298044f6594cf83ab347"}, - {file = "aiohttp-3.12.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f64e748e9e741d2eccff9597d09fb3cd962210e5b5716047cbb646dc8fe06f"}, - {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c955989bf4c696d2ededc6b0ccb85a73623ae6e112439398935362bacfaaf6"}, - {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d640191016763fab76072c87d8854a19e8e65d7a6fcfcbf017926bdbbb30a7e5"}, - {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dc507481266b410dede95dd9f26c8d6f5a14315372cc48a6e43eac652237d9b"}, - {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8a94daa873465d518db073bd95d75f14302e0208a08e8c942b2f3f1c07288a75"}, - {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f52420cde4ce0bb9425a375d95577fe082cb5721ecb61da3049b55189e4e6"}, - {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f7df1f620ec40f1a7fbcb99ea17d7326ea6996715e78f71a1c9a021e31b96b8"}, - {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3062d4ad53b36e17796dce1c0d6da0ad27a015c321e663657ba1cc7659cfc710"}, - {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:8605e22d2a86b8e51ffb5253d9045ea73683d92d47c0b1438e11a359bdb94462"}, - {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:54fbbe6beafc2820de71ece2198458a711e224e116efefa01b7969f3e2b3ddae"}, - {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:050bd277dfc3768b606fd4eae79dd58ceda67d8b0b3c565656a89ae34525d15e"}, - {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2637a60910b58f50f22379b6797466c3aa6ae28a6ab6404e09175ce4955b4e6a"}, - {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e986067357550d1aaa21cfe9897fa19e680110551518a5a7cf44e6c5638cb8b5"}, - {file = "aiohttp-3.12.13-cp312-cp312-win32.whl", hash = "sha256:ac941a80aeea2aaae2875c9500861a3ba356f9ff17b9cb2dbfb5cbf91baaf5bf"}, - {file = "aiohttp-3.12.13-cp312-cp312-win_amd64.whl", hash = "sha256:671f41e6146a749b6c81cb7fd07f5a8356d46febdaaaf07b0e774ff04830461e"}, - {file = "aiohttp-3.12.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d4a18e61f271127465bdb0e8ff36e8f02ac4a32a80d8927aa52371e93cd87938"}, - {file = "aiohttp-3.12.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:532542cb48691179455fab429cdb0d558b5e5290b033b87478f2aa6af5d20ace"}, - {file = "aiohttp-3.12.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d7eea18b52f23c050ae9db5d01f3d264ab08f09e7356d6f68e3f3ac2de9dfabb"}, - {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad7c8e5c25f2a26842a7c239de3f7b6bfb92304593ef997c04ac49fb703ff4d7"}, - {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6af355b483e3fe9d7336d84539fef460120c2f6e50e06c658fe2907c69262d6b"}, - {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a95cf9f097498f35c88e3609f55bb47b28a5ef67f6888f4390b3d73e2bac6177"}, - {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8ed8c38a1c584fe99a475a8f60eefc0b682ea413a84c6ce769bb19a7ff1c5ef"}, - {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0b9170d5d800126b5bc89d3053a2363406d6e327afb6afaeda2d19ee8bb103"}, - {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:372feeace612ef8eb41f05ae014a92121a512bd5067db8f25101dd88a8db11da"}, - {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a946d3702f7965d81f7af7ea8fb03bb33fe53d311df48a46eeca17e9e0beed2d"}, - {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a0c4725fae86555bbb1d4082129e21de7264f4ab14baf735278c974785cd2041"}, - {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b28ea2f708234f0a5c44eb6c7d9eb63a148ce3252ba0140d050b091b6e842d1"}, - {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d4f5becd2a5791829f79608c6f3dc745388162376f310eb9c142c985f9441cc1"}, - {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:60f2ce6b944e97649051d5f5cc0f439360690b73909230e107fd45a359d3e911"}, - {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69fc1909857401b67bf599c793f2183fbc4804717388b0b888f27f9929aa41f3"}, - {file = "aiohttp-3.12.13-cp313-cp313-win32.whl", hash = "sha256:7d7e68787a2046b0e44ba5587aa723ce05d711e3a3665b6b7545328ac8e3c0dd"}, - {file = "aiohttp-3.12.13-cp313-cp313-win_amd64.whl", hash = "sha256:5a178390ca90419bfd41419a809688c368e63c86bd725e1186dd97f6b89c2706"}, - {file = "aiohttp-3.12.13-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:36f6c973e003dc9b0bb4e8492a643641ea8ef0e97ff7aaa5c0f53d68839357b4"}, - {file = "aiohttp-3.12.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6cbfc73179bd67c229eb171e2e3745d2afd5c711ccd1e40a68b90427f282eab1"}, - {file = "aiohttp-3.12.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1e8b27b2d414f7e3205aa23bb4a692e935ef877e3a71f40d1884f6e04fd7fa74"}, - {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eabded0c2b2ef56243289112c48556c395d70150ce4220d9008e6b4b3dd15690"}, - {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:003038e83f1a3ff97409999995ec02fe3008a1d675478949643281141f54751d"}, - {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b6f46613031dbc92bdcaad9c4c22c7209236ec501f9c0c5f5f0b6a689bf50f3"}, - {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c332c6bb04650d59fb94ed96491f43812549a3ba6e7a16a218e612f99f04145e"}, - {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fea41a2c931fb582cb15dc86a3037329e7b941df52b487a9f8b5aa960153cbd"}, - {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:846104f45d18fb390efd9b422b27d8f3cf8853f1218c537f36e71a385758c896"}, - {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d6c85ac7dd350f8da2520bac8205ce99df4435b399fa7f4dc4a70407073e390"}, - {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5a1ecce0ed281bec7da8550da052a6b89552db14d0a0a45554156f085a912f48"}, - {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5304d74867028cca8f64f1cc1215eb365388033c5a691ea7aa6b0dc47412f495"}, - {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:64d1f24ee95a2d1e094a4cd7a9b7d34d08db1bbcb8aa9fb717046b0a884ac294"}, - {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:119c79922a7001ca6a9e253228eb39b793ea994fd2eccb79481c64b5f9d2a055"}, - {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bb18f00396d22e2f10cd8825d671d9f9a3ba968d708a559c02a627536b36d91c"}, - {file = "aiohttp-3.12.13-cp39-cp39-win32.whl", hash = "sha256:0022de47ef63fd06b065d430ac79c6b0bd24cdae7feaf0e8c6bac23b805a23a8"}, - {file = "aiohttp-3.12.13-cp39-cp39-win_amd64.whl", hash = "sha256:29e08111ccf81b2734ae03f1ad1cb03b9615e7d8f616764f22f71209c094f122"}, - {file = "aiohttp-3.12.13.tar.gz", hash = "sha256:47e2da578528264a12e4e3dd8dd72a7289e5f812758fe086473fab037a10fcce"}, + {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b6fc902bff74d9b1879ad55f5404153e2b33a82e72a95c89cec5eb6cc9e92fbc"}, + {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:098e92835b8119b54c693f2f88a1dec690e20798ca5f5fe5f0520245253ee0af"}, + {file = "aiohttp-3.12.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:40b3fee496a47c3b4a39a731954c06f0bd9bd3e8258c059a4beb76ac23f8e421"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ce13fcfb0bb2f259fb42106cdc63fa5515fb85b7e87177267d89a771a660b79"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3beb14f053222b391bf9cf92ae82e0171067cc9c8f52453a0f1ec7c37df12a77"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c39e87afe48aa3e814cac5f535bc6199180a53e38d3f51c5e2530f5aa4ec58c"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5f1b4ce5bc528a6ee38dbf5f39bbf11dd127048726323b72b8e85769319ffc4"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1004e67962efabbaf3f03b11b4c43b834081c9e3f9b32b16a7d97d4708a9abe6"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8faa08fcc2e411f7ab91d1541d9d597d3a90e9004180edb2072238c085eac8c2"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fe086edf38b2222328cdf89af0dde2439ee173b8ad7cb659b4e4c6f385b2be3d"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:79b26fe467219add81d5e47b4a4ba0f2394e8b7c7c3198ed36609f9ba161aecb"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b761bac1192ef24e16706d761aefcb581438b34b13a2f069a6d343ec8fb693a5"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e153e8adacfe2af562861b72f8bc47f8a5c08e010ac94eebbe33dc21d677cd5b"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fc49c4de44977aa8601a00edbf157e9a421f227aa7eb477d9e3df48343311065"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2776c7ec89c54a47029940177e75c8c07c29c66f73464784971d6a81904ce9d1"}, + {file = "aiohttp-3.12.15-cp310-cp310-win32.whl", hash = "sha256:2c7d81a277fa78b2203ab626ced1487420e8c11a8e373707ab72d189fcdad20a"}, + {file = "aiohttp-3.12.15-cp310-cp310-win_amd64.whl", hash = "sha256:83603f881e11f0f710f8e2327817c82e79431ec976448839f3cd05d7afe8f830"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685"}, + {file = "aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b"}, + {file = "aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3"}, + {file = "aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1"}, + {file = "aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51"}, + {file = "aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0"}, + {file = "aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:691d203c2bdf4f4637792efbbcdcd157ae11e55eaeb5e9c360c1206fb03d4d98"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e995e1abc4ed2a454c731385bf4082be06f875822adc4c6d9eaadf96e20d406"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd44d5936ab3193c617bfd6c9a7d8d1085a8dc8c3f44d5f1dcf554d17d04cf7d"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46749be6e89cd78d6068cdf7da51dbcfa4321147ab8e4116ee6678d9a056a0cf"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0c643f4d75adea39e92c0f01b3fb83d57abdec8c9279b3078b68a3a52b3933b6"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a23918fedc05806966a2438489dcffccbdf83e921a1170773b6178d04ade142"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74bdd8c864b36c3673741023343565d95bfbd778ffe1eb4d412c135a28a8dc89"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a146708808c9b7a988a4af3821379e379e0f0e5e466ca31a73dbdd0325b0263"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7011a70b56facde58d6d26da4fec3280cc8e2a78c714c96b7a01a87930a9530"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3bdd6e17e16e1dbd3db74d7f989e8af29c4d2e025f9828e6ef45fbdee158ec75"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57d16590a351dfc914670bd72530fd78344b885a00b250e992faea565b7fdc05"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc9a0f6569ff990e0bbd75506c8d8fe7214c8f6579cca32f0546e54372a3bb54"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:536ad7234747a37e50e7b6794ea868833d5220b49c92806ae2d7e8a9d6b5de02"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f0adb4177fa748072546fb650d9bd7398caaf0e15b370ed3317280b13f4083b0"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14954a2988feae3987f1eb49c706bff39947605f4b6fa4027c1d75743723eb09"}, + {file = "aiohttp-3.12.15-cp39-cp39-win32.whl", hash = "sha256:b784d6ed757f27574dca1c336f968f4e81130b27595e458e69457e6878251f5d"}, + {file = "aiohttp-3.12.15-cp39-cp39-win_amd64.whl", hash = "sha256:86ceded4e78a992f835209e236617bffae649371c4a50d5e5a3987f237db84b8"}, + {file = "aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2"}, ] [package.dependencies] aiohappyeyeballs = ">=2.5.0" -aiosignal = ">=1.1.2" +aiosignal = ">=1.4.0" attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" @@ -316,14 +316,14 @@ voluptuous = ">0.15" [[package]] name = "anyio" -version = "4.9.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" +version = "4.10.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, - {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, + {file = "anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1"}, + {file = "anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6"}, ] [package.dependencies] @@ -331,8 +331,6 @@ idna = ">=2.8" sniffio = ">=1.1" [package.extras] -doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] [[package]] @@ -692,18 +690,18 @@ docs = ["Sphinx (>=5,<9)", "myst-parser (>=0.18,<4.1)", "sphinx-rtd-theme (>=1,< [[package]] name = "boto3" -version = "1.39.14" +version = "1.40.4" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "boto3-1.39.14-py3-none-any.whl", hash = "sha256:82c6868cad18c3bd4170915e9525f9af5f83e9779c528417f8863629558fc2d0"}, - {file = "boto3-1.39.14.tar.gz", hash = "sha256:fabb16360a93b449d5241006485bcc761c26694e75ac01009f4459f114acc06e"}, + {file = "boto3-1.40.4-py3-none-any.whl", hash = "sha256:95cdc86454e9ff43e0693c5d807a54ce6813b6711d3543a0052ead5216b93367"}, + {file = "boto3-1.40.4.tar.gz", hash = "sha256:6eceffe4ae67c2cb077574289c0efe3ba60e8446646893a974fc3c2fa1130e7c"}, ] [package.dependencies] -botocore = ">=1.39.14,<1.40.0" +botocore = ">=1.40.4,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -712,14 +710,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.39.14" +version = "1.40.4" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "botocore-1.39.14-py3-none-any.whl", hash = "sha256:4ed551c77194167b7e8063f33059bc2f9b2ead0ed4ee33dc7857273648ed4349"}, - {file = "botocore-1.39.14.tar.gz", hash = "sha256:7fc44d4ad13b524e5d8a6296785776ef5898ac026ff74df9b35313831d507926"}, + {file = "botocore-1.40.4-py3-none-any.whl", hash = "sha256:4e131c52731e10a6af998c2ac3bfbda12e6ecef0e3633268c7752d0502c74197"}, + {file = "botocore-1.40.4.tar.gz", hash = "sha256:f1dacde69ec8b08f39bcdb62247bab4554938b5d7f8805ade78447da55c9df36"}, ] [package.dependencies] @@ -750,14 +748,14 @@ test = ["coverage", "pycodestyle"] [[package]] name = "certifi" -version = "2025.7.14" +version = "2025.8.3" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, - {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, + {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, + {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, ] [[package]] @@ -1098,58 +1096,58 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "dbus-fast" -version = "2.44.2" +version = "2.44.3" description = "A faster version of dbus-next" optional = false python-versions = ">=3.9" groups = ["main"] markers = "platform_system == \"Linux\"" files = [ - {file = "dbus_fast-2.44.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a07e3a66c0ac5fb0ae6f296f7f659c759347e739a5b6c5faf5fd470209715436"}, - {file = "dbus_fast-2.44.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10160e8e25a80b7b84363c82f43bafbba3ba320869f33dcf46eb68172f97d9a"}, - {file = "dbus_fast-2.44.2-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:526674fbb9de53e2538c513c2d1025985d0fd99b2f97855120a308eab8a90b82"}, - {file = "dbus_fast-2.44.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5c46a6698a31ff3f2600e75b39adf79a9db32ecac84a9eff6fbca41dfef6b51"}, - {file = "dbus_fast-2.44.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a5ff265dec3afe1f37d8f7da57f7e0b544479d8e29e126fbcecf0f539e13215"}, - {file = "dbus_fast-2.44.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b9ec223b9c83a3dde27602000a273e48de17b76f9f1cd16f8df2fd536b391891"}, - {file = "dbus_fast-2.44.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c037f93fe754399a52e0c0d049e30d2768009249ccaa065c47358625007e37c1"}, - {file = "dbus_fast-2.44.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b9e0f153165e6e4571d7611a9f1d34ace4168f0304a33c43ff9fad8c5855cef5"}, - {file = "dbus_fast-2.44.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ce7bccaefe0461138c17d414762a84751b4071fe2383f577b8437c0594caad4"}, - {file = "dbus_fast-2.44.2-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0ef232a0e5713e47a4f7201484646f2034606ea09d60a1bc9d79444bfc9052fe"}, - {file = "dbus_fast-2.44.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c3f940a48543e364f241cac0279c568fde7d748dc79c97cc5606823ec3035f2"}, - {file = "dbus_fast-2.44.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9c4079ee0da668cde461b72b072cf29061c96bff1210aa79d48aafea598fea5d"}, - {file = "dbus_fast-2.44.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e6f5ac08cbe344ab47c1e5f5b5912028403edd79a08c610c919ffc6f3346c959"}, - {file = "dbus_fast-2.44.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170fdbb232c060b885cb7329feab34d253d4705b4429727b431fddd0cd928bc4"}, - {file = "dbus_fast-2.44.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:567c2c7b1499e08f1bf3f6dee6dacac17f04d46c7b89984647f7923bfaf81e51"}, - {file = "dbus_fast-2.44.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ee39aa85d4b997726efe8698f82942e4988399abf85a1ad4c463f95e725110"}, - {file = "dbus_fast-2.44.2-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a0afe5cd44d1ee196dc02e81e4932fdf1fdbf5ca3ce8afbb439a1d9ddc33d6b5"}, - {file = "dbus_fast-2.44.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482b467685e9554c2515c528a7302b57edb2c9dd962d04379c2e22ab489680f5"}, - {file = "dbus_fast-2.44.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:613e0e3360c6c9a3a75ad1c90b5eee5ba2f4af405dd532c0cc0fc44ca6c82374"}, - {file = "dbus_fast-2.44.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a66b495be204716f6d51b3da58d8315f75288b85fe53fe7dc2ee97e3cafcab8"}, - {file = "dbus_fast-2.44.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4b5c2ccdffd547bb362671eb9cb251728077b8588701cb9bbe18f49f6362d182"}, - {file = "dbus_fast-2.44.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:13704054d837e51e74524cec0fbccb7318342f6d3aac430075c69f24e1664993"}, - {file = "dbus_fast-2.44.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcc5bf32596b0a2de7f3f708745203e1846be35949b621edf03a14732dcf0f8d"}, - {file = "dbus_fast-2.44.2-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:95263c7ffb07641341a4d58a0e371d8a5eaac3e05df33b4b6b407166e678594d"}, - {file = "dbus_fast-2.44.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1477afc3456a237a68cd1bb0e9d41f8cf721718f564ba92839d0b3db8435d6a4"}, - {file = "dbus_fast-2.44.2-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:b697ab2c32937af8ca7ea2029a7f81cea4b560ca6b33d2f10a6d97c897e104ba"}, - {file = "dbus_fast-2.44.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6b8886ddeb1a8db48490a7609a0559dc27dccd73a62f189ce2cf7f1a96afbcdf"}, - {file = "dbus_fast-2.44.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b6ccd00ae8f42d6d098f8252d56f1101c1a876adda94d1909e6c50ea71f79907"}, - {file = "dbus_fast-2.44.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bdf0014cd60a6de1cff80abdd7aa508bfc71bbd9d447bb69c061c6c77173ed13"}, - {file = "dbus_fast-2.44.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:123b9ca6640188cf7df34226f2a0468be19ace8ea8ea007679ed03e48ffe1fac"}, - {file = "dbus_fast-2.44.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcdbb4b4a0c42e6212267095e990ab2cedfe29c5afe1adcdb4195c25b4fc6de0"}, - {file = "dbus_fast-2.44.2-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a0f4af1fd6439845c127970f93102f41d75f94be8ec09390c39ad9fa9eee6696"}, - {file = "dbus_fast-2.44.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:797db94a38e6d9436b0bf5206794017ebbe019ec969a7f911368ea7097ff8fe0"}, - {file = "dbus_fast-2.44.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9eb55aa73bd5ae4e3b1090a5ae3a92f8ae5263e0c122b9d1b2f6091275b83ca4"}, - {file = "dbus_fast-2.44.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fd017a1ad478acacd145ec25a403253249fdb31ab6d2bc567bd3ef18f0a887a9"}, - {file = "dbus_fast-2.44.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b7f0dc2dd2d38a14bd8f0cc4db4dcef630c248ce743fe60cbf1f0c54fc41b7a0"}, - {file = "dbus_fast-2.44.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:206dc3b9a8619b932f234e55d39fe30c914adcd6bec70bd89ded71d382d2f46a"}, - {file = "dbus_fast-2.44.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96a33d043763b1ee17c2b1e9c5108e34b4091e3323f638af8b3e0e7bd441f667"}, - {file = "dbus_fast-2.44.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:713de29c3fc122726f871bffffd0ac5ecf2e578bd9031c1388d271b757571776"}, - {file = "dbus_fast-2.44.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e46159b0f236ba2b8f7ec5b02eed5c1fd5fa6e4485c89f082887b071ce3ff3df"}, - {file = "dbus_fast-2.44.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3667ce4c7d433c94cb428ac75dd6b041673335f8bb34487d806a5ac7d3540f8c"}, - {file = "dbus_fast-2.44.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5304cd238f927bd11a468d2a8607663152bca5ee69f9b13d64aff45628c025fd"}, - {file = "dbus_fast-2.44.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:19c97f9106b5f036e3db086a6066bfbbb0c3f34f172b24772ccf4f5e7a17e630"}, - {file = "dbus_fast-2.44.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6720a25717b2c41fd15e85ae920bc745aeddb93325822474334f4759e641b6f0"}, - {file = "dbus_fast-2.44.2.tar.gz", hash = "sha256:752f355c32e28468ba9f57b509e2694c4ba0d3d55ae6eb0035511c226438eb35"}, + {file = "dbus_fast-2.44.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:644880d8db53a6d92e88015f6ac6e0d9a5c1bfdacbc5356de816212cca33c629"}, + {file = "dbus_fast-2.44.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be7e2e39bc6a5e0fe758d9d7abb19f91a7540e3b45124764f318147b74c9b2e6"}, + {file = "dbus_fast-2.44.3-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:049236a2cacddc6f1f8583371d8fa54d0a01e2081c8f1311a6ad71b27b1512aa"}, + {file = "dbus_fast-2.44.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69bb4820259e0969ae79585ffc98409bf781589c138a90d4799d5751c83ed04a"}, + {file = "dbus_fast-2.44.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:86350a3fc4304f50c56730b64bd3d709458648fa1b23f8e9449dfcce206defe4"}, + {file = "dbus_fast-2.44.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:89c418c8f18fff8eb17143184d4e0f68216c4d702f16cba4323a6b6be6aaab2a"}, + {file = "dbus_fast-2.44.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c700cdb06e74a6c462d180eff146105fe08f0dc4a8f1f8ff93022175c8e6fe76"}, + {file = "dbus_fast-2.44.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9018568987b878e577bc3e692f2eef6b7a4482490a373ec00098578fa919076c"}, + {file = "dbus_fast-2.44.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3879fb6d6e9260b310fed33457835e11b83e96144bfcf2cbb9abcd3e740c2836"}, + {file = "dbus_fast-2.44.3-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0c68f14d5a329bd494a2da561da961ddfb3f3351d41225dcf0e59106f32bf5d6"}, + {file = "dbus_fast-2.44.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f10ee6ba45f37d067775c0719d072bc4a7e0bdc9a0411f5c7c93af0bfd9958"}, + {file = "dbus_fast-2.44.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bec6cb61d9ce56715410e17e6e6d935df6d39bc01e0aae691135229a0d69072"}, + {file = "dbus_fast-2.44.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94ae76e470c5cf6eb507e2a92e698a9183b3558e3a09efcb7fe2152b92dd300b"}, + {file = "dbus_fast-2.44.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3f1df8582723ee1b1689243663f4e93fc406f0966ff3e9c26a21cb498de3b9ca"}, + {file = "dbus_fast-2.44.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:861352c19f57087e9b2ff7e16a1bab0cfb2e7dc982ce0249aad2a36e1af8f110"}, + {file = "dbus_fast-2.44.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aafa42df91e17023885c508539df2f6312abb9d050f56e39345175cef05bfbb"}, + {file = "dbus_fast-2.44.3-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:4e5c2515bdc159eaa9ac9e99115016af65261cb4d1d237162295966ad1d8cac0"}, + {file = "dbus_fast-2.44.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dab3b4802e1c518b8f3d98bfefe1f696125c00016faf1b6f1fd5170efc06d7e"}, + {file = "dbus_fast-2.44.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:42842e8f396be5d938c60cb449600df811373efd57dc630bb40d6d36f4e710a4"}, + {file = "dbus_fast-2.44.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:93ea055c644bdfd7c70614f7c860db9f5234736a15992df9e4a723fa55ef7622"}, + {file = "dbus_fast-2.44.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9764e4188e21ad4a9f65856f3adacfc83d583a950d4dabc5ec5856db387784b"}, + {file = "dbus_fast-2.44.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d967a751cc2dd530d5b756a22bf67a603ebeca13c6f72d8b1cb8575b872caa16"}, + {file = "dbus_fast-2.44.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da0910f813350b951efe4964a19d7f4aaf253b6c1021b0d68340160a990dc2fc"}, + {file = "dbus_fast-2.44.3-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:253ad2417b0651ba32325661bb559228ceaedea9fb75d238972087a5f66551fd"}, + {file = "dbus_fast-2.44.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebb4c56bef8f69e4e2606eb29a5c137ba448cf7d6958f4f2fba263d74623bd06"}, + {file = "dbus_fast-2.44.3-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:6e0a6a27a1f53b32259d0789bca6f53decd88dec52722cac9a93327f8b7670c3"}, + {file = "dbus_fast-2.44.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a990390c5d019e8e4d41268a3ead0eb6e48e977173d7685b0f5b5b3d0695c2f"}, + {file = "dbus_fast-2.44.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5aca3c940eddb99f19bd3f0c6c50cd566fd98396dd9516d35dbf12af25b7a2c6"}, + {file = "dbus_fast-2.44.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0046e74c25b79ffb6ea5b07f33b5da0bdc2a75ad6aede3f7836654485239121d"}, + {file = "dbus_fast-2.44.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fce364e03b98a6acb4694f1c24b05bfc33d10045af1469378a25ffe4fa046f40"}, + {file = "dbus_fast-2.44.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd955b153622df80cc420fe53c265cd43b7c559100a9e52c83ab0425bc083604"}, + {file = "dbus_fast-2.44.3-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:6b00eef5437d27917d55d04b3edea60c12a3e2a94fd82e81b396311ff7bb1c88"}, + {file = "dbus_fast-2.44.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8468df924e5a3870b1e23377ea573e4b43a22ab1730084eab1b838fd18c9a589"}, + {file = "dbus_fast-2.44.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e4dd64813f175403fac894b5f6f6ff028127ea3c6ca8eda41770f39ba9815572"}, + {file = "dbus_fast-2.44.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f36183af2c6d3a00bd555e7d871d8c3214bb91c42439428dfcf7cc664081182a"}, + {file = "dbus_fast-2.44.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0bb0dfc386ae246def7ee64ce058d099b1bc8c35cd5325e6cd80f57b8115fec7"}, + {file = "dbus_fast-2.44.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b853f75e10b34bb2ba76706d10fdab5ba0cef9ebc1faec1969c84e5b155b3b8"}, + {file = "dbus_fast-2.44.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de00d3d7731b2f915ac3f4ed2119442f3054efeb84c5bdd21717b92241b68f82"}, + {file = "dbus_fast-2.44.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:92377b4f274e3e70b9fcffd9a0e37a9808748f8df4b9d510a81f36b9e8c0f42f"}, + {file = "dbus_fast-2.44.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6ee1dc3e05b47e89b6be5b45d345b57a85b822f3a55299b569766384e74d0f9"}, + {file = "dbus_fast-2.44.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:780c960c546fe509dd2b7a8c7f5eeef3a88f99cdea77225a400a47411b9aea17"}, + {file = "dbus_fast-2.44.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d4200a3c33684df692a545b16f72f52e70ecd68e8226273e828fc12fbcdde88"}, + {file = "dbus_fast-2.44.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:e1643f9d47450e29fd14e62c583c71f332337dc157e9536692e5c0cd5e70ec53"}, + {file = "dbus_fast-2.44.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1f3c673c40a3f82388b377d492aa31f9ba66c20ba1183f1bcd8f9b64eda599c"}, + {file = "dbus_fast-2.44.3.tar.gz", hash = "sha256:962b36abbe885159e31135c57a7d9659997c61a13d55ecb070a61dc502dbd87e"}, ] [[package]] @@ -1471,44 +1469,60 @@ files = [ [[package]] name = "habluetooth" -version = "4.0.1" +version = "4.0.2" description = "High availability Bluetooth" optional = false python-versions = ">=3.11" groups = ["main"] files = [ - {file = "habluetooth-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d5db3e9cad61ce69ab0d31ca1ec6f46f4b8345a8bc3d54938defdaf006ab0e64"}, - {file = "habluetooth-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:273265c4f6a272b96bd1dfe9af82cbee5800fd9970a83979fe6c500084d3ab8d"}, - {file = "habluetooth-4.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec3953dffa549133ef3fdaaeb12200f53a5b8ed814fa48d5783850ef20a18a2d"}, - {file = "habluetooth-4.0.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:29189723ed10c810b227106acebbea9c5357fb1f7b5269f3ffe46deb410490bb"}, - {file = "habluetooth-4.0.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:306b95ec10f2de0f5b4d74b1f98f85735fb7f6e74b98e3c7383ed9131c6f87a4"}, - {file = "habluetooth-4.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c3357dab20069f6ceca62bfa877f2bc98b417c5ccda8214b546a64d1bff2fdd"}, - {file = "habluetooth-4.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:029425bf0454f0c1149e10c050c4b39e12f6d375c2b4ce2d7fe08f0d39784839"}, - {file = "habluetooth-4.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8aed1fcb275b83d65a0a1f14efc96de58b2705e7f57cc1f2a223ad0ca9a6f4ac"}, - {file = "habluetooth-4.0.1-cp311-cp311-win32.whl", hash = "sha256:b4cd8c0f375bb0f3f089bfb13b41f5b5e64205ee8dabfa83fa12f2a5ecfb238a"}, - {file = "habluetooth-4.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:84c75efa373ec33beb91e72181841ff0094c250aca3148793f9fa0985d61744d"}, - {file = "habluetooth-4.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3768931e60b082536b789da5dee6b4b06025ef83699521af448a029527eabef0"}, - {file = "habluetooth-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:debb6a37e041c0086acea1a5da1aae752f4fe098d381644eb565064650b14865"}, - {file = "habluetooth-4.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a6d496488c73db4f8f0b310f0b5d0eb9ab145639425f1f078a6e6079f92cb9d"}, - {file = "habluetooth-4.0.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:42ab082aad33c2a3de1b1f94f604da282b63490f6311825a808d05d6d8dd8eb0"}, - {file = "habluetooth-4.0.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b424e6fb07d60974047c191b01cb2f2613e2de56cc8ae2ad9f6cfe38d6ca0b3f"}, - {file = "habluetooth-4.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:55321424604d46e74b6f4db75635d678939cac9aa8c9b61be536850da3adf3d4"}, - {file = "habluetooth-4.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:60ba9d7086568ca1f022066dff6d1b3901c9555ddb908012f01bee1c306ca059"}, - {file = "habluetooth-4.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9ed04fca2e4fe0ba4a7c473db97d24bf7c5e86963282d1baf607a6cc09475e6"}, - {file = "habluetooth-4.0.1-cp312-cp312-win32.whl", hash = "sha256:05a5915d7a6283d1000420f8d6006b4847732f4194088bedf9c19ae407777073"}, - {file = "habluetooth-4.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fdb2a071277a86488969dd45322f39b063ac07a89f353a5fe115931d3f7bfa50"}, - {file = "habluetooth-4.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4a7e451033cee7a0efd75c2106304d2a1460b554cb62d9bfc64ae3362b54658"}, - {file = "habluetooth-4.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:283979c6b177c779f1670d13cf0d059816a6e07340d2480beac6e065c9579832"}, - {file = "habluetooth-4.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49e7deb8038c0801fcc961ae3e9c912b2ef8050e80a56b0d5135065b3b132b73"}, - {file = "habluetooth-4.0.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:56ee4cef2aa5b15853e3ef3c21886071b77674ca9dd520ea40207de160d5a09c"}, - {file = "habluetooth-4.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44030442dc873888289537297c74b53b1247cdff5f9771c95e67b5aa21c18442"}, - {file = "habluetooth-4.0.1-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:a74f6c357c08434c52e34957e9af6f78f8a949d9521d2f1188358b463e96add0"}, - {file = "habluetooth-4.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1e7097fab343f41aaaf27799c1a030d7cd430bc618c135f1f57f5bc134644a12"}, - {file = "habluetooth-4.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7cb0cda7e89e0b897a7e1bacdc7fafb9e6a3e59a10611ce90ad1b46b22d3d33"}, - {file = "habluetooth-4.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:446d4d575e577df00484f4ce39f15a540551cd5457f2237c274be9071a8f1008"}, - {file = "habluetooth-4.0.1-cp313-cp313-win32.whl", hash = "sha256:eb99fdaf189eb98a0e20a5b56f7821ab4291ca96a4ae648a6694c5b095586446"}, - {file = "habluetooth-4.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:58fa09a014fed1155ad09898757aaef3f71f234f50a14b30613874e02b9bb6ed"}, - {file = "habluetooth-4.0.1.tar.gz", hash = "sha256:13819ef42551ddcb01feff646c9a39bfcad896940bedc54a8aec1a92f4bb0211"}, + {file = "habluetooth-4.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:943b5bb533a49cb1bce627dfdad52e4c2547c84a62a20248f18ff92c5d557ac4"}, + {file = "habluetooth-4.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c389b1674b977c2e142d05f97a2e6c2f146cce9ed3579b2f50854b601915ad76"}, + {file = "habluetooth-4.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:579c77e25859b17c93926da10ae8292d662cc36b8d5cf0649cc7882209d72f08"}, + {file = "habluetooth-4.0.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b4a308d5f31e5494312fc108cc264ab461e2b17ea9bddd633f92fae2197578f1"}, + {file = "habluetooth-4.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a88a3aa36c3f3566f0116cf80eced5b178881513db7f2db970329022df7ed8f"}, + {file = "habluetooth-4.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:22ff7e21d33116a9415e80b29b31cb0471a83a8acad631fab110d3f6d2b78f65"}, + {file = "habluetooth-4.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5941a865f77960d999caeb14c715ec4d4583097f3776bc4b4d38539448810aad"}, + {file = "habluetooth-4.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2137042806417a781183f5f8361dff1178a5ff6c6b7bf1f8c31b309d20b0489"}, + {file = "habluetooth-4.0.2-cp311-cp311-win32.whl", hash = "sha256:4fb7ec381a54e56d78ffcb96b00bc326cbe936180deafe37dd3fbd28e489bbb0"}, + {file = "habluetooth-4.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:a63a1955f032ccbdd5fcc53c1d6e14227796068aa47e78c2b110cad3d83650c9"}, + {file = "habluetooth-4.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef51e756a18f3cab134cb965267aeca87ff86d05e9ecb8c6c6aea87819f4ca1e"}, + {file = "habluetooth-4.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3f9af20c32bb8fc4f93b82c43c66b35941f1c1dd4257ef2cb50e2b3e3a07afb1"}, + {file = "habluetooth-4.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:168d9dae743b05b7cc83286b5e2d881fb6c00354768e6bb31e68a554092f09c2"}, + {file = "habluetooth-4.0.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c55ac9cea6a2c846cefd0137c05608926783e0a4ba8588d2adf55ea8a8be9e63"}, + {file = "habluetooth-4.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2ec89851efbf982f8cdf273afb4bbaaeaeb52f5285ce4684235b42b4d68e"}, + {file = "habluetooth-4.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c12affa73c5d4743eab53eebb95b6a31806ffb03b0b339975a55a260f1598f7"}, + {file = "habluetooth-4.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4c05ed10a4175fd182477bf9f5be6a50f265ffbd68f3c388db6cf4e85ea3e90e"}, + {file = "habluetooth-4.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:28febb8a637a66d7b41b2ae73f53a335efec4eee3daa6acec6677290b7b386e6"}, + {file = "habluetooth-4.0.2-cp312-cp312-win32.whl", hash = "sha256:1b8f53c893b79ba4be1aca34714007fb3ccb0631f4a6965c789c0d93e0d93274"}, + {file = "habluetooth-4.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:943eace066d7a6621b46616b0d56d74d8b602900d4a2e3a9bf7f5cf1702bc283"}, + {file = "habluetooth-4.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fa5cb9988e520f4e417f846af0224078a5cec52374771190dc2a68eab2b4c7bb"}, + {file = "habluetooth-4.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f667402a93bbe791291f1803945232ff889180982cbb46131a92ae4965fd32a"}, + {file = "habluetooth-4.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:06f2b0bbbc454e98a7ce55f3a3f0f8a95ac93f239a46d42910cdfd3c68d58b75"}, + {file = "habluetooth-4.0.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21ff0614cbf6713fddabaf825d1f28540865c385600a4828f8a4b78a523642ae"}, + {file = "habluetooth-4.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05689102deb193e39c600fcedd42d4ff38571116014599e0a8f0a47551aefb4f"}, + {file = "habluetooth-4.0.2-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:2c6c6b59b508b22f48ce5e903b05209278cad76085588ad12508d613e01a87ab"}, + {file = "habluetooth-4.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5036fb92bc60bfd10552633d0958e8f9e6230c0a07b054ff033c0d0ff8307e7f"}, + {file = "habluetooth-4.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c2874a8432ea1232e691d7075169219e84fd6228f0b6e8cdb6f83e31403d2513"}, + {file = "habluetooth-4.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71043f0185d129713798b4b2785b386cc077fc259014a1cb5e66dcd3818c195c"}, + {file = "habluetooth-4.0.2-cp313-cp313-win32.whl", hash = "sha256:c38c9d1e4c664d53315b8cbb74cb0143f2dedf23c4c39b24fcb41ce7c8f18383"}, + {file = "habluetooth-4.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:a0eda4d430bea3f2d27eaba38c64094f1f5308d9a74c8d3e37fd71479f1f730c"}, + {file = "habluetooth-4.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:83e8c8b8662c78f41a0b8d699f08881895795180beefd5cccd83082e5bf11ebe"}, + {file = "habluetooth-4.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c8b28ad298f07f72e955c37724fc4fc5383e685760540228f3ccffd07410c983"}, + {file = "habluetooth-4.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca156ef9378646409f864ded4daded1f353d91ef5cf0a9d26353b040441b3ecc"}, + {file = "habluetooth-4.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a20795f97f7c91da03c6083069cd62052ffb3c0a1f12cf172a787fcdff5be561"}, + {file = "habluetooth-4.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de1a066013ddeb28ef858a37b86a25b6c2835279076c9b40518d43903f9ab618"}, + {file = "habluetooth-4.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:994370adde9e1910516a0c2ae8952c12c7844f7d6f80f33970fca966ebf496ba"}, + {file = "habluetooth-4.0.2-cp314-cp314-win32.whl", hash = "sha256:533bd23369a7853ebe6229875b47723adbd3a489297607ffa1195b4f01d9f724"}, + {file = "habluetooth-4.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:45b1ce825089f600fe7ef5efc788a7e122bd2e8f46d656ae4208f494be63621c"}, + {file = "habluetooth-4.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8a32f3bdc6b5705e73cd6f501dfa13fdd6faafb184fc66b41094e4963a1b69f2"}, + {file = "habluetooth-4.0.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fb47e1d116a06e7d3a9a33070594214fa1c6a3b0f77b1279411c05918e015bd4"}, + {file = "habluetooth-4.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1983397093e49773bc3c0018bb2d9b2bf74f338bf2ecca9c3c5ee794e398a4ce"}, + {file = "habluetooth-4.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b449f8dc33241047c585fa639ecaff8e7c593775324bcecfddff5b1380ef9746"}, + {file = "habluetooth-4.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7ff82d793aef7079634eccb928498d10b4e22e953174dd2c2360409b52fa490b"}, + {file = "habluetooth-4.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:09b53be688183745e20a0529d5958c51604aee897f349bfb6b933eaa82fa0827"}, + {file = "habluetooth-4.0.2-cp314-cp314t-win32.whl", hash = "sha256:b65167aaed991c0d1c23472566682bbe8287bfb51fff7030d840555a5cfacf3a"}, + {file = "habluetooth-4.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:8d2bce29fa7f36bf3ce2df85e8fae46aacac9e784ba6f9fa720aee09d9c97969"}, + {file = "habluetooth-4.0.2.tar.gz", hash = "sha256:64209ef20acc366afbdc3cbb14dbf2283c9df90e0f751ed16a91b74a8bac9eda"}, ] [package.dependencies] @@ -1522,14 +1536,14 @@ dbus-fast = {version = ">=2.30.2", markers = "platform_system == \"Linux\""} [[package]] name = "hass-nabucasa" -version = "0.104.0" +version = "0.111.1" description = "Home Assistant cloud integration by Nabu Casa, Inc." optional = false python-versions = ">=3.13" groups = ["main"] files = [ - {file = "hass_nabucasa-0.104.0-py3-none-any.whl", hash = "sha256:c24a23dcc5cfb22c5f80bbbb9a7aaa51beb32590b926e9725326af96e2e0d662"}, - {file = "hass_nabucasa-0.104.0.tar.gz", hash = "sha256:c4d3755d004a47e68604f8b11cb54e92fe4bdbf7d29aef3f22395be0c09d880c"}, + {file = "hass_nabucasa-0.111.1-py3-none-any.whl", hash = "sha256:446177dde8af6ef7c5af137ceb47f9b3054d8f477f6625f288eedda0856445d7"}, + {file = "hass_nabucasa-0.111.1.tar.gz", hash = "sha256:184541ca05d598ca01d9d52839b4b280032c701d8abb3e2809940a0ebf31e43b"}, ] [package.dependencies] @@ -1543,11 +1557,13 @@ cryptography = ">=42.0.0" josepy = ">=2,<3" pycognito = "2024.5.1" PyJWT = ">=2.8.0" +sentence-stream = "1.1.0" snitun = "0.40.0" webrtc-models = "<1.0.0" +yarl = ">=1.20,<2" [package.extras] -test = ["codespell (==2.4.1)", "mypy (==1.16.1)", "pre-commit (==4.2.0)", "pre-commit-hooks (==5.0.0)", "pylint (==3.3.7)", "pytest (==8.4.1)", "pytest-aiohttp (==1.1.0)", "pytest-timeout (==2.4.0)", "ruff (==0.12.0)", "syrupy (==4.9.1)", "tomli (==2.2.1)", "types_atomicwrites (==1.4.5.1)", "types_pyOpenSSL (==24.1.0.20240722)", "xmltodict (==0.14.2)"] +test = ["codespell (==2.4.1)", "freezegun (==1.5.4)", "mypy (==1.17.1)", "pre-commit (==4.2.0)", "pre-commit-hooks (==5.0.0)", "pylint (==3.3.7)", "pytest (==8.4.1)", "pytest-aiohttp (==1.1.0)", "pytest-socket (==0.7.0)", "pytest-timeout (==2.4.0)", "ruff (==0.12.7)", "syrupy (==4.9.1)", "tomli (==2.2.1)", "types_atomicwrites (==1.4.5.1)", "types_pyOpenSSL (==24.1.0.20240722)", "xmltodict (==0.14.2)"] [[package]] name = "home-assistant-bluetooth" @@ -1566,20 +1582,20 @@ habluetooth = ">=3.0" [[package]] name = "homeassistant" -version = "2025.7.0" +version = "2025.8.0" description = "Open-source home automation platform running on Python 3." optional = false python-versions = ">=3.13.2" groups = ["main"] files = [ - {file = "homeassistant-2025.7.0-py3-none-any.whl", hash = "sha256:60e34c152a645c186d251612515b8ed5a2d2f631af57d51a19a7d4a2d43917bf"}, - {file = "homeassistant-2025.7.0.tar.gz", hash = "sha256:628b101cdb39e658939dd2954f423153f567a6a5a0f0ac86ec855e1d63f2905c"}, + {file = "homeassistant-2025.8.0-py3-none-any.whl", hash = "sha256:b603e8f3fb9d1e107422c2f8816d6733587d32ad4807722f9eeea3cfa12be0a5"}, + {file = "homeassistant-2025.8.0.tar.gz", hash = "sha256:534eadb571167b8ea1f0edb0bab63268237bf047520af3acd7455b9f239076c3"}, ] [package.dependencies] aiodns = "3.5.0" aiohasupervisor = "0.3.1" -aiohttp = "3.12.13" +aiohttp = "3.12.15" aiohttp-asyncmdnsresolver = "0.1.1" aiohttp_cors = "0.8.1" aiohttp-fast-zlib = "0.3.0" @@ -1597,15 +1613,15 @@ ciso8601 = "2.3.2" cronsim = "2.6" cryptography = "45.0.3" fnv-hash-fast = "1.5.0" -hass-nabucasa = "0.104.0" +hass-nabucasa = "0.111.1" home-assistant-bluetooth = "1.13.1" httpx = "0.28.1" ifaddr = "0.2.0" Jinja2 = "3.1.6" lru-dict = "1.3.0" -orjson = "3.10.18" +orjson = "3.11.1" packaging = ">=23.1" -Pillow = "11.2.1" +Pillow = "11.3.0" propcache = "0.3.2" psutil-home-assistant = "0.0.1" PyJWT = "2.10.1" @@ -2113,84 +2129,95 @@ files = [ [[package]] name = "orjson" -version = "3.10.18" +version = "3.11.1" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402"}, - {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be3b9b143e8b9db05368b13b04c84d37544ec85bb97237b3a923f076265ec89c"}, - {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9b0aa09745e2c9b3bf779b096fa71d1cc2d801a604ef6dd79c8b1bfef52b2f92"}, - {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53a245c104d2792e65c8d225158f2b8262749ffe64bc7755b00024757d957a13"}, - {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9495ab2611b7f8a0a8a505bcb0f0cbdb5469caafe17b0e404c3c746f9900469"}, - {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73be1cbcebadeabdbc468f82b087df435843c809cd079a565fb16f0f3b23238f"}, - {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8936ee2679e38903df158037a2f1c108129dee218975122e37847fb1d4ac68"}, - {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7115fcbc8525c74e4c2b608129bef740198e9a120ae46184dac7683191042056"}, - {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:771474ad34c66bc4d1c01f645f150048030694ea5b2709b87d3bda273ffe505d"}, - {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c14047dbbea52886dd87169f21939af5d55143dad22d10db6a7514f058156a8"}, - {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:641481b73baec8db14fdf58f8967e52dc8bda1f2aba3aa5f5c1b07ed6df50b7f"}, - {file = "orjson-3.10.18-cp310-cp310-win32.whl", hash = "sha256:607eb3ae0909d47280c1fc657c4284c34b785bae371d007595633f4b1a2bbe06"}, - {file = "orjson-3.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:8770432524ce0eca50b7efc2a9a5f486ee0113a5fbb4231526d414e6254eba92"}, - {file = "orjson-3.10.18-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e0a183ac3b8e40471e8d843105da6fbe7c070faab023be3b08188ee3f85719b8"}, - {file = "orjson-3.10.18-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5ef7c164d9174362f85238d0cd4afdeeb89d9e523e4651add6a5d458d6f7d42d"}, - {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd14c5d99cdc7bf93f22b12ec3b294931518aa019e2a147e8aa2f31fd3240f7"}, - {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b672502323b6cd133c4af6b79e3bea36bad2d16bca6c1f645903fce83909a7a"}, - {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51f8c63be6e070ec894c629186b1c0fe798662b8687f3d9fdfa5e401c6bd7679"}, - {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9478ade5313d724e0495d167083c6f3be0dd2f1c9c8a38db9a9e912cdaf947"}, - {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:187aefa562300a9d382b4b4eb9694806e5848b0cedf52037bb5c228c61bb66d4"}, - {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da552683bc9da222379c7a01779bddd0ad39dd699dd6300abaf43eadee38334"}, - {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e450885f7b47a0231979d9c49b567ed1c4e9f69240804621be87c40bc9d3cf17"}, - {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5e3c9cc2ba324187cd06287ca24f65528f16dfc80add48dc99fa6c836bb3137e"}, - {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:50ce016233ac4bfd843ac5471e232b865271d7d9d44cf9d33773bcd883ce442b"}, - {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b3ceff74a8f7ffde0b2785ca749fc4e80e4315c0fd887561144059fb1c138aa7"}, - {file = "orjson-3.10.18-cp311-cp311-win32.whl", hash = "sha256:fdba703c722bd868c04702cac4cb8c6b8ff137af2623bc0ddb3b3e6a2c8996c1"}, - {file = "orjson-3.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:c28082933c71ff4bc6ccc82a454a2bffcef6e1d7379756ca567c772e4fb3278a"}, - {file = "orjson-3.10.18-cp311-cp311-win_arm64.whl", hash = "sha256:a6c7c391beaedd3fa63206e5c2b7b554196f14debf1ec9deb54b5d279b1b46f5"}, - {file = "orjson-3.10.18-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:50c15557afb7f6d63bc6d6348e0337a880a04eaa9cd7c9d569bcb4e760a24753"}, - {file = "orjson-3.10.18-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:356b076f1662c9813d5fa56db7d63ccceef4c271b1fb3dd522aca291375fcf17"}, - {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:559eb40a70a7494cd5beab2d73657262a74a2c59aff2068fdba8f0424ec5b39d"}, - {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3c29eb9a81e2fbc6fd7ddcfba3e101ba92eaff455b8d602bf7511088bbc0eae"}, - {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6612787e5b0756a171c7d81ba245ef63a3533a637c335aa7fcb8e665f4a0966f"}, - {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ac6bd7be0dcab5b702c9d43d25e70eb456dfd2e119d512447468f6405b4a69c"}, - {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f72f100cee8dde70100406d5c1abba515a7df926d4ed81e20a9730c062fe9ad"}, - {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca85398d6d093dd41dc0983cbf54ab8e6afd1c547b6b8a311643917fbf4e0c"}, - {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22748de2a07fcc8781a70edb887abf801bb6142e6236123ff93d12d92db3d406"}, - {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a83c9954a4107b9acd10291b7f12a6b29e35e8d43a414799906ea10e75438e6"}, - {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:303565c67a6c7b1f194c94632a4a39918e067bd6176a48bec697393865ce4f06"}, - {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:86314fdb5053a2f5a5d881f03fca0219bfdf832912aa88d18676a5175c6916b5"}, - {file = "orjson-3.10.18-cp312-cp312-win32.whl", hash = "sha256:187ec33bbec58c76dbd4066340067d9ece6e10067bb0cc074a21ae3300caa84e"}, - {file = "orjson-3.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:f9f94cf6d3f9cd720d641f8399e390e7411487e493962213390d1ae45c7814fc"}, - {file = "orjson-3.10.18-cp312-cp312-win_arm64.whl", hash = "sha256:3d600be83fe4514944500fa8c2a0a77099025ec6482e8087d7659e891f23058a"}, - {file = "orjson-3.10.18-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:69c34b9441b863175cc6a01f2935de994025e773f814412030f269da4f7be147"}, - {file = "orjson-3.10.18-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1ebeda919725f9dbdb269f59bc94f861afbe2a27dce5608cdba2d92772364d1c"}, - {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5adf5f4eed520a4959d29ea80192fa626ab9a20b2ea13f8f6dc58644f6927103"}, - {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7592bb48a214e18cd670974f289520f12b7aed1fa0b2e2616b8ed9e069e08595"}, - {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f872bef9f042734110642b7a11937440797ace8c87527de25e0c53558b579ccc"}, - {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0315317601149c244cb3ecef246ef5861a64824ccbcb8018d32c66a60a84ffbc"}, - {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0da26957e77e9e55a6c2ce2e7182a36a6f6b180ab7189315cb0995ec362e049"}, - {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb70d489bc79b7519e5803e2cc4c72343c9dc1154258adf2f8925d0b60da7c58"}, - {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9e86a6af31b92299b00736c89caf63816f70a4001e750bda179e15564d7a034"}, - {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c382a5c0b5931a5fc5405053d36c1ce3fd561694738626c77ae0b1dfc0242ca1"}, - {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8e4b2ae732431127171b875cb2668f883e1234711d3c147ffd69fe5be51a8012"}, - {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d808e34ddb24fc29a4d4041dcfafbae13e129c93509b847b14432717d94b44f"}, - {file = "orjson-3.10.18-cp313-cp313-win32.whl", hash = "sha256:ad8eacbb5d904d5591f27dee4031e2c1db43d559edb8f91778efd642d70e6bea"}, - {file = "orjson-3.10.18-cp313-cp313-win_amd64.whl", hash = "sha256:aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52"}, - {file = "orjson-3.10.18-cp313-cp313-win_arm64.whl", hash = "sha256:f54c1385a0e6aba2f15a40d703b858bedad36ded0491e55d35d905b2c34a4cc3"}, - {file = "orjson-3.10.18-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c95fae14225edfd699454e84f61c3dd938df6629a00c6ce15e704f57b58433bb"}, - {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5232d85f177f98e0cefabb48b5e7f60cff6f3f0365f9c60631fecd73849b2a82"}, - {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2783e121cafedf0d85c148c248a20470018b4ffd34494a68e125e7d5857655d1"}, - {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e54ee3722caf3db09c91f442441e78f916046aa58d16b93af8a91500b7bbf273"}, - {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2daf7e5379b61380808c24f6fc182b7719301739e4271c3ec88f2984a2d61f89"}, - {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f39b371af3add20b25338f4b29a8d6e79a8c7ed0e9dd49e008228a065d07781"}, - {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b819ed34c01d88c6bec290e6842966f8e9ff84b7694632e88341363440d4cc0"}, - {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2f6c57debaef0b1aa13092822cbd3698a1fb0209a9ea013a969f4efa36bdea57"}, - {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:755b6d61ffdb1ffa1e768330190132e21343757c9aa2308c67257cc81a1a6f5a"}, - {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce8d0a875a85b4c8579eab5ac535fb4b2a50937267482be402627ca7e7570ee3"}, - {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57b5d0673cbd26781bebc2bf86f99dd19bd5a9cb55f71cc4f66419f6b50f3d77"}, - {file = "orjson-3.10.18-cp39-cp39-win32.whl", hash = "sha256:951775d8b49d1d16ca8818b1f20c4965cae9157e7b562a2ae34d3967b8f21c8e"}, - {file = "orjson-3.10.18-cp39-cp39-win_amd64.whl", hash = "sha256:fdd9d68f83f0bc4406610b1ac68bdcded8c5ee58605cc69e643a06f4d075f429"}, - {file = "orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53"}, + {file = "orjson-3.11.1-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:92d771c492b64119456afb50f2dff3e03a2db8b5af0eba32c5932d306f970532"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0085ef83a4141c2ed23bfec5fecbfdb1e95dd42fc8e8c76057bdeeec1608ea65"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5caf7f13f2e1b4e137060aed892d4541d07dabc3f29e6d891e2383c7ed483440"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f716bcc166524eddfcf9f13f8209ac19a7f27b05cf591e883419079d98c8c99d"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:507d6012fab05465d8bf21f5d7f4635ba4b6d60132874e349beff12fb51af7fe"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1545083b0931f754c80fd2422a73d83bea7a6d1b6de104a5f2c8dd3d64c291e"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e217ce3bad76351e1eb29ebe5ca630326f45cd2141f62620107a229909501a3"}, + {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06ef26e009304bda4df42e4afe518994cde6f89b4b04c0ff24021064f83f4fbb"}, + {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ba49683b87bea3ae1489a88e766e767d4f423a669a61270b6d6a7ead1c33bd65"}, + {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5072488fcc5cbcda2ece966d248e43ea1d222e19dd4c56d3f82747777f24d864"}, + {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f58ae2bcd119226fe4aa934b5880fe57b8e97b69e51d5d91c88a89477a307016"}, + {file = "orjson-3.11.1-cp310-cp310-win32.whl", hash = "sha256:6723be919c07906781b9c63cc52dc7d2fb101336c99dd7e85d3531d73fb493f7"}, + {file = "orjson-3.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:5fd44d69ddfdfb4e8d0d83f09d27a4db34930fba153fbf79f8d4ae8b47914e04"}, + {file = "orjson-3.11.1-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:15e2a57ce3b57c1a36acffcc02e823afefceee0a532180c2568c62213c98e3ef"}, + {file = "orjson-3.11.1-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:17040a83ecaa130474af05bbb59a13cfeb2157d76385556041f945da936b1afd"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a68f23f09e5626cc0867a96cf618f68b91acb4753d33a80bf16111fd7f9928c"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47e07528bb6ccbd6e32a55e330979048b59bfc5518b47c89bc7ab9e3de15174a"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3807cce72bf40a9d251d689cbec28d2efd27e0f6673709f948f971afd52cb09"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b2dc7e88da4ca201c940f5e6127998d9e89aa64264292334dad62854bc7fc27"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3091dad33ac9e67c0a550cfff8ad5be156e2614d6f5d2a9247df0627751a1495"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ed0fce2307843b79a0c83de49f65b86197f1e2310de07af9db2a1a77a61ce4c"}, + {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a31e84782a18c30abd56774c0cfa7b9884589f4d37d9acabfa0504dad59bb9d"}, + {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26b6c821abf1ae515fbb8e140a2406c9f9004f3e52acb780b3dee9bfffddbd84"}, + {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f857b3d134b36a8436f1e24dcb525b6b945108b30746c1b0b556200b5cb76d39"}, + {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df146f2a14116ce80f7da669785fcb411406d8e80136558b0ecda4c924b9ac55"}, + {file = "orjson-3.11.1-cp311-cp311-win32.whl", hash = "sha256:d777c57c1f86855fe5492b973f1012be776e0398571f7cc3970e9a58ecf4dc17"}, + {file = "orjson-3.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:e9a5fd589951f02ec2fcb8d69339258bbf74b41b104c556e6d4420ea5e059313"}, + {file = "orjson-3.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:4cddbe41ee04fddad35d75b9cf3e3736ad0b80588280766156b94783167777af"}, + {file = "orjson-3.11.1-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2b7c8be96db3a977367250c6367793a3c5851a6ca4263f92f0b48d00702f9910"}, + {file = "orjson-3.11.1-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:72e18088f567bd4a45db5e3196677d9ed1605e356e500c8e32dd6e303167a13d"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d346e2ae1ce17888f7040b65a5a4a0c9734cb20ffbd228728661e020b4c8b3a5"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4bda5426ebb02ceb806a7d7ec9ba9ee5e0c93fca62375151a7b1c00bc634d06b"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10506cebe908542c4f024861102673db534fd2e03eb9b95b30d94438fa220abf"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45202ee3f5494644e064c41abd1320497fb92fd31fc73af708708af664ac3b56"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5adaf01b92e0402a9ac5c3ebe04effe2bbb115f0914a0a53d34ea239a746289"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6162a1a757a1f1f4a94bc6ffac834a3602e04ad5db022dd8395a54ed9dd51c81"}, + {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:78404206977c9f946613d3f916727c189d43193e708d760ea5d4b2087d6b0968"}, + {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:db48f8e81072e26df6cdb0e9fff808c28597c6ac20a13d595756cf9ba1fed48a"}, + {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0c1e394e67ced6bb16fea7054d99fbdd99a539cf4d446d40378d4c06e0a8548d"}, + {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e7a840752c93d4eecd1378e9bb465c3703e127b58f675cd5c620f361b6cf57a4"}, + {file = "orjson-3.11.1-cp312-cp312-win32.whl", hash = "sha256:4537b0e09f45d2b74cb69c7f39ca1e62c24c0488d6bf01cd24673c74cd9596bf"}, + {file = "orjson-3.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:dbee6b050062540ae404530cacec1bf25e56e8d87d8d9b610b935afeb6725cae"}, + {file = "orjson-3.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:f55e557d4248322d87c4673e085c7634039ff04b47bfc823b87149ae12bef60d"}, + {file = "orjson-3.11.1-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53cfefe4af059e65aabe9683f76b9c88bf34b4341a77d329227c2424e0e59b0e"}, + {file = "orjson-3.11.1-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:93d5abed5a6f9e1b6f9b5bf6ed4423c11932b5447c2f7281d3b64e0f26c6d064"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbf06642f3db2966df504944cdd0eb68ca2717f0353bb20b20acd78109374a6"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dddf4e78747fa7f2188273f84562017a3c4f0824485b78372513c1681ea7a894"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa3fe8653c9f57f0e16f008e43626485b6723b84b2f741f54d1258095b655912"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6334d2382aff975a61f6f4d1c3daf39368b887c7de08f7c16c58f485dcf7adb2"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3d0855b643f259ee0cb76fe3df4c04483354409a520a902b067c674842eb6b8"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0eacdfeefd0a79987926476eb16e0245546bedeb8febbbbcf4b653e79257a8e4"}, + {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ed07faf9e4873518c60480325dcbc16d17c59a165532cccfb409b4cdbaeff24"}, + {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d308dd578ae3658f62bb9eba54801533225823cd3248c902be1ebc79b5e014"}, + {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c4aa13ca959ba6b15c0a98d3d204b850f9dc36c08c9ce422ffb024eb30d6e058"}, + {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:be3d0653322abc9b68e5bcdaee6cfd58fcbe9973740ab222b87f4d687232ab1f"}, + {file = "orjson-3.11.1-cp313-cp313-win32.whl", hash = "sha256:4dd34e7e2518de8d7834268846f8cab7204364f427c56fb2251e098da86f5092"}, + {file = "orjson-3.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:d6895d32032b6362540e6d0694b19130bb4f2ad04694002dce7d8af588ca5f77"}, + {file = "orjson-3.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:bb7c36d5d3570fcbb01d24fa447a21a7fe5a41141fd88e78f7994053cc4e28f4"}, + {file = "orjson-3.11.1-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7b71ef394327b3d0b39f6ea7ade2ecda2731a56c6a7cbf0d6a7301203b92a89b"}, + {file = "orjson-3.11.1-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:77c0fe28ed659b62273995244ae2aa430e432c71f86e4573ab16caa2f2e3ca5e"}, + {file = "orjson-3.11.1-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:1495692f1f1ba2467df429343388a0ed259382835922e124c0cfdd56b3d1f727"}, + {file = "orjson-3.11.1-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:08c6a762fca63ca4dc04f66c48ea5d2428db55839fec996890e1bfaf057b658c"}, + {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e26794fe3976810b2c01fda29bd9ac7c91a3c1284b29cc9a383989f7b614037"}, + {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4b4b4f8f0b1d3ef8dc73e55363a0ffe012a42f4e2f1a140bf559698dca39b3fa"}, + {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:848be553ea35aa89bfefbed2e27c8a41244c862956ab8ba00dc0b27e84fd58de"}, + {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c964c29711a4b1df52f8d9966f015402a6cf87753a406c1c4405c407dd66fd45"}, + {file = "orjson-3.11.1-cp314-cp314-win32.whl", hash = "sha256:33aada2e6b6bc9c540d396528b91e666cedb383740fee6e6a917f561b390ecb1"}, + {file = "orjson-3.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:68e10fd804e44e36188b9952543e3fa22f5aa8394da1b5283ca2b423735c06e8"}, + {file = "orjson-3.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:f3cf6c07f8b32127d836be8e1c55d4f34843f7df346536da768e9f73f22078a1"}, + {file = "orjson-3.11.1-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3d593a9e0bccf2c7401ae53625b519a7ad7aa555b1c82c0042b322762dc8af4e"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0baad413c498fc1eef568504f11ea46bc71f94b845c075e437da1e2b85b4fb86"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:22cf17ae1dae3f9b5f37bfcdba002ed22c98bbdb70306e42dc18d8cc9b50399a"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e855c1e97208133ce88b3ef6663c9a82ddf1d09390cd0856a1638deee0390c3c"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5861c5f7acff10599132854c70ab10abf72aebf7c627ae13575e5f20b1ab8fe"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1e6415c5b5ff3a616a6dafad7b6ec303a9fc625e9313c8e1268fb1370a63dcb"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:912579642f5d7a4a84d93c5eed8daf0aa34e1f2d3f4dc6571a8e418703f5701e"}, + {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2092e1d3b33f64e129ff8271642afddc43763c81f2c30823b4a4a4a5f2ea5b55"}, + {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:b8ac64caba1add2c04e9cd4782d4d0c4d6c554b7a3369bdec1eed7854c98db7b"}, + {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:23196b826ebc85c43f8e27bee0ab33c5fb13a29ea47fb4fcd6ebb1e660eb0252"}, + {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f2d3364cfad43003f1e3d564a069c8866237cca30f9c914b26ed2740b596ed00"}, + {file = "orjson-3.11.1-cp39-cp39-win32.whl", hash = "sha256:20b0dca94ea4ebe4628330de50975b35817a3f52954c1efb6d5d0498a3bbe581"}, + {file = "orjson-3.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:200c3ad7ed8b5d31d49143265dfebd33420c4b61934ead16833b5cd2c3d241be"}, + {file = "orjson-3.11.1.tar.gz", hash = "sha256:48d82770a5fd88778063604c566f9c7c71820270c9cc9338d25147cbf34afd96"}, ] [[package]] @@ -2207,101 +2234,126 @@ files = [ [[package]] name = "pillow" -version = "11.2.1" +version = "11.3.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047"}, - {file = "pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d"}, - {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97"}, - {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579"}, - {file = "pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d"}, - {file = "pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad"}, - {file = "pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2"}, - {file = "pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70"}, - {file = "pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788"}, - {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e"}, - {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e"}, - {file = "pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6"}, - {file = "pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193"}, - {file = "pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7"}, - {file = "pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f"}, - {file = "pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4"}, - {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443"}, - {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c"}, - {file = "pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3"}, - {file = "pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941"}, - {file = "pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb"}, - {file = "pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28"}, - {file = "pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155"}, - {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14"}, - {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b"}, - {file = "pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2"}, - {file = "pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691"}, - {file = "pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c"}, - {file = "pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22"}, - {file = "pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91"}, - {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751"}, - {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9"}, - {file = "pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd"}, - {file = "pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e"}, - {file = "pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681"}, - {file = "pillow-11.2.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:7491cf8a79b8eb867d419648fff2f83cb0b3891c8b36da92cc7f1931d46108c8"}, - {file = "pillow-11.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b02d8f9cb83c52578a0b4beadba92e37d83a4ef11570a8688bbf43f4ca50909"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:014ca0050c85003620526b0ac1ac53f56fc93af128f7546623cc8e31875ab928"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3692b68c87096ac6308296d96354eddd25f98740c9d2ab54e1549d6c8aea9d79"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:f781dcb0bc9929adc77bad571b8621ecb1e4cdef86e940fe2e5b5ee24fd33b35"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:2b490402c96f907a166615e9a5afacf2519e28295f157ec3a2bb9bd57de638cb"}, - {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6b20b93b3ccc9c1b597999209e4bc5cf2853f9ee66e3fc9a400a78733ffc9a"}, - {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4b835d89c08a6c2ee7781b8dd0a30209a8012b5f09c0a665b65b0eb3560b6f36"}, - {file = "pillow-11.2.1-cp39-cp39-win32.whl", hash = "sha256:b10428b3416d4f9c61f94b494681280be7686bda15898a3a9e08eb66a6d92d67"}, - {file = "pillow-11.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:6ebce70c3f486acf7591a3d73431fa504a4e18a9b97ff27f5f47b7368e4b9dd1"}, - {file = "pillow-11.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:c27476257b2fdcd7872d54cfd119b3a9ce4610fb85c8e32b70b42e3680a29a1e"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044"}, - {file = "pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6"}, + {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"}, + {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"}, + {file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"}, + {file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"}, + {file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"}, + {file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"}, + {file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"}, + {file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"}, + {file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"}, + {file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"}, + {file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"}, + {file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"}, + {file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"}, + {file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"}, + {file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"}, + {file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"}, + {file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"}, + {file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"}, + {file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"}, + {file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"}, + {file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"}, + {file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"}, + {file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"}, + {file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"}, + {file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"}, + {file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"}, + {file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] test-arrow = ["pyarrow"] -tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] +tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] @@ -2505,88 +2557,78 @@ psutil = "*" [[package]] name = "pycares" -version = "4.9.0" +version = "4.10.0" description = "Python interface for c-ares" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pycares-4.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b8bd9a3ee6e9bc990e1933dc7e7e2f44d4184f49a90fa444297ac12ab6c0c84"}, - {file = "pycares-4.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:417a5c20861f35977240ad4961479a6778125bcac21eb2ad1c3aad47e2ff7fab"}, - {file = "pycares-4.9.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab290faa4ea53ce53e3ceea1b3a42822daffce2d260005533293a52525076750"}, - {file = "pycares-4.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1df81193084c9717734e4615e8c5074b9852478c9007d1a8bb242f7f580e67"}, - {file = "pycares-4.9.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20c7a6af0c2ccd17cc5a70d76e299a90e7ebd6c4d8a3d7fff5ae533339f61431"}, - {file = "pycares-4.9.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:370f41442a5b034aebdb2719b04ee04d3e805454a20d3f64f688c1c49f9137c3"}, - {file = "pycares-4.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:340e4a3bbfd14d73c01ec0793a321b8a4a93f64c508225883291078b7ee17ac8"}, - {file = "pycares-4.9.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f0ec94785856ea4f5556aa18f4c027361ba4b26cb36c4ad97d2105ef4eec68ba"}, - {file = "pycares-4.9.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd6b7e23a4a9e2039b5d67dfa0499d2d5f114667dc13fb5d7d03eed230c7ac4f"}, - {file = "pycares-4.9.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:490c978b0be9d35a253a5e31dd598f6d66b453625f0eb7dc2d81b22b8c3bb3f4"}, - {file = "pycares-4.9.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e433faaf07f44e44f1a1b839fee847480fe3db9431509dafc9f16d618d491d0f"}, - {file = "pycares-4.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf6d8851a06b79d10089962c9dadcb34dad00bf027af000f7102297a54aaff2e"}, - {file = "pycares-4.9.0-cp310-cp310-win32.whl", hash = "sha256:4f803e7d66ac7d8342998b8b07393788991353a46b05bbaad0b253d6f3484ea8"}, - {file = "pycares-4.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e17bd32267e3870855de3baed7d0efa6337344d68f44853fd9195c919f39400"}, - {file = "pycares-4.9.0-cp310-cp310-win_arm64.whl", hash = "sha256:6b74f75d8e430f9bb11a1cc99b2e328eed74b17d8d4b476de09126f38d419eb9"}, - {file = "pycares-4.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:16a97ee83ec60d35c7f716f117719932c27d428b1bb56b242ba1c4aa55521747"}, - {file = "pycares-4.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:78748521423a211ce699a50c27cc5c19e98b7db610ccea98daad652ace373990"}, - {file = "pycares-4.9.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8818b2c7a57d9d6d41e8b64d9ff87992b8ea2522fc0799686725228bc3cff6c5"}, - {file = "pycares-4.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96df8990f16013ca5194d6ece19dddb4ef9cd7c3efaab9f196ec3ccd44b40f8d"}, - {file = "pycares-4.9.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61af86fd58b8326e723b0d20fb96b56acaec2261c3a7c9a1c29d0a79659d613a"}, - {file = "pycares-4.9.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec72edb276bda559813cc807bc47b423d409ffab2402417a5381077e9c2c6be1"}, - {file = "pycares-4.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:832fb122c7376c76cab62f8862fa5e398b9575fb7c9ff6bc9811086441ee64ca"}, - {file = "pycares-4.9.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cdcfaef24f771a471671470ccfd676c0366ab6b0616fd8217b8f356c40a02b83"}, - {file = "pycares-4.9.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:52cb056d06ff55d78a8665b97ae948abaaba2ca200ca59b10346d4526bce1e7d"}, - {file = "pycares-4.9.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:54985ed3f2e8a87315269f24cb73441622857a7830adfc3a27c675a94c3261c1"}, - {file = "pycares-4.9.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:08048e223615d4aef3dac81fe0ea18fb18d6fc97881f1eb5be95bb1379969b8d"}, - {file = "pycares-4.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cc60037421ce05a409484287b2cd428e1363cca73c999b5f119936bb8f255208"}, - {file = "pycares-4.9.0-cp311-cp311-win32.whl", hash = "sha256:62b86895b60cfb91befb3086caa0792b53f949231c6c0c3053c7dfee3f1386ab"}, - {file = "pycares-4.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:7046b3c80954beaabf2db52b09c3d6fe85f6c4646af973e61be79d1c51589932"}, - {file = "pycares-4.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:fcbda3fdf44e94d3962ca74e6ba3dc18c0d7029106f030d61c04c0876f319403"}, - {file = "pycares-4.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d68ca2da1001aeccdc81c4a2fb1f1f6cfdafd3d00e44e7c1ed93e3e05437f666"}, - {file = "pycares-4.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4f0c8fa5a384d79551a27eafa39eed29529e66ba8fa795ee432ab88d050432a3"}, - {file = "pycares-4.9.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eb8c428cf3b9c6ff9c641ba50ab6357b4480cd737498733e6169b0ac8a1a89b"}, - {file = "pycares-4.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6845bd4a43abf6dab7fedbf024ef458ac3750a25b25076ea9913e5ac5fec4548"}, - {file = "pycares-4.9.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e28f4acc3b97e46610cf164665ebf914f709daea6ced0ca4358ce55bc1c3d6b"}, - {file = "pycares-4.9.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9464a39861840ce35a79352c34d653a9db44f9333af7c9feddb97998d3e00c07"}, - {file = "pycares-4.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0611c1bd46d1fc6bdd9305b8850eb84c77df485769f72c574ed7b8389dfbee2"}, - {file = "pycares-4.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4fb5a38a51d03b75ac4320357e632c2e72e03fdeb13263ee333a40621415fdc"}, - {file = "pycares-4.9.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:df5edae05fb3e1370ab7639e67e8891fdaa9026cb10f05dbd57893713f7a9cfe"}, - {file = "pycares-4.9.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:397123ea53d261007bb0aa7e767ef238778f45026db40bed8196436da2cc73de"}, - {file = "pycares-4.9.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bb0d874d0b131b29894fd8a0f842be91ac21d50f90ec04cff4bb3f598464b523"}, - {file = "pycares-4.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:497cc03a61ec1585eb17d2cb086a29a6a67d24babf1e9be519b47222916a3b06"}, - {file = "pycares-4.9.0-cp312-cp312-win32.whl", hash = "sha256:b46e46313fdb5e82da15478652aac0fd15e1c9f33e08153bad845aa4007d6f84"}, - {file = "pycares-4.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:12547a06445777091605a7581da15a0da158058beb8a05a3ebbf7301fd1f58d4"}, - {file = "pycares-4.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:f1e10bf1e8eb80b08e5c828627dba1ebc4acd54803bd0a27d92b9063b6aa99d8"}, - {file = "pycares-4.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:574d815112a95ab09d75d0a9dc7dea737c06985e3125cf31c32ba6a3ed6ca006"}, - {file = "pycares-4.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50e5ab06361d59625a27a7ad93d27e067dc7c9f6aa529a07d691eb17f3b43605"}, - {file = "pycares-4.9.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:785f5fd11ff40237d9bc8afa441551bb449e2812c74334d1d10859569e07515c"}, - {file = "pycares-4.9.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e194a500e403eba89b91fb863c917495c5b3dfcd1ce0ee8dc3a6f99a1360e2fc"}, - {file = "pycares-4.9.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:112dd49cdec4e6150a8d95b197e8b6b7b4468a3170b30738ed9b248cb2240c04"}, - {file = "pycares-4.9.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94aa3c2f3eb0aa69160137134775501f06c901188e722aac63d2a210d4084f99"}, - {file = "pycares-4.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b510d71255cf5a92ccc2643a553548fcb0623d6ed11c8c633b421d99d7fa4167"}, - {file = "pycares-4.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5c6aa30b1492b8130f7832bf95178642c710ce6b7ba610c2b17377f77177e3cd"}, - {file = "pycares-4.9.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e5767988e044faffe2aff6a76aa08df99a8b6ef2641be8b00ea16334ce5dea93"}, - {file = "pycares-4.9.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b9928a942820a82daa3207509eaba9e0fa9660756ac56667ec2e062815331fcb"}, - {file = "pycares-4.9.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:556c854174da76d544714cdfab10745ed5d4b99eec5899f7b13988cd26ff4763"}, - {file = "pycares-4.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d42e2202ca9aa9a0a9a6e43a4a4408bbe0311aaa44800fa27b8fd7f82b20152a"}, - {file = "pycares-4.9.0-cp313-cp313-win32.whl", hash = "sha256:cce8ef72c9ed4982c84114e6148a4e42e989d745de7862a0ad8b3f1cdc05def2"}, - {file = "pycares-4.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:318cdf24f826f1d2f0c5a988730bd597e1683296628c8f1be1a5b96643c284fe"}, - {file = "pycares-4.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:faa9de8e647ed06757a2c117b70a7645a755561def814da6aca0d766cf71a402"}, - {file = "pycares-4.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8310d27d68fa25be9781ce04d330f4860634a2ac34dd9265774b5f404679b41f"}, - {file = "pycares-4.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99cf98452d3285307eec123049f2c9c50b109e06751b0727c6acefb6da30c6a0"}, - {file = "pycares-4.9.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ffd6e8c8250655504602b076f106653e085e6b1e15318013442558101aa4777"}, - {file = "pycares-4.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4065858d8c812159c9a55601fda73760d9e5e3300f7868d9e546eab1084f36c"}, - {file = "pycares-4.9.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91ee6818113faf9013945c2b54bcd6b123d0ac192ae3099cf4288cedaf2dbb25"}, - {file = "pycares-4.9.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21f0602059ec11857ab7ad608c7ec8bc6f7a302c04559ec06d33e82f040585f8"}, - {file = "pycares-4.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e22e5b46ed9b12183091da56e4a5a20813b5436c4f13135d7a1c20a84027ca8a"}, - {file = "pycares-4.9.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9eded8649867bfd7aea7589c5755eae4d37686272f6ed7a995da40890d02de71"}, - {file = "pycares-4.9.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f71d31cbbe066657a2536c98aad850724a9ab7b1cd2624f491832ae9667ea8e7"}, - {file = "pycares-4.9.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2b30945982ab4741f097efc5b0853051afc3c11df26996ed53a700c7575175af"}, - {file = "pycares-4.9.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54a8f1f067d64810426491d33033f5353b54f35e5339126440ad4e6afbf3f149"}, - {file = "pycares-4.9.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:41556a269a192349e92eee953f62eddd867e9eddb27f444b261e2c1c4a4a9eff"}, - {file = "pycares-4.9.0-cp39-cp39-win32.whl", hash = "sha256:524d6c14eaa167ed098a4fe54856d1248fa20c296cdd6976f9c1b838ba32d014"}, - {file = "pycares-4.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:15f930c733d36aa487b4ad60413013bd811281b5ea4ca620070fa38505d84df4"}, - {file = "pycares-4.9.0-cp39-cp39-win_arm64.whl", hash = "sha256:79b7addb2a41267d46650ac0d9c4f3b3233b036f186b85606f7586881dfb4b69"}, - {file = "pycares-4.9.0.tar.gz", hash = "sha256:8ee484ddb23dbec4d88d14ed5b6d592c1960d2e93c385d5e52b6fad564d82395"}, + {file = "pycares-4.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d209ce5bf50cf06b72fa7d0eb9cb90fac094e6ada7d9a3b2dd2ba67de1809c25"}, + {file = "pycares-4.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:34089bc561583210d81bd8a14c553390bb209076d280f74291da5a75793c84fc"}, + {file = "pycares-4.10.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5dcd68e87c95c83cf3e5a9492635dc3be706c50a38ea67e02eb6a7741bca671f"}, + {file = "pycares-4.10.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:967e53086bd84b3d7f7e1fc54a0ff2ffdd89d56bb10a392bffd9b810a396164f"}, + {file = "pycares-4.10.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:7063804e7fca5959f315ee13ab2b65bdf0f43ea18cd0c84e4b171436363e0b5f"}, + {file = "pycares-4.10.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:27dbbc055336e79b47628fe890378b22126298bea5a1399fcd4ef9a12de9eb05"}, + {file = "pycares-4.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f444226dc35afb35135a8a82c884e44d97aa4a034057d12acf1ed4879538a601"}, + {file = "pycares-4.10.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2c953e6abf941e92cb1a4dca7be192b76eaac9e42a88e1c5380c79af82fa4aa7"}, + {file = "pycares-4.10.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e0d4a963531e49413c7f0797280b10056ed3df52f8f5e5e25c16f274e85956ab"}, + {file = "pycares-4.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:202a1565a2c7b60647e52d5743c0b24b8d2e236665230e2c46e0e304fd170408"}, + {file = "pycares-4.10.0-cp310-cp310-win32.whl", hash = "sha256:4b4aeecb56631fb640c35e076a9a095f9a41973d04849a83397479e57ffaff40"}, + {file = "pycares-4.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:5baa470fea401ec30d8f8292f190939ac3028637572fae46955122e6930d1609"}, + {file = "pycares-4.10.0-cp310-cp310-win_arm64.whl", hash = "sha256:afb22427ab950a490268db058248e9bdaf4f0bfd52cee5fb7cf670d2d5185c7b"}, + {file = "pycares-4.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29f866c704e4c59789a01a0564d22de359a53a337b3edea4975888373ed934e2"}, + {file = "pycares-4.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdb1558665988cb84e56ccfc86c856f1fc3725e5d08a002ac4faeee65c2f36fa"}, + {file = "pycares-4.10.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9281bf62f03a708976c08755948c288f22a7cba5e4fe0b446dde673b08936a60"}, + {file = "pycares-4.10.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:8e93993bac49a5d6f0bd919084dd701995882b78db9a213e3773adb24b4dc46f"}, + {file = "pycares-4.10.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:6ab788f779b6161cd5129e8cd25ce25d7d91976a5ea6f0e16afdbdd20fe966f6"}, + {file = "pycares-4.10.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:575da87e38e10608be0556edad1458d2374609e7baec7832465078d5ad5c7822"}, + {file = "pycares-4.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7217231366390755f32faeaf0f91ebec8f8a8056fe6e6340a7ee803c0feba05c"}, + {file = "pycares-4.10.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:531cb88285cd3b50d45020ff42dab8cefa65eecab5281dbec33c00258e20ca2d"}, + {file = "pycares-4.10.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:db9187a95ea487b3f5b5878b1d3ba1f541c0bea6b83b7946cc4b5953de82bbc8"}, + {file = "pycares-4.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cdb7232757ca6d6a8b8535ffbffde081271caef397f3b6002789f35f6743dea3"}, + {file = "pycares-4.10.0-cp311-cp311-win32.whl", hash = "sha256:d2434724db49e65146983bd084f16f5780093906bb24522551282ae17ad5add0"}, + {file = "pycares-4.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:e11fe3fbcef622de29711d9a76c97995e4635e113ded1f33cab2bd4248e3c92c"}, + {file = "pycares-4.10.0-cp311-cp311-win_arm64.whl", hash = "sha256:330e656182aa186b6a1b433bfcddbbc11850af5c54d2befa3b77ed289b44bc10"}, + {file = "pycares-4.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:870354741adb5d212a521c33005b368b5c8baa81e2f0d3143e868c025c5bb32f"}, + {file = "pycares-4.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8912544250edc3da6a1fc97ef9543f69ee4bc2812f90e17d294397382d1ecc80"}, + {file = "pycares-4.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:49d896bb5ae3c571bc359d3076c1484fd4f99bb5138c1c597da1f57979238771"}, + {file = "pycares-4.10.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:08e3d70c714e3955dc5ccfe6abc132d2f410ca1c610375faee42fda6cc90ca0f"}, + {file = "pycares-4.10.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:f4f76946b1d6eae7bdbfefef0f143efb8acf5b55e37d631f7ec947fc9a8d6b06"}, + {file = "pycares-4.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:cf99fbdb5f566320d5c1330e55de4f3cbe49ca42690b782db6380523bcfbb34b"}, + {file = "pycares-4.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ba103bbc7f85d0b7c386021cafed122317d05bee56c75c06c22707d8a0393a3d"}, + {file = "pycares-4.10.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6f0e546194fa64e751e70e16239f54fbf34ba216f4d3c7b55ca8ac50a5d82eb5"}, + {file = "pycares-4.10.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5c32115f7004c1b9071c0f250c9092bacd9090bd31a289bd155d58a60d4434fa"}, + {file = "pycares-4.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:259c9b6b4547e1400515a373c6910506f3cebe6e65bb9814be10e59c49dcb634"}, + {file = "pycares-4.10.0-cp312-cp312-win32.whl", hash = "sha256:f972732b3ce1300e6eec8670967920cae56b44df014fd63a793b990d930da64f"}, + {file = "pycares-4.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:489584abc1523d7e444b2b27a563d1c3c0c0852b40f3b453fa3a74cf10b38ebb"}, + {file = "pycares-4.10.0-cp312-cp312-win_arm64.whl", hash = "sha256:468aa3bb19e7f6f193ae5375d1b21722a0cad5726e17c9817bfefbcf29cd662e"}, + {file = "pycares-4.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d4904ebd5e4d0c78e9fd56e6c974da005eaa721365961764922929e8e8f7dd0a"}, + {file = "pycares-4.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7144676e54b0686605333ec62ffdb7bb2b6cb4a6c53eed3e35ae3249dc64676b"}, + {file = "pycares-4.10.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f9a259bf46cc51c51c7402a2bf32d1416f029b9a4af3de8b8973345520278092"}, + {file = "pycares-4.10.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1dcfdda868ad2cee8d171288a4cd725a9ad67498a2f679428874a917396d464e"}, + {file = "pycares-4.10.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:f2d57bb27c884d130ac62d8c0ac57a158d27f8d75011f8700c7d44601f093652"}, + {file = "pycares-4.10.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:95f4d976bf2feb3f406aef6b1314845dc1384d2e4ea0c439c7d50631f2b6d166"}, + {file = "pycares-4.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f9eecd9e28e43254c6fb1c69518bd6b753bf18230579c23e7f272ac52036d41f"}, + {file = "pycares-4.10.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f4f8ec43ce0db38152cded6939a3fa4d8aba888e323803cda99f67fa3053fa15"}, + {file = "pycares-4.10.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ef107d30a9d667c295db58897390c2d32c206eb1802b14d98ac643990be4e04f"}, + {file = "pycares-4.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:56c843e69aad724dc5a795f32ebd6fec1d1592f58cabf89d2d148697c22c41be"}, + {file = "pycares-4.10.0-cp313-cp313-win32.whl", hash = "sha256:4310259be37b586ba8cd0b4983689e4c18e15e03709bd88b1076494e91ff424b"}, + {file = "pycares-4.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:893020d802afb54d929afda5289fe322b50110cd5386080178479a7381241f97"}, + {file = "pycares-4.10.0-cp313-cp313-win_arm64.whl", hash = "sha256:ffa3e0f7a13f287b575e64413f2f9af6cf9096e383d1fd40f2870591628d843b"}, + {file = "pycares-4.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7c2fddd529e3a429d5d83ecf9cd508cc1f7380f50d9004b8735054b9e86655fb"}, + {file = "pycares-4.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:67e27fa1e660fc5847f2e5bcd2284ef5c74ee5c87ab9248a772fcf8dc279e853"}, + {file = "pycares-4.10.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:1add5d01e45698c8ca59123e693c23fd15caaed24b556a1af00316aa5ce13769"}, + {file = "pycares-4.10.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:10e6f724e24fb46b40f4f1fb72308022bb3b5d08a827a0ab9e34971e1cbfc61d"}, + {file = "pycares-4.10.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6ca443da2efece7252709a73506bf259e159804dd9cca344b61a6696d1790129"}, + {file = "pycares-4.10.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:458fe77483605eb18ec42210dbe204805130c95f2776779faf256b64341ca5f2"}, + {file = "pycares-4.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:476b395c0a6cbfae3157389bea09d95af90b2865582371b7af0c446bd1d566e0"}, + {file = "pycares-4.10.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:25eb63e837b94130255a45e8481bf48957642b28e505243c7d471dfb4459f899"}, + {file = "pycares-4.10.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fdd676b8f5d4b98ba87365c82b782dc27089813390cce944ca6d55e6b0904512"}, + {file = "pycares-4.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:283806ab6d18862a11e466ac7df9c5e0cd5adea1a5bec55d754d8fbf89b5c8a3"}, + {file = "pycares-4.10.0-cp39-cp39-win32.whl", hash = "sha256:d53ae1c3d3ea822334251de1e18966a5dd3a13d323f89b77f35603c71e8d6a78"}, + {file = "pycares-4.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:6696a1a259b6f77d3f2183d5dab26a1d4e21d49ea54485419b02092ad169e4e5"}, + {file = "pycares-4.10.0-cp39-cp39-win_arm64.whl", hash = "sha256:620bde2908e7046e26f95283aa47c6558f109c9cf2ae3fb4b4feca4c3e42852e"}, + {file = "pycares-4.10.0.tar.gz", hash = "sha256:9df70dce6e05afa5d477f48959170e569485e20dad1a089c4cf3b2d7ffbd8bf9"}, ] [package.dependencies] @@ -2912,6 +2954,110 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] +[[package]] +name = "regex" +version = "2024.11.6" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, + {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, + {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, + {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, + {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, + {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, + {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, + {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, + {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, + {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, + {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, + {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, + {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, + {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, +] + [[package]] name = "requests" version = "2.32.4" @@ -3071,6 +3217,24 @@ files = [ [package.dependencies] cryptography = "*" +[[package]] +name = "sentence-stream" +version = "1.1.0" +description = "A small sentence splitter for text streams" +optional = false +python-versions = ">=3.9.0" +groups = ["main"] +files = [ + {file = "sentence_stream-1.1.0-py3-none-any.whl", hash = "sha256:3fceb47673ff16f5e301d7d0935db18413f8f1143ba4aea7ea2d9f808c5f1436"}, + {file = "sentence_stream-1.1.0.tar.gz", hash = "sha256:a512604a9f43d4132e29ad04664e8b1778f4a20265799ac86e8d62d181009483"}, +] + +[package.dependencies] +regex = "2024.11.6" + +[package.extras] +dev = ["black (==24.8.0)", "build (==1.2.2)", "flake8 (==7.2.0)", "mypy (==1.14.0)", "pylint (==3.2.7)", "pytest (==8.3.5)", "pytest-asyncio (==1.1.0)", "tox (==4.26.0)"] + [[package]] name = "six" version = "1.17.0" @@ -3385,14 +3549,14 @@ files = [ [[package]] name = "virtualenv" -version = "20.32.0" +version = "20.33.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.32.0-py3-none-any.whl", hash = "sha256:2c310aecb62e5aa1b06103ed7c2977b81e042695de2697d01017ff0f1034af56"}, - {file = "virtualenv-20.32.0.tar.gz", hash = "sha256:886bf75cadfdc964674e6e33eb74d787dff31ca314ceace03ca5810620f4ecf0"}, + {file = "virtualenv-20.33.1-py3-none-any.whl", hash = "sha256:07c19bc66c11acab6a5958b815cbcee30891cd1c2ccf53785a28651a0d8d8a67"}, + {file = "virtualenv-20.33.1.tar.gz", hash = "sha256:1b44478d9e261b3fb8baa5e74a0ca3bc0e05f21aa36167bf9cbf850e542765b8"}, ] [package.dependencies] @@ -3938,4 +4102,4 @@ ifaddr = ">=0.1.7" [metadata] lock-version = "2.1" python-versions = ">=3.13.2,<3.14" -content-hash = "30503a59bb012df7290e80b58beaabd3cade6046a70f3d3087088d2a33d12e30" +content-hash = "174aedcf17fad6e796736fe1070f3750a397a3ac28359b5da3e4461de2f8b9a9" diff --git a/pyproject.toml b/pyproject.toml index d228027b3..56621f346 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ repository = "https://github.com/andrew-codechimp/HA-Battery-Notes" version = "0.0.0" [tool.poetry.dependencies] -homeassistant = "2025.7.0" +homeassistant = "2025.8.0" python = ">=3.13.2,<3.14" [tool.poetry.group.dev.dependencies] diff --git a/requirements.txt b/requirements.txt index 00f50cfe3..c87d47cf3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ colorlog>=6.8.2,<7.0 -homeassistant==2025.7.0 -ruff>=0.5.0,<0.8.2 +homeassistant==2025.8.0 +ruff>=0.5.0,<0.12.7 From f3ba8a06ecb5217d39720610be5ffa0002bff405 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 8 Aug 2025 12:35:13 +0000 Subject: [PATCH 042/235] Refactor BatteryNotesTypeSensor class to remove SensorEntity inheritance and improve device attachment logic --- custom_components/battery_notes/sensor.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 127dd8d23..73aba5e63 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -305,7 +305,7 @@ async def async_setup_platform( await async_setup_reload_service(hass, DOMAIN, PLATFORMS) -class BatteryNotesTypeSensor(RestoreSensor, SensorEntity): +class BatteryNotesTypeSensor(RestoreSensor): """Represents a battery note type sensor.""" _attr_should_poll = False @@ -355,17 +355,20 @@ def __init__( self.entity_description = description self._attr_unique_id = unique_id - # TODO: Replace this with new method of attached to device - # if coordinator.device_id and ( - # device_entry := device_registry.async_get(coordinator.device_id) - # ): - # self._attr_device_info = DeviceInfo( - # connections=device_entry.connections, - # identifiers=device_entry.identifiers, - # ) + # If a device_id then attach to that device if coordinator.device_id and (device_registry.async_get(coordinator.device_id)): self.device_entry = device_registry.async_get(coordinator.device_id) - # TODO: If not a device_id but source_entity_id is attached to a device, use that and add + + # If not a device_id but source_entity_id is attached to a device, use that and add + elif coordinator.source_entity_id: + device_id = async_entity_id_to_device_id( + hass, coordinator.source_entity_id + ) + if device_id and (device_entry := device_registry.async_get(device_id)): + self.device_entry = device_entry + else: + # TODO: If not a device at all then do something else (this note becomes the device or leave hanging?) + self.device_entry = None self._battery_type = coordinator.battery_type self._battery_quantity = coordinator.battery_quantity From 22c924bf649b000bd0d53f5065fab58dc669c4a6 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 8 Aug 2025 14:01:05 +0000 Subject: [PATCH 043/235] Refactor BatteryNotesTypeSensor and add BatteryNotesLastReplacedSensor for improved device association and entity management --- custom_components/battery_notes/entity.py | 73 +++++++ custom_components/battery_notes/sensor.py | 242 +++++++++++----------- 2 files changed, 194 insertions(+), 121 deletions(-) diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index b6f621a74..174bbb83a 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -3,8 +3,15 @@ from __future__ import annotations from dataclasses import dataclass +from typing import TYPE_CHECKING +from homeassistant.core import HomeAssistant, split_entity_id +from homeassistant.helpers import device_registry as dr +from homeassistant.helpers.device import async_entity_id_to_device_id from homeassistant.helpers.entity import EntityDescription +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .coordinator import BatteryNotesCoordinator @dataclass(frozen=True, kw_only=True) @@ -17,3 +24,69 @@ class BatteryNotesRequiredKeysMixin: @dataclass(frozen=True, kw_only=True) class BatteryNotesEntityDescription(EntityDescription, BatteryNotesRequiredKeysMixin): """Generic Battery Notes entity description.""" + + +class BatteryNoteEntity(CoordinatorEntity[BatteryNotesCoordinator]): + """Base class for Battery Notes entities.""" + + def __init__( + self, + hass: HomeAssistant, + coordinator: BatteryNotesCoordinator, + ) -> None: + """Initialize the base entity.""" + super().__init__(coordinator) + + device_registry = dr.async_get(hass) + + self.coordinator = coordinator + self._attr_has_entity_name = True + + # Set up entity naming and translation placeholders + # self._setup_entity_naming(description) + + # Set up device association + self._setup_device_association(hass, device_registry) + + # def _setup_entity_naming(self, description: BatteryNotesEntityDescription) -> None: + # """Set up entity naming and translation placeholders.""" + # if self.coordinator.source_entity_id and not self.coordinator.device_id: + # self._attr_translation_placeholders = { + # "device_name": self.coordinator.device_name + " " + # } + # self.entity_id = ( + # f"sensor.{self.coordinator.device_name.lower()}_{description.key}" + # ) + # elif self.coordinator.source_entity_id and self.coordinator.device_id: + # source_entity_domain, source_object_id = split_entity_id( + # self.coordinator.source_entity_id + # ) + # self._attr_translation_placeholders = { + # "device_name": self.coordinator.source_entity_name + " " + # } + # self.entity_id = f"sensor.{source_object_id}_{description.key}" + # else: + # self._attr_translation_placeholders = {"device_name": ""} + # self.entity_id = ( + # f"sensor.{self.coordinator.device_name.lower()}_{description.key}" + # ) + + def _setup_device_association( + self, hass: "HomeAssistant", device_registry: dr.DeviceRegistry + ) -> None: + """Set up device association.""" + if self.coordinator.device_id and ( + device_registry.async_get(self.coordinator.device_id) + ): + # Attach to the device_id + self.device_entry = device_registry.async_get(self.coordinator.device_id) + elif self.coordinator.source_entity_id: + device_id = async_entity_id_to_device_id( + hass, self.coordinator.source_entity_id + ) + # source_entity_id is attached to a device, use that and add + if device_id and (device_entry := device_registry.async_get(device_id)): + self.device_entry = device_entry + else: + # No device, leave hanging + self.device_entry = None diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 73aba5e63..d270ae9fa 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -74,16 +74,16 @@ ATTR_DEVICE_ID, ATTR_DEVICE_NAME, ATTR_SOURCE_ENTITY_ID, + CONF_ADVANCED_SETTINGS, CONF_BATTERY_QUANTITY, CONF_BATTERY_TYPE, + CONF_ENABLE_REPLACED, CONF_SOURCE_ENTITY_ID, DOMAIN, PLATFORMS, ) from .coordinator import MY_KEY, BatteryNotesConfigEntry, BatteryNotesCoordinator -from .entity import ( - BatteryNotesEntityDescription, -) +from .entity import BatteryNoteEntity, BatteryNotesEntityDescription @dataclass(frozen=True, kw_only=True) @@ -151,6 +151,15 @@ async def async_setup_entry( entity_category=EntityCategory.DIAGNOSTIC, ) + last_replaced_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="_battery_last_replaced", + key="battery_last_replaced", + translation_key="battery_last_replaced", + entity_category=EntityCategory.DIAGNOSTIC, + device_class=SensorDeviceClass.TIMESTAMP, + entity_registry_enabled_default=config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), + ) + entities = [ BatteryNotesTypeSensor( hass, @@ -160,6 +169,14 @@ async def async_setup_entry( type_sensor_entity_description, f"{config_entry.entry_id}{subentry.unique_id}{type_sensor_entity_description.unique_id_suffix}", ), + BatteryNotesLastReplacedSensor( + hass, + config_entry, + subentry, + coordinator, + last_replaced_sensor_entity_description, + f"{config_entry.entry_id}{subentry.unique_id}{last_replaced_sensor_entity_description.unique_id_suffix}", + ), ] async_add_entities( @@ -229,13 +246,13 @@ async def _setup_battery_note_subentry( type_sensor_entity_description, f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", ), - # BatteryNotesLastReplacedSensor( - # hass, - # config_entry, - # coordinator, - # last_replaced_sensor_entity_description, - # f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", - # ), + BatteryNotesLastReplacedSensor( + hass, + config_entry, + coordinator, + last_replaced_sensor_entity_description, + f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", + ), ] # if coordinator.wrapped_battery is not None: @@ -305,7 +322,7 @@ async def async_setup_platform( await async_setup_reload_service(hass, DOMAIN, PLATFORMS) -class BatteryNotesTypeSensor(RestoreSensor): +class BatteryNotesTypeSensor(BatteryNoteEntity, RestoreSensor): """Represents a battery note type sensor.""" _attr_should_poll = False @@ -315,7 +332,7 @@ class BatteryNotesTypeSensor(RestoreSensor): def __init__( self, hass, - config_entry: ConfigEntry, + config_entry: BatteryNotesConfigEntry, subentry: ConfigSubentry, coordinator: BatteryNotesCoordinator, description: BatteryNotesSensorEntityDescription, @@ -323,9 +340,7 @@ def __init__( ) -> None: # pylint: disable=unused-argument """Initialize the sensor.""" - super().__init__() - - device_registry = dr.async_get(hass) + super().__init__(hass=hass,coordinator=coordinator) self.coordinator = coordinator @@ -355,21 +370,6 @@ def __init__( self.entity_description = description self._attr_unique_id = unique_id - # If a device_id then attach to that device - if coordinator.device_id and (device_registry.async_get(coordinator.device_id)): - self.device_entry = device_registry.async_get(coordinator.device_id) - - # If not a device_id but source_entity_id is attached to a device, use that and add - elif coordinator.source_entity_id: - device_id = async_entity_id_to_device_id( - hass, coordinator.source_entity_id - ) - if device_id and (device_entry := device_registry.async_get(device_id)): - self.device_entry = device_entry - else: - # TODO: If not a device at all then do something else (this note becomes the device or leave hanging?) - self.device_entry = None - self._battery_type = coordinator.battery_type self._battery_quantity = coordinator.battery_quantity @@ -411,6 +411,97 @@ def extra_state_attributes(self) -> dict[str, Any] | None: attrs.update(super_attrs) return attrs +class BatteryNotesLastReplacedSensor( + BatteryNoteEntity, SensorEntity +): + """Represents a battery note sensor.""" + + _attr_should_poll = False + entity_description: BatteryNotesSensorEntityDescription + + def __init__( + self, + hass, + config_entry: BatteryNotesConfigEntry, + subentry: ConfigSubentry, + coordinator: BatteryNotesCoordinator, + description: BatteryNotesSensorEntityDescription, + unique_id: str, + ) -> None: + # pylint: disable=unused-argument + """Initialize the sensor.""" + super().__init__(hass=hass, coordinator=coordinator) + + self.coordinator = coordinator + + self._attr_has_entity_name = True + + if coordinator.source_entity_id and not coordinator.device_id: + self._attr_translation_placeholders = { + "device_name": coordinator.device_name + " " + } + self.entity_id = ( + f"sensor.{coordinator.device_name.lower()}_{description.key}" + ) + elif coordinator.source_entity_id and coordinator.device_id: + source_entity_domain, source_object_id = split_entity_id( + coordinator.source_entity_id + ) + self._attr_translation_placeholders = { + "device_name": coordinator.source_entity_name + " " + } + self.entity_id = f"sensor.{source_object_id}_{description.key}" + else: + self._attr_translation_placeholders = {"device_name": ""} + self.entity_id = ( + f"sensor.{coordinator.device_name.lower()}_{description.key}" + ) + + self._attr_device_class = description.device_class + self._attr_unique_id = unique_id + self._device_id = coordinator.device_id + self._source_entity_id = coordinator.source_entity_id + self.entity_description = description + self._native_value: datetime | None = None + + self._set_native_value(log_on_error=False) + + device_registry = dr.async_get(hass) + + # if coordinator.device_id and ( + # device_entry := device_registry.async_get(coordinator.device_id) + # ): + # self._attr_device_info = DeviceInfo( + # connections=device_entry.connections, + # identifiers=device_entry.identifiers, + # ) + + async def async_added_to_hass(self) -> None: + """Handle added to Hass.""" + await super().async_added_to_hass() + + def _set_native_value(self, log_on_error=True): + # pylint: disable=unused-argument + + if last_replaced := self.coordinator.last_replaced: + self._native_value = last_replaced + + return True + return False + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + + if last_replaced := self.coordinator.last_replaced: + self._native_value = last_replaced + + self.async_write_ha_state() + + @property + def native_value(self) -> datetime | None: + """Return the native value of the sensor.""" + return self._native_value class BatteryNotesBatteryPlusSensor( RestoreSensor, SensorEntity, CoordinatorEntity[BatteryNotesCoordinator] @@ -798,94 +889,3 @@ def native_value(self) -> StateType | Any | datetime: """Return the value reported by the sensor.""" return self._attr_native_value - -class BatteryNotesLastReplacedSensor( - SensorEntity, CoordinatorEntity[BatteryNotesCoordinator] -): - """Represents a battery note sensor.""" - - _attr_should_poll = False - entity_description: BatteryNotesSensorEntityDescription - - def __init__( - self, - hass, - config_entry: ConfigEntry, - coordinator: BatteryNotesCoordinator, - description: BatteryNotesSensorEntityDescription, - unique_id: str, - ) -> None: - # pylint: disable=unused-argument - """Initialize the sensor.""" - super().__init__(coordinator) - - self.coordinator = coordinator - - self._attr_has_entity_name = True - - if coordinator.source_entity_id and not coordinator.device_id: - self._attr_translation_placeholders = { - "device_name": coordinator.device_name + " " - } - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( - coordinator.source_entity_id - ) - self._attr_translation_placeholders = { - "device_name": coordinator.source_entity_name + " " - } - self.entity_id = f"sensor.{source_object_id}_{description.key}" - else: - self._attr_translation_placeholders = {"device_name": ""} - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - - self._attr_device_class = description.device_class - self._attr_unique_id = unique_id - self._device_id = coordinator.device_id - self._source_entity_id = coordinator.source_entity_id - self.entity_description = description - self._native_value: datetime | None = None - - self._set_native_value(log_on_error=False) - - device_registry = dr.async_get(hass) - - if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) - ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, - ) - - async def async_added_to_hass(self) -> None: - """Handle added to Hass.""" - await super().async_added_to_hass() - - def _set_native_value(self, log_on_error=True): - # pylint: disable=unused-argument - - if last_replaced := self.coordinator.last_replaced: - self._native_value = last_replaced - - return True - return False - - @callback - def _handle_coordinator_update(self) -> None: - """Handle updated data from the coordinator.""" - - if last_replaced := self.coordinator.last_replaced: - self._native_value = last_replaced - - self.async_write_ha_state() - - @property - def native_value(self) -> datetime | None: - """Return the native value of the sensor.""" - return self._native_value From b12b0aef9594e28d190320b7f3ee4d19523debfa Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 8 Aug 2025 14:50:15 +0000 Subject: [PATCH 044/235] Refactor BatteryNotesEntity and related classes for improved device association and entity management --- custom_components/battery_notes/entity.py | 13 +- custom_components/battery_notes/sensor.py | 180 ++++++---------------- 2 files changed, 58 insertions(+), 135 deletions(-) diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index 174bbb83a..8177dff9a 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -19,6 +19,7 @@ class BatteryNotesRequiredKeysMixin: """Mixin for required keys.""" unique_id_suffix: str + require_device: bool = False @dataclass(frozen=True, kw_only=True) @@ -26,12 +27,16 @@ class BatteryNotesEntityDescription(EntityDescription, BatteryNotesRequiredKeysM """Generic Battery Notes entity description.""" -class BatteryNoteEntity(CoordinatorEntity[BatteryNotesCoordinator]): +class BatteryNotesEntity(CoordinatorEntity[BatteryNotesCoordinator]): """Base class for Battery Notes entities.""" + coordinator: BatteryNotesCoordinator + entity_description: BatteryNotesEntityDescription + def __init__( self, hass: HomeAssistant, + entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesCoordinator, ) -> None: """Initialize the base entity.""" @@ -39,7 +44,9 @@ def __init__( device_registry = dr.async_get(hass) + self.entity_description = entity_description self.coordinator = coordinator + self._attr_has_entity_name = True # Set up entity naming and translation placeholders @@ -72,7 +79,7 @@ def __init__( # ) def _setup_device_association( - self, hass: "HomeAssistant", device_registry: dr.DeviceRegistry + self, hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: """Set up device association.""" if self.coordinator.device_id and ( @@ -80,7 +87,7 @@ def _setup_device_association( ): # Attach to the device_id self.device_entry = device_registry.async_get(self.coordinator.device_id) - elif self.coordinator.source_entity_id: + elif self.entity_description.require_device is False and self.coordinator.source_entity_id: device_id = async_entity_id_to_device_id( hass, self.coordinator.source_entity_id ) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index d270ae9fa..4343b8029 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -78,12 +78,13 @@ CONF_BATTERY_QUANTITY, CONF_BATTERY_TYPE, CONF_ENABLE_REPLACED, + CONF_ROUND_BATTERY, CONF_SOURCE_ENTITY_ID, DOMAIN, PLATFORMS, ) from .coordinator import MY_KEY, BatteryNotesConfigEntry, BatteryNotesCoordinator -from .entity import BatteryNoteEntity, BatteryNotesEntityDescription +from .entity import BatteryNotesEntity, BatteryNotesEntityDescription @dataclass(frozen=True, kw_only=True) @@ -108,29 +109,13 @@ class BatteryNotesSensorEntityDescription( _LOGGER = logging.getLogger(__name__) - -# @callback -# def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry, subentry: ConfigSubentry) -> str | None: -# """Add our config entry to the device.""" -# device_registry = dr.async_get(hass) - -# device_id = subentry.data.get(CONF_DEVICE_ID) - -# if device_id: -# if device_registry.async_get(device_id): -# device_registry.async_update_device( -# device_id, add_config_entry_id=entry.entry_id -# ) -# return device_id -# return None - - async def async_setup_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Initialize Battery Type config entry.""" + entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) @@ -160,11 +145,21 @@ async def async_setup_entry( entity_registry_enabled_default=config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), ) + battery_plus_sensor_entity_description = BatteryNotesSensorEntityDescription( + unique_id_suffix="_battery_plus", + key="battery_plus", + translation_key="battery_plus", + device_class=SensorDeviceClass.BATTERY, + suggested_display_precision=0 if config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, True) else 1, + require_device= True, + ) + entities = [ BatteryNotesTypeSensor( hass, config_entry, subentry, + type_sensor_entity_description, coordinator, type_sensor_entity_description, f"{config_entry.entry_id}{subentry.unique_id}{type_sensor_entity_description.unique_id_suffix}", @@ -173,102 +168,34 @@ async def async_setup_entry( hass, config_entry, subentry, + last_replaced_sensor_entity_description, coordinator, last_replaced_sensor_entity_description, f"{config_entry.entry_id}{subentry.unique_id}{last_replaced_sensor_entity_description.unique_id_suffix}", ), ] + + if coordinator.wrapped_battery is not None: + entities.append( + BatteryNotesBatteryPlusSensor( + hass, + config_entry, + subentry, + battery_plus_sensor_entity_description, + coordinator, + battery_plus_sensor_entity_description, + f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", + config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), + config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, False), + ) + ) + async_add_entities( entities, config_subentry_id=subentry.subentry_id, ) - # await _setup_battery_note_subentry(hass, config_entry, subentry, async_add_entities) - - -async def _setup_battery_note_subentry( - hass: HomeAssistant, - config_entry: BatteryNotesConfigEntry, - subentry: ConfigSubentry, - async_add_entities: AddConfigEntryEntitiesCallback, -) -> None: - """Set up a battery_note subentry.""" - entity_registry = er.async_get(hass) - device_registry = dr.async_get(hass) - - device_id = subentry.data.get(CONF_DEVICE_ID, None) - - coordinator = config_entry.runtime_data.subentry_coordinators.get( - subentry.subentry_id - ) - assert coordinator - - # if not coordinator.fake_device: - # device_id = async_add_to_device(hass, config_entry, subentry) - # if not device_id: - # return - - await coordinator.async_refresh() - - domain_config = hass.data[MY_KEY] - - battery_plus_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="_battery_plus", - key="battery_plus", - translation_key="battery_plus", - device_class=SensorDeviceClass.BATTERY, - suggested_display_precision=0 if domain_config.round_battery else 1, - ) - - type_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix - key="battery_type", - translation_key="battery_type", - entity_category=EntityCategory.DIAGNOSTIC, - ) - - last_replaced_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="_battery_last_replaced", - key="battery_last_replaced", - translation_key="battery_last_replaced", - entity_category=EntityCategory.DIAGNOSTIC, - device_class=SensorDeviceClass.TIMESTAMP, - entity_registry_enabled_default=domain_config.enable_replaced, - ) - - entities = [ - BatteryNotesTypeSensor( - hass, - config_entry, - subentry, - coordinator, - type_sensor_entity_description, - f"{config_entry.entry_id}{type_sensor_entity_description.unique_id_suffix}", - ), - BatteryNotesLastReplacedSensor( - hass, - config_entry, - coordinator, - last_replaced_sensor_entity_description, - f"{config_entry.entry_id}{last_replaced_sensor_entity_description.unique_id_suffix}", - ), - ] - - # if coordinator.wrapped_battery is not None: - # entities.append( - # BatteryNotesBatteryPlusSensor( - # hass, - # config_entry, - # subentry, - # coordinator, - # battery_plus_sensor_entity_description, - # f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", - # domain_config.enable_replaced, - # domain_config.round_battery, - # ) - # ) - async def async_registry_updated( event: Event[er.EventEntityRegistryUpdatedData], ) -> None: @@ -308,11 +235,6 @@ async def async_registry_updated( ) ) - async_add_entities( - entities, - config_subentry_id=subentry.subentry_id, - ) - async def async_setup_platform( hass: HomeAssistant, @@ -322,7 +244,7 @@ async def async_setup_platform( await async_setup_reload_service(hass, DOMAIN, PLATFORMS) -class BatteryNotesTypeSensor(BatteryNoteEntity, RestoreSensor): +class BatteryNotesTypeSensor(BatteryNotesEntity, RestoreSensor): """Represents a battery note type sensor.""" _attr_should_poll = False @@ -334,13 +256,14 @@ def __init__( hass, config_entry: BatteryNotesConfigEntry, subentry: ConfigSubentry, + entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesCoordinator, description: BatteryNotesSensorEntityDescription, unique_id: str, ) -> None: # pylint: disable=unused-argument """Initialize the sensor.""" - super().__init__(hass=hass,coordinator=coordinator) + super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) self.coordinator = coordinator @@ -412,7 +335,7 @@ def extra_state_attributes(self) -> dict[str, Any] | None: return attrs class BatteryNotesLastReplacedSensor( - BatteryNoteEntity, SensorEntity + BatteryNotesEntity, SensorEntity ): """Represents a battery note sensor.""" @@ -424,13 +347,14 @@ def __init__( hass, config_entry: BatteryNotesConfigEntry, subentry: ConfigSubentry, + entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesCoordinator, description: BatteryNotesSensorEntityDescription, unique_id: str, ) -> None: # pylint: disable=unused-argument """Initialize the sensor.""" - super().__init__(hass=hass, coordinator=coordinator) + super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) self.coordinator = coordinator @@ -466,16 +390,6 @@ def __init__( self._set_native_value(log_on_error=False) - device_registry = dr.async_get(hass) - - # if coordinator.device_id and ( - # device_entry := device_registry.async_get(coordinator.device_id) - # ): - # self._attr_device_info = DeviceInfo( - # connections=device_entry.connections, - # identifiers=device_entry.identifiers, - # ) - async def async_added_to_hass(self) -> None: """Handle added to Hass.""" await super().async_added_to_hass() @@ -504,7 +418,7 @@ def native_value(self) -> datetime | None: return self._native_value class BatteryNotesBatteryPlusSensor( - RestoreSensor, SensorEntity, CoordinatorEntity[BatteryNotesCoordinator] + BatteryNotesEntity, RestoreSensor ): """Represents a battery plus type sensor.""" @@ -529,7 +443,9 @@ class BatteryNotesBatteryPlusSensor( def __init__( self, hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: BatteryNotesConfigEntry, + subentry: ConfigSubentry, + entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesCoordinator, description: BatteryNotesSensorEntityDescription, unique_id: str, @@ -537,7 +453,7 @@ def __init__( round_battery: bool, ) -> None: """Initialize the sensor.""" - super().__init__(coordinator) + super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) device_registry = dr.async_get(hass) @@ -575,13 +491,13 @@ def __init__( self._device_id = coordinator.device_id self._source_entity_id = coordinator.source_entity_id - if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) - ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, - ) + # if coordinator.device_id and ( + # device_entry := device_registry.async_get(coordinator.device_id) + # ): + # self._attr_device_info = DeviceInfo( + # connections=device_entry.connections, + # identifiers=device_entry.identifiers, + # ) entity_category = ( coordinator.wrapped_battery.entity_category From 29a1041ac33e6c720452fca7e102d621ac8ec62b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 8 Aug 2025 15:14:41 +0000 Subject: [PATCH 045/235] Fix formatting of require_device parameter in async_setup_entry function --- custom_components/battery_notes/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 4343b8029..6b17593fe 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -151,7 +151,7 @@ async def async_setup_entry( translation_key="battery_plus", device_class=SensorDeviceClass.BATTERY, suggested_display_precision=0 if config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, True) else 1, - require_device= True, + require_device=True, ) entities = [ From 2e0f8b0d5a5004797d358c1d0235d2b09bfb686b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 8 Aug 2025 15:51:42 +0000 Subject: [PATCH 046/235] Refactor imports in __init__.py and sensor.py to streamline code and remove unused dependencies --- custom_components/battery_notes/__init__.py | 2 +- custom_components/battery_notes/sensor.py | 67 +-------------------- 2 files changed, 4 insertions(+), 65 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index d19d3ad0a..9129056e4 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -12,7 +12,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigSubentry +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import CONF_SOURCE from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 6b17593fe..70544b0d2 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -17,7 +17,7 @@ SensorEntityDescription, SensorStateClass, ) -from homeassistant.config_entries import ConfigEntry, ConfigSubentry +from homeassistant.config_entries import ConfigSubentry from homeassistant.const import ( CONF_DEVICE_ID, CONF_NAME, @@ -29,37 +29,22 @@ from homeassistant.helpers import ( config_validation as cv, ) -from homeassistant.helpers import ( - device_registry as dr, -) from homeassistant.helpers import ( entity_registry as er, ) -from homeassistant.helpers.device import ( - async_entity_id_to_device, - async_entity_id_to_device_id, - async_remove_stale_devices_links_keep_entity_device, -) -from homeassistant.helpers.entity import DeviceInfo, EntityCategory -from homeassistant.helpers.entity_platform import ( - AddConfigEntryEntitiesCallback, - AddEntitiesCallback, -) +from homeassistant.helpers.entity import EntityCategory +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_registry import ( EVENT_ENTITY_REGISTRY_UPDATED, ) from homeassistant.helpers.event import ( EventStateChangedData, EventStateReportedData, - async_track_entity_registry_updated_event, async_track_state_change_event, async_track_state_report_event, ) from homeassistant.helpers.reload import async_setup_reload_service from homeassistant.helpers.typing import StateType -from homeassistant.helpers.update_coordinator import ( - CoordinatorEntity, -) from .common import utcnow_no_timezone, validate_is_float from .const import ( @@ -116,14 +101,10 @@ async def async_setup_entry( ) -> None: """Initialize Battery Type config entry.""" - entity_registry = er.async_get(hass) - device_registry = dr.async_get(hass) - for subentry in config_entry.subentries.values(): if subentry.subentry_type != "battery_note": continue - device_id = subentry.data.get(CONF_DEVICE_ID, None) coordinator = config_entry.runtime_data.subentry_coordinators.get( subentry.subentry_id ) @@ -175,7 +156,6 @@ async def async_setup_entry( ), ] - if coordinator.wrapped_battery is not None: entities.append( BatteryNotesBatteryPlusSensor( @@ -196,45 +176,6 @@ async def async_setup_entry( config_subentry_id=subentry.subentry_id, ) - async def async_registry_updated( - event: Event[er.EventEntityRegistryUpdatedData], - ) -> None: - """Handle entity registry update.""" - data = event.data - if data["action"] == "remove": - await hass.config_entries.async_remove(config_entry.entry_id) - - if data["action"] != "update": - return - - if "entity_id" in data["changes"]: - # Entity_id replaced, reload the config entry - await hass.config_entries.async_reload(config_entry.entry_id) - - if device_id and "device_id" in data["changes"]: - # If the tracked battery note is no longer in the device, remove our config entry - # from the device - if ( - not (entity_entry := entity_registry.async_get(data["entity_id"])) - or not device_registry.async_get(device_id) - or entity_entry.device_id == device_id - ): - # No need to do any cleanup - return - - device_registry.async_update_device( - device_id, remove_config_entry_id=config_entry.entry_id - ) - - config_entry.async_on_unload( - async_track_entity_registry_updated_event( - # TODO: This doesnt look right, should be entity_id - hass, - config_entry.entry_id, - async_registry_updated, - ) - ) - async def async_setup_platform( hass: HomeAssistant, @@ -455,8 +396,6 @@ def __init__( """Initialize the sensor.""" super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) - device_registry = dr.async_get(hass) - self.config_entry = config_entry self.coordinator = coordinator From e0ca4e9fa28a971ca69fda5e0aa463885ea33824 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 8 Aug 2025 16:00:25 +0000 Subject: [PATCH 047/235] Refactor button.py and entity.py to remove unused imports and streamline code --- custom_components/battery_notes/button.py | 42 +---------------------- custom_components/battery_notes/entity.py | 1 - 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index bba0afbba..4a0857350 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -15,7 +15,7 @@ CONF_DEVICE_ID, CONF_NAME, ) -from homeassistant.core import Event, HomeAssistant, callback, split_entity_id +from homeassistant.core import HomeAssistant, callback, split_entity_id from homeassistant.helpers import ( config_validation as cv, ) @@ -27,9 +27,6 @@ ) from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.event import ( - async_track_entity_registry_updated_event, -) from homeassistant.helpers.reload import async_setup_reload_service from . import PLATFORMS @@ -94,49 +91,12 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Initialize Battery Type config entry.""" - entity_registry = er.async_get(hass) - device_registry = dr.async_get(hass) device_id = config_entry.data.get(CONF_DEVICE_ID, None) - async def async_registry_updated(event: Event[er.EventEntityRegistryUpdatedData]) -> None: - """Handle entity registry update.""" - data = event.data - if data["action"] == "remove": - await hass.config_entries.async_remove(config_entry.entry_id) - - if data["action"] != "update": - return - - if "entity_id" in data["changes"]: - # Entity_id changed, reload the config entry - await hass.config_entries.async_reload(config_entry.entry_id) - - if device_id and "device_id" in data["changes"]: - # If the tracked battery note is no longer in the device, remove our config entry - # from the device - if ( - not (entity_entry := entity_registry.async_get(data["entity_id"])) - or not device_registry.async_get(device_id) - or entity_entry.device_id == device_id - ): - # No need to do any cleanup - return - - device_registry.async_update_device( - device_id, remove_config_entry_id=config_entry.entry_id - ) - coordinator = config_entry.runtime_data.coordinator assert(coordinator) - config_entry.async_on_unload( - async_track_entity_registry_updated_event( - #TODO: This doesnt look right, should be entity_id - hass, config_entry.entry_id, async_registry_updated - ) - ) - if not coordinator.fake_device: device_id = async_add_to_device(hass, config_entry) diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index 8177dff9a..4b4576f10 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -3,7 +3,6 @@ from __future__ import annotations from dataclasses import dataclass -from typing import TYPE_CHECKING from homeassistant.core import HomeAssistant, split_entity_id from homeassistant.helpers import device_registry as dr From 7b45623436a81184506f18b71d1528f070e93799 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 12:18:06 +0000 Subject: [PATCH 048/235] Refactor entity and sensor classes to improve entity ID setup and streamline device association --- custom_components/battery_notes/entity.py | 55 +++++++-------- custom_components/battery_notes/sensor.py | 81 ++--------------------- 2 files changed, 32 insertions(+), 104 deletions(-) diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index 4b4576f10..0ba39d58e 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -18,6 +18,7 @@ class BatteryNotesRequiredKeysMixin: """Mixin for required keys.""" unique_id_suffix: str + entity_type: str require_device: bool = False @@ -49,35 +50,35 @@ def __init__( self._attr_has_entity_name = True # Set up entity naming and translation placeholders - # self._setup_entity_naming(description) + self._set_entity_id(entity_description) # Set up device association - self._setup_device_association(hass, device_registry) - - # def _setup_entity_naming(self, description: BatteryNotesEntityDescription) -> None: - # """Set up entity naming and translation placeholders.""" - # if self.coordinator.source_entity_id and not self.coordinator.device_id: - # self._attr_translation_placeholders = { - # "device_name": self.coordinator.device_name + " " - # } - # self.entity_id = ( - # f"sensor.{self.coordinator.device_name.lower()}_{description.key}" - # ) - # elif self.coordinator.source_entity_id and self.coordinator.device_id: - # source_entity_domain, source_object_id = split_entity_id( - # self.coordinator.source_entity_id - # ) - # self._attr_translation_placeholders = { - # "device_name": self.coordinator.source_entity_name + " " - # } - # self.entity_id = f"sensor.{source_object_id}_{description.key}" - # else: - # self._attr_translation_placeholders = {"device_name": ""} - # self.entity_id = ( - # f"sensor.{self.coordinator.device_name.lower()}_{description.key}" - # ) - - def _setup_device_association( + self._associate_device(hass, device_registry) + + def _set_entity_id(self, entity_description: BatteryNotesEntityDescription) -> None: + """Set up entity naming and translation placeholders.""" + if self.coordinator.source_entity_id and not self.coordinator.device_id: + self._attr_translation_placeholders = { + "device_name": self.coordinator.device_name + " " + } + self.entity_id = ( + f"{entity_description.entity_type}.{self.coordinator.device_name.lower()}_{entity_description.key}" + ) + elif self.coordinator.source_entity_id and self.coordinator.device_id: + source_entity_domain, source_object_id = split_entity_id( + self.coordinator.source_entity_id + ) + self._attr_translation_placeholders = { + "device_name": self.coordinator.source_entity_name + " " + } + self.entity_id = f"{entity_description.entity_type}.{source_object_id}_{entity_description.key}" + else: + self._attr_translation_placeholders = {"device_name": ""} + self.entity_id = ( + f"{entity_description.entity_type}.{self.coordinator.device_name.lower()}_{entity_description.key}" + ) + + def _associate_device( self, hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: """Set up device association.""" diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 70544b0d2..5868336a3 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -25,7 +25,7 @@ STATE_UNAVAILABLE, STATE_UNKNOWN, ) -from homeassistant.core import Event, HomeAssistant, callback, split_entity_id +from homeassistant.core import Event, HomeAssistant, callback from homeassistant.helpers import ( config_validation as cv, ) @@ -115,6 +115,7 @@ async def async_setup_entry( key="battery_type", translation_key="battery_type", entity_category=EntityCategory.DIAGNOSTIC, + entity_type="sensor", ) last_replaced_sensor_entity_description = BatteryNotesSensorEntityDescription( @@ -124,6 +125,7 @@ async def async_setup_entry( entity_category=EntityCategory.DIAGNOSTIC, device_class=SensorDeviceClass.TIMESTAMP, entity_registry_enabled_default=config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), + entity_type="sensor", ) battery_plus_sensor_entity_description = BatteryNotesSensorEntityDescription( @@ -132,6 +134,7 @@ async def async_setup_entry( translation_key="battery_plus", device_class=SensorDeviceClass.BATTERY, suggested_display_precision=0 if config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, True) else 1, + entity_type="sensor", require_device=True, ) @@ -206,31 +209,8 @@ def __init__( """Initialize the sensor.""" super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) - self.coordinator = coordinator - self._attr_has_entity_name = True - if coordinator.source_entity_id and not coordinator.device_id: - self._attr_translation_placeholders = { - "device_name": coordinator.device_name + " " - } - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( - coordinator.source_entity_id - ) - self._attr_translation_placeholders = { - "device_name": coordinator.source_entity_name + " " - } - self.entity_id = f"sensor.{source_object_id}_{description.key}" - else: - self._attr_translation_placeholders = {"device_name": ""} - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - self.entity_description = description self._attr_unique_id = unique_id @@ -297,31 +277,8 @@ def __init__( """Initialize the sensor.""" super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) - self.coordinator = coordinator - self._attr_has_entity_name = True - if coordinator.source_entity_id and not coordinator.device_id: - self._attr_translation_placeholders = { - "device_name": coordinator.device_name + " " - } - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( - coordinator.source_entity_id - ) - self._attr_translation_placeholders = { - "device_name": coordinator.source_entity_name + " " - } - self.entity_id = f"sensor.{source_object_id}_{description.key}" - else: - self._attr_translation_placeholders = {"device_name": ""} - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - self._attr_device_class = description.device_class self._attr_unique_id = unique_id self._device_id = coordinator.device_id @@ -397,31 +354,9 @@ def __init__( super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) self.config_entry = config_entry - self.coordinator = coordinator self._attr_has_entity_name = True - if coordinator.source_entity_id and not coordinator.device_id: - self._attr_translation_placeholders = { - "device_name": coordinator.device_name + " " - } - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( - coordinator.source_entity_id - ) - self._attr_translation_placeholders = { - "device_name": coordinator.source_entity_name + " " - } - self.entity_id = f"sensor.{source_object_id}_{description.key}" - else: - self._attr_translation_placeholders = {"device_name": ""} - self.entity_id = ( - f"sensor.{coordinator.device_name.lower()}_{description.key}" - ) - self.entity_description = description self._attr_unique_id = unique_id self.enable_replaced = enable_replaced @@ -430,14 +365,6 @@ def __init__( self._device_id = coordinator.device_id self._source_entity_id = coordinator.source_entity_id - # if coordinator.device_id and ( - # device_entry := device_registry.async_get(coordinator.device_id) - # ): - # self._attr_device_info = DeviceInfo( - # connections=device_entry.connections, - # identifiers=device_entry.identifiers, - # ) - entity_category = ( coordinator.wrapped_battery.entity_category if coordinator.wrapped_battery From 378801855ccd1f152dd5e1841ed18f5ba4d96ab5 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 12:37:53 +0000 Subject: [PATCH 049/235] Refactor button and sensor modules to streamline entity initialization and improve code clarity --- custom_components/battery_notes/button.py | 96 +++++++++-------------- custom_components/battery_notes/const.py | 2 +- custom_components/battery_notes/sensor.py | 13 --- 3 files changed, 40 insertions(+), 71 deletions(-) diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 4a0857350..399b46790 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -25,8 +25,8 @@ from homeassistant.helpers import ( entity_registry as er, ) -from homeassistant.helpers.entity import DeviceInfo, EntityCategory -from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.entity import EntityCategory +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.reload import async_setup_reload_service from . import PLATFORMS @@ -43,9 +43,7 @@ EVENT_BATTERY_REPLACED, ) from .coordinator import BatteryNotesConfigEntry, BatteryNotesCoordinator -from .entity import ( - BatteryNotesEntityDescription, -) +from .entity import BatteryNotesEntity, BatteryNotesEntityDescription _LOGGER = logging.getLogger(__name__) @@ -88,40 +86,39 @@ def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry) -> async def async_setup_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, - async_add_entities: AddEntitiesCallback, + async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Initialize Battery Type config entry.""" - device_id = config_entry.data.get(CONF_DEVICE_ID, None) - - coordinator = config_entry.runtime_data.coordinator - assert(coordinator) - - if not coordinator.fake_device: - device_id = async_add_to_device(hass, config_entry) - - if not device_id: - return - - description = BatteryNotesButtonEntityDescription( - unique_id_suffix="_battery_replaced_button", - key="battery_replaced", - translation_key="battery_replaced", - entity_category=EntityCategory.DIAGNOSTIC, - entity_registry_enabled_default=config_entry.runtime_data.domain_config.enable_replaced, - ) - - async_add_entities( - [ - BatteryNotesButton( - hass, - coordinator, - description, - f"{config_entry.entry_id}{description.unique_id_suffix}", - device_id, - ) - ] - ) + for subentry in config_entry.subentries.values(): + if subentry.subentry_type != "battery_note": + continue + + coordinator = config_entry.runtime_data.subentry_coordinators.get( + subentry.subentry_id + ) + assert coordinator + + description = BatteryNotesButtonEntityDescription( + unique_id_suffix="_battery_replaced_button", + key="battery_replaced", + translation_key="battery_replaced", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=config_entry.runtime_data.domain_config.enable_replaced, + entity_type="button", + ) + + async_add_entities( + [ + BatteryNotesButton( + hass, + coordinator, + description, + f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + ) + ], + config_subentry_id=subentry.subentry_id, + ) async def async_setup_platform( @@ -132,7 +129,7 @@ async def async_setup_platform( await async_setup_reload_service(hass, DOMAIN, PLATFORMS) -class BatteryNotesButton(ButtonEntity): +class BatteryNotesButton(BatteryNotesEntity, ButtonEntity): """Represents a battery replaced button.""" _attr_should_poll = False @@ -143,26 +140,19 @@ def __init__( self, hass: HomeAssistant, coordinator: BatteryNotesCoordinator, - description: BatteryNotesButtonEntityDescription, + entity_description: BatteryNotesButtonEntityDescription, unique_id: str, - device_id: str, ) -> None: """Create a battery replaced button.""" - super().__init__() - - device_registry = dr.async_get(hass) - - self.coordinator = coordinator - - self._attr_has_entity_name = True + super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) if coordinator.source_entity_id and not coordinator.device_id: self._attr_translation_placeholders = { "device_name": coordinator.device_name + " " } self.entity_id = ( - f"button.{coordinator.device_name.lower()}_{description.key}" + f"button.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: source_entity_domain, source_object_id = split_entity_id( @@ -171,24 +161,16 @@ def __init__( self._attr_translation_placeholders = { "device_name": coordinator.source_entity_name + " " } - self.entity_id = f"button.{source_object_id}_{description.key}" + self.entity_id = f"button.{source_object_id}_{entity_description.key}" else: self._attr_translation_placeholders = {"device_name": ""} self.entity_id = ( - f"button.{coordinator.device_name.lower()}_{description.key}" + f"button.{coordinator.device_name.lower()}_{entity_description.key}" ) - self.entity_description = description self._attr_unique_id = unique_id - self._device_id = device_id self._source_entity_id = coordinator.source_entity_id - if device_id and (device := device_registry.async_get(device_id)): - self._attr_device_info = DeviceInfo( - connections=device.connections, - identifiers=device.identifiers, - ) - async def async_added_to_hass(self) -> None: """Handle added to Hass.""" registry = er.async_get(self.hass) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 7f036d21a..0e57517fc 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -110,7 +110,7 @@ # TODO: Change back to all platforms once all completed PLATFORMS: Final = [ - # Platform.BUTTON, + Platform.BUTTON, Platform.SENSOR, # Platform.BINARY_SENSOR, ] diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 5868336a3..1d0e2c94a 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -145,7 +145,6 @@ async def async_setup_entry( subentry, type_sensor_entity_description, coordinator, - type_sensor_entity_description, f"{config_entry.entry_id}{subentry.unique_id}{type_sensor_entity_description.unique_id_suffix}", ), BatteryNotesLastReplacedSensor( @@ -167,7 +166,6 @@ async def async_setup_entry( subentry, battery_plus_sensor_entity_description, coordinator, - battery_plus_sensor_entity_description, f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, False), @@ -202,16 +200,12 @@ def __init__( subentry: ConfigSubentry, entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesCoordinator, - description: BatteryNotesSensorEntityDescription, unique_id: str, ) -> None: # pylint: disable=unused-argument """Initialize the sensor.""" super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) - self._attr_has_entity_name = True - - self.entity_description = description self._attr_unique_id = unique_id self._battery_type = coordinator.battery_type @@ -277,13 +271,10 @@ def __init__( """Initialize the sensor.""" super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) - self._attr_has_entity_name = True - self._attr_device_class = description.device_class self._attr_unique_id = unique_id self._device_id = coordinator.device_id self._source_entity_id = coordinator.source_entity_id - self.entity_description = description self._native_value: datetime | None = None self._set_native_value(log_on_error=False) @@ -345,7 +336,6 @@ def __init__( subentry: ConfigSubentry, entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesCoordinator, - description: BatteryNotesSensorEntityDescription, unique_id: str, enable_replaced: bool, round_battery: bool, @@ -355,9 +345,6 @@ def __init__( self.config_entry = config_entry - self._attr_has_entity_name = True - - self.entity_description = description self._attr_unique_id = unique_id self.enable_replaced = enable_replaced self.round_battery = round_battery From ee7362f469453c24a9b8385388c7316968b85a7f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 13:46:58 +0000 Subject: [PATCH 050/235] Refactor binary sensor, button, and sensor modules to improve entity handling and streamline code structure --- .../battery_notes/binary_sensor.py | 237 ++++++------------ custom_components/battery_notes/button.py | 25 -- custom_components/battery_notes/const.py | 3 +- custom_components/battery_notes/sensor.py | 10 - 4 files changed, 73 insertions(+), 202 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index a8bf1642a..53be86ea3 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -40,7 +40,7 @@ template, ) from homeassistant.helpers.entity import DeviceInfo, Entity, EntityCategory -from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_registry import ( EVENT_ENTITY_REGISTRY_UPDATED, ) @@ -52,7 +52,6 @@ async_track_state_change_event, async_track_template_result, ) -from homeassistant.helpers.reload import async_setup_reload_service from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.start import async_at_start from homeassistant.helpers.template import ( @@ -63,7 +62,6 @@ CoordinatorEntity, ) -from . import PLATFORMS from .common import validate_is_float from .const import ( ATTR_BATTERY_LAST_REPLACED, @@ -82,9 +80,7 @@ BatteryNotesConfigEntry, BatteryNotesCoordinator, ) -from .entity import ( - BatteryNotesEntityDescription, -) +from .entity import BatteryNotesEntity, BatteryNotesEntityDescription _LOGGER = logging.getLogger(__name__) @@ -127,113 +123,67 @@ def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry) -> async def async_setup_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, - async_add_entities: AddEntitiesCallback, + async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Initialize Battery Type config entry.""" - entity_registry = er.async_get(hass) - device_registry = dr.async_get(hass) - - - async def async_registry_updated( - event: Event[er.EventEntityRegistryUpdatedData], - ) -> None: - """Handle entity registry update.""" - data = event.data - if data["action"] == "remove": - await hass.config_entries.async_remove(config_entry.entry_id) - - if data["action"] != "update": - return - - if "entity_id" in data["changes"]: - # Entity_id changed, reload the config entry - await hass.config_entries.async_reload(config_entry.entry_id) - - if device_id and "device_id" in data["changes"]: - # If the tracked battery note is no longer in the device, remove our config entry - # from the device - if ( - not (entity_entry := entity_registry.async_get(data["entity_id"])) - or not device_registry.async_get(device_id) - or entity_entry.device_id == device_id - ): - # No need to do any cleanup - return - - device_registry.async_update_device( - device_id, remove_config_entry_id=config_entry.entry_id - ) - device_id = config_entry.data.get(CONF_DEVICE_ID) - coordinator = config_entry.runtime_data.coordinator - assert(coordinator) + for subentry in config_entry.subentries.values(): + if subentry.subentry_type != "battery_note": + continue - config_entry.async_on_unload( - async_track_entity_registry_updated_event( - #TODO: This doesnt look right, should be entity_id - hass, config_entry.entry_id, async_registry_updated + coordinator = config_entry.runtime_data.subentry_coordinators.get( + subentry.subentry_id ) - ) - - if not coordinator.fake_device: - device_id = async_add_to_device(hass, config_entry) - - if not device_id: - return - - description = BatteryNotesBinarySensorEntityDescription( - unique_id_suffix="_battery_low", - key="_battery_plus_low", - translation_key="battery_low", - entity_category=EntityCategory.DIAGNOSTIC, - device_class=BinarySensorDeviceClass.BATTERY, - ) - - if coordinator.battery_low_template is not None: - async_add_entities( - [ - BatteryNotesBatteryLowTemplateSensor( - hass, - coordinator, - description, - f"{config_entry.entry_id}{description.unique_id_suffix}", - coordinator.battery_low_template, - ) - ] + assert coordinator + + description = BatteryNotesBinarySensorEntityDescription( + unique_id_suffix="_battery_low", + key="_battery_plus_low", + translation_key="battery_low", + entity_category=EntityCategory.DIAGNOSTIC, + device_class=BinarySensorDeviceClass.BATTERY, + entity_type="binary_sensor", ) - elif coordinator.wrapped_battery is not None: - async_add_entities( - [ - BatteryNotesBatteryLowSensor( - hass, - coordinator, - description, - f"{config_entry.entry_id}{description.unique_id_suffix}", - ) - ] - ) - - elif coordinator.wrapped_battery_low is not None: - async_add_entities( - [ - BatteryNotesBatteryBinaryLowSensor( - hass, - coordinator, - description, - f"{config_entry.entry_id}{description.unique_id_suffix}", - ) - ] - ) - - -async def async_setup_platform( - hass: HomeAssistant, -) -> None: - """Set up the battery note sensor.""" + if coordinator.battery_low_template is not None: + async_add_entities( + [ + BatteryNotesBatteryLowTemplateSensor( + hass, + coordinator, + description, + f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + coordinator.battery_low_template, + ) + ], + config_subentry_id=subentry.subentry_id, + ) - await async_setup_reload_service(hass, DOMAIN, PLATFORMS) + elif coordinator.wrapped_battery is not None: + async_add_entities( + [ + BatteryNotesBatteryLowSensor( + hass, + coordinator, + description, + f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + ) + ], + config_subentry_id=subentry.subentry_id, + ) + elif coordinator.wrapped_battery_low is not None: + async_add_entities( + [ + BatteryNotesBatteryBinaryLowSensor( + hass, + coordinator, + description, + f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + ) + ], + config_subentry_id=subentry.subentry_id, + ) class _TemplateAttribute: """Attribute value linked to template result.""" @@ -331,7 +281,7 @@ def handle_result( class BatteryNotesBatteryLowBaseSensor( - BinarySensorEntity, CoordinatorEntity[BatteryNotesCoordinator] + BatteryNotesEntity, BinarySensorEntity ): """Low battery binary sensor base.""" @@ -339,10 +289,11 @@ def __init__( self, hass: HomeAssistant, coordinator: BatteryNotesCoordinator, + entity_description: BatteryNotesBinarySensorEntityDescription, ): """Initialize the low battery binary sensor.""" - super().__init__(coordinator=coordinator) + super().__init__(hass, entity_description=entity_description, coordinator=coordinator) self.enable_replaced = hass.data[MY_KEY].enable_replaced @@ -397,37 +348,23 @@ def __init__( self, hass: HomeAssistant, coordinator: BatteryNotesCoordinator, - description: BatteryNotesBinarySensorEntityDescription, + entity_description: BatteryNotesBinarySensorEntityDescription, unique_id: str, template: str, ) -> None: """Create a low battery binary sensor.""" - device_registry = dr.async_get(hass) + super().__init__(hass=hass, coordinator=coordinator, entity_description=entity_description) - self.coordinator = coordinator - self.entity_description = description self._attr_unique_id = unique_id self._template_attrs: dict[Template, list[_TemplateAttribute]] = {} - super().__init__(hass=hass, coordinator=coordinator) - - if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) - ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, - ) - - self._attr_has_entity_name = True - if coordinator.source_entity_id and not coordinator.device_id: self._attr_translation_placeholders = { "device_name": coordinator.device_name + " " } self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{description.key}" + f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: source_entity_domain, source_object_id = split_entity_id( @@ -436,11 +373,11 @@ def __init__( self._attr_translation_placeholders = { "device_name": coordinator.source_entity_name + " " } - self.entity_id = f"binary_sensor.{source_object_id}_{description.key}" + self.entity_id = f"binary_sensor.{source_object_id}_{entity_description.key}" else: self._attr_translation_placeholders = {"device_name": ""} self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{description.key}" + f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) self._template = template @@ -606,22 +543,18 @@ def __init__( self, hass: HomeAssistant, coordinator: BatteryNotesCoordinator, - description: BatteryNotesBinarySensorEntityDescription, + entity_description: BatteryNotesBinarySensorEntityDescription, unique_id: str, ) -> None: """Create a low battery binary sensor.""" - - device_registry = dr.async_get(hass) - - self.coordinator = coordinator - self._attr_has_entity_name = True + super().__init__(hass=hass, coordinator=coordinator, entity_description=entity_description) if coordinator.source_entity_id and not coordinator.device_id: self._attr_translation_placeholders = { "device_name": coordinator.device_name + " " } self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{description.key}" + f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: source_entity_domain, source_object_id = split_entity_id( @@ -630,26 +563,15 @@ def __init__( self._attr_translation_placeholders = { "device_name": coordinator.source_entity_name + " " } - self.entity_id = f"binary_sensor.{source_object_id}_{description.key}" + self.entity_id = f"binary_sensor.{source_object_id}_{entity_description.key}" else: self._attr_translation_placeholders = {"device_name": ""} self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{description.key}" + f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) - self.entity_description = description self._attr_unique_id = unique_id - super().__init__(hass=hass, coordinator=coordinator) - - if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) - ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, - ) - async def async_added_to_hass(self) -> None: """Handle added to Hass.""" @@ -701,22 +623,18 @@ def __init__( self, hass: HomeAssistant, coordinator: BatteryNotesCoordinator, - description: BatteryNotesBinarySensorEntityDescription, + entity_description: BatteryNotesBinarySensorEntityDescription, unique_id: str, ) -> None: """Create a low battery binary sensor.""" - - device_registry = dr.async_get(hass) - - self.coordinator = coordinator - self._attr_has_entity_name = True + super().__init__(hass=hass, coordinator=coordinator, entity_description=entity_description) if coordinator.source_entity_id and not coordinator.device_id: self._attr_translation_placeholders = { "device_name": coordinator.device_name + " " } self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{description.key}" + f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: source_entity_domain, source_object_id = split_entity_id( @@ -725,26 +643,15 @@ def __init__( self._attr_translation_placeholders = { "device_name": coordinator.source_entity_name + " " } - self.entity_id = f"binary_sensor.{source_object_id}_{description.key}" + self.entity_id = f"binary_sensor.{source_object_id}_{entity_description.key}" else: self._attr_translation_placeholders = {"device_name": ""} self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{description.key}" + f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) - self.entity_description = description self._attr_unique_id = unique_id - super().__init__(hass=hass, coordinator=coordinator) - - if coordinator.device_id and ( - device_entry := device_registry.async_get(coordinator.device_id) - ): - self._attr_device_info = DeviceInfo( - connections=device_entry.connections, - identifiers=device_entry.identifiers, - ) - self._state: bool | None = None @callback diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 399b46790..05b879351 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -5,15 +5,12 @@ import logging from dataclasses import dataclass -import voluptuous as vol from homeassistant.components.button import ( - PLATFORM_SCHEMA, ButtonEntity, ButtonEntityDescription, ) from homeassistant.const import ( CONF_DEVICE_ID, - CONF_NAME, ) from homeassistant.core import HomeAssistant, callback, split_entity_id from homeassistant.helpers import ( @@ -27,9 +24,7 @@ ) from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.reload import async_setup_reload_service -from . import PLATFORMS from .common import utcnow_no_timezone from .const import ( ATTR_BATTERY_QUANTITY, @@ -38,7 +33,6 @@ ATTR_DEVICE_ID, ATTR_DEVICE_NAME, ATTR_SOURCE_ENTITY_ID, - CONF_SOURCE_ENTITY_ID, DOMAIN, EVENT_BATTERY_REPLACED, ) @@ -58,15 +52,6 @@ class BatteryNotesButtonEntityDescription( unique_id_suffix: str -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_DEVICE_ID): cv.string, - vol.Optional(CONF_SOURCE_ENTITY_ID): cv.string, - } -) - - @callback def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry) -> str | None: """Add our config entry to the device.""" @@ -121,21 +106,11 @@ async def async_setup_entry( ) -async def async_setup_platform( - hass: HomeAssistant, -) -> None: - """Set up the battery note sensor.""" - - await async_setup_reload_service(hass, DOMAIN, PLATFORMS) - - class BatteryNotesButton(BatteryNotesEntity, ButtonEntity): """Represents a battery replaced button.""" _attr_should_poll = False - entity_description: BatteryNotesButtonEntityDescription - def __init__( self, hass: HomeAssistant, diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 0e57517fc..290a66063 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -108,9 +108,8 @@ } ) -# TODO: Change back to all platforms once all completed PLATFORMS: Final = [ Platform.BUTTON, Platform.SENSOR, - # Platform.BINARY_SENSOR, + Platform.BINARY_SENSOR, ] diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 1d0e2c94a..b70d177e1 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -43,7 +43,6 @@ async_track_state_change_event, async_track_state_report_event, ) -from homeassistant.helpers.reload import async_setup_reload_service from homeassistant.helpers.typing import StateType from .common import utcnow_no_timezone, validate_is_float @@ -66,7 +65,6 @@ CONF_ROUND_BATTERY, CONF_SOURCE_ENTITY_ID, DOMAIN, - PLATFORMS, ) from .coordinator import MY_KEY, BatteryNotesConfigEntry, BatteryNotesCoordinator from .entity import BatteryNotesEntity, BatteryNotesEntityDescription @@ -178,14 +176,6 @@ async def async_setup_entry( ) -async def async_setup_platform( - hass: HomeAssistant, -) -> None: - """Set up the battery note sensor.""" - - await async_setup_reload_service(hass, DOMAIN, PLATFORMS) - - class BatteryNotesTypeSensor(BatteryNotesEntity, RestoreSensor): """Represents a battery note type sensor.""" From 5551e9b93ed5d1618d18bf1ade4c9713fd690e37 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 14:21:06 +0000 Subject: [PATCH 051/235] Refactor battery notes integration to enhance type hinting, streamline entity handling, and improve code clarity --- custom_components/battery_notes/__init__.py | 8 ++- .../battery_notes/binary_sensor.py | 60 ++++++++++--------- custom_components/battery_notes/button.py | 2 + .../battery_notes/config_flow.py | 16 ++--- .../battery_notes/coordinator.py | 1 - custom_components/battery_notes/sensor.py | 3 + 6 files changed, 47 insertions(+), 43 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 9129056e4..6ebf56b93 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -85,7 +85,7 @@ extra=vol.ALLOW_EXTRA, ) -_migrate_base_entry: ConfigEntry = None +_migrate_base_entry: ConfigEntry | None = None _yaml_domain_config: list[dict[str, Any]] | None = None async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: @@ -200,6 +200,8 @@ async def async_remove_entry( ) -> None: """Device removed, tidy up store.""" + # TODO: Make this sub config entry aware + # Remove any issues raised ir.async_delete_issue(hass, DOMAIN, f"missing_device_{config_entry.entry_id}") @@ -326,9 +328,9 @@ async def async_migrate_entry( title=INTEGRATION_NAME, version=3, unique_id=DOMAIN, - optons=options, + options=options, ) - hass.config_entries.async_add(_migrate_base_entry) + await hass.config_entries.async_add(_migrate_base_entry) assert _migrate_base_entry is not None, "Base entry should not be None" diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 53be86ea3..9549d11e9 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -131,6 +131,7 @@ async def async_setup_entry( if subentry.subentry_type != "battery_note": continue + assert config_entry.runtime_data.subentry_coordinators coordinator = config_entry.runtime_data.subentry_coordinators.get( subentry.subentry_id ) @@ -145,43 +146,42 @@ async def async_setup_entry( entity_type="binary_sensor", ) + entities: list[BatteryNotesBatteryLowTemplateSensor | BatteryNotesBatteryLowSensor | BatteryNotesBatteryBinaryLowSensor] = [] + if coordinator.battery_low_template is not None: - async_add_entities( - [ - BatteryNotesBatteryLowTemplateSensor( - hass, - coordinator, - description, - f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", - coordinator.battery_low_template, - ) - ], - config_subentry_id=subentry.subentry_id, + entities = [ + BatteryNotesBatteryLowTemplateSensor( + hass, + coordinator, + description, + f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + coordinator.battery_low_template, ) + ] elif coordinator.wrapped_battery is not None: - async_add_entities( - [ - BatteryNotesBatteryLowSensor( - hass, - coordinator, - description, - f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", - ) - ], - config_subentry_id=subentry.subentry_id, + entities = [ + BatteryNotesBatteryLowSensor( + hass, + coordinator, + description, + f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", ) + ] elif coordinator.wrapped_battery_low is not None: + entities = [ + BatteryNotesBatteryBinaryLowSensor( + hass, + coordinator, + description, + f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + ) + ] + + if entities: async_add_entities( - [ - BatteryNotesBatteryBinaryLowSensor( - hass, - coordinator, - description, - f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", - ) - ], + entities, config_subentry_id=subentry.subentry_id, ) @@ -285,6 +285,8 @@ class BatteryNotesBatteryLowBaseSensor( ): """Low battery binary sensor base.""" + entity_description: BatteryNotesBinarySensorEntityDescription + def __init__( self, hass: HomeAssistant, diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 05b879351..5984cc4b0 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -79,6 +79,7 @@ async def async_setup_entry( if subentry.subentry_type != "battery_note": continue + assert config_entry.runtime_data.subentry_coordinators coordinator = config_entry.runtime_data.subentry_coordinators.get( subentry.subentry_id ) @@ -110,6 +111,7 @@ class BatteryNotesButton(BatteryNotesEntity, ButtonEntity): """Represents a battery replaced button.""" _attr_should_poll = False + entity_description: BatteryNotesButtonEntityDescription def __init__( self, diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 74e14c068..d294194d0 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from types import MappingProxyType from typing import Any import homeassistant.helpers.device_registry as dr @@ -196,7 +197,6 @@ async def async_step_integration_discovery( "model_id": discovery_info[CONF_MODEL_ID], } - return await self.async_step_device(discovery_info) # triggered by async_setup() from __init__.py @@ -324,9 +324,6 @@ async def async_step_device( device_battery_details.battery_quantity ) - if device_battery_details and device_battery_details.is_manual: - return await self.async_step_manual() - return await self.async_step_battery() schema = DEVICE_SCHEMA @@ -393,9 +390,8 @@ async def async_step_battery( title = device_entry.name_by_user or device_entry.name config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] - # Create a subentry - subentry = ConfigSubentry(subentry_type="battery_note", data=self.data, title=str(title), unique_id=unique_id) + subentry = ConfigSubentry(subentry_type="battery_note", data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) self.hass.config_entries.async_add_subentry(config_entry, subentry) return self.async_abort(reason="created_sub_entry") @@ -489,7 +485,7 @@ async def async_step_user( async def async_step_device( self, user_input: dict | None = None, - ) -> ConfigFlowResult: + ) -> SubentryFlowResult: """Handle a flow for a device or discovery.""" errors: dict[str, str] = {} device_battery_details = None @@ -567,7 +563,7 @@ async def async_step_device( async def async_step_entity( self, user_input: dict | None = None, - ) -> ConfigFlowResult: + ) -> SubentryFlowResult: """Handle a flow for a device or discovery.""" errors: dict[str, str] = {} device_battery_details = None @@ -656,7 +652,7 @@ async def async_step_entity( last_step=False, ) - async def async_step_manual(self, user_input: dict[str, Any] | None = None): + async def async_step_manual(self, user_input: dict[str, Any] | None = None) -> SubentryFlowResult: """Second step in config flow to add the battery type.""" errors: dict[str, str] = {} if user_input is not None: @@ -671,7 +667,7 @@ async def async_step_manual(self, user_input: dict[str, Any] | None = None): async def async_step_battery( self, user_input: dict[str, Any] | None = None - ) -> ConfigFlowResult: + ) -> SubentryFlowResult: """Second step in config flow to add the battery type.""" errors: dict[str, str] = {} diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 807bb0f5f..d841db790 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -88,7 +88,6 @@ class BatteryNotesData: coordinator: BatteryNotesCoordinator | None = None subentry_coordinators: dict[str, BatteryNotesCoordinator] | None = None - class BatteryNotesCoordinator(DataUpdateCoordinator[None]): """Define an object to hold Battery Notes device.""" diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index b70d177e1..1be468fdd 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -103,6 +103,7 @@ async def async_setup_entry( if subentry.subentry_type != "battery_note": continue + assert config_entry.runtime_data.subentry_coordinators coordinator = config_entry.runtime_data.subentry_coordinators.get( subentry.subentry_id ) @@ -319,6 +320,8 @@ class BatteryNotesBatteryPlusSensor( } ) + entity_description: BatteryNotesSensorEntityDescription + def __init__( self, hass: HomeAssistant, From 53abd8eaf73a69607e0b0d6564a8cdbad1e26c86 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 14:54:27 +0000 Subject: [PATCH 052/235] Refactor BatteryNotesData to enhance subentry handling and improve runtime data management --- custom_components/battery_notes/__init__.py | 20 ++++++++++++++++++- .../battery_notes/coordinator.py | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 6ebf56b93..564efc748 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -165,9 +165,9 @@ async def async_setup_entry( config_entry.runtime_data = BatteryNotesData( domain_config=domain_config, store=domain_config.store, + subentries=config_entry.subentries.copy(), ) - # TODO: Get this working config_entry.runtime_data.subentry_coordinators = {} for subentry in config_entry.subentries.values(): if subentry.subentry_type == "battery_note": @@ -201,6 +201,8 @@ async def async_remove_entry( """Device removed, tidy up store.""" # TODO: Make this sub config entry aware + # Instead of remove_entry, we should listen for the config_entry being updated and compare old/new + # sub entries, then remove any that are no longer present # Remove any issues raised ir.async_delete_issue(hass, DOMAIN, f"missing_device_{config_entry.entry_id}") @@ -353,8 +355,24 @@ async def update_listener( """Update the device and related entities. Triggered when the device is renamed on the frontend. + + Look at sub entries and remove any that are no longer present. """ + for subentry in config_entry.runtime_data.subentries: + if subentry not in config_entry.subentries: + _LOGGER.debug( + "Sub entry %s no longer present, removing it from runtime data", + subentry, + ) + + # TODO: Remove the stuff in async_remove_entry + + if subentry in config_entry.runtime_data.subentry_coordinators: + del config_entry.runtime_data.subentry_coordinators[subentry] + + config_entry.runtime_data.subentries = config_entry.subentries.copy() + await hass.config_entries.async_reload(config_entry.entry_id) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index d841db790..c4d8455b0 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -85,7 +85,7 @@ class BatteryNotesData: domain_config: BatteryNotesDomainConfig store: BatteryNotesStorage - coordinator: BatteryNotesCoordinator | None = None + subentries: dict[str, ConfigSubentry] subentry_coordinators: dict[str, BatteryNotesCoordinator] | None = None class BatteryNotesCoordinator(DataUpdateCoordinator[None]): From 1caa504bd23ae24c8a513ed38fb4b6df8c264373 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 14:55:49 +0000 Subject: [PATCH 053/235] Refactor binary sensor and button modules to remove unused imports and improve code clarity --- custom_components/battery_notes/binary_sensor.py | 6 +----- custom_components/battery_notes/button.py | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 9549d11e9..fe57211f4 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -39,7 +39,7 @@ from homeassistant.helpers import ( template, ) -from homeassistant.helpers.entity import DeviceInfo, Entity, EntityCategory +from homeassistant.helpers.entity import Entity, EntityCategory from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_registry import ( EVENT_ENTITY_REGISTRY_UPDATED, @@ -48,7 +48,6 @@ EventStateChangedData, TrackTemplate, TrackTemplateResult, - async_track_entity_registry_updated_event, async_track_state_change_event, async_track_template_result, ) @@ -58,9 +57,6 @@ Template, TemplateStateFromEntityId, ) -from homeassistant.helpers.update_coordinator import ( - CoordinatorEntity, -) from .common import validate_is_float from .const import ( diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 5984cc4b0..9f97f0c32 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -13,9 +13,6 @@ CONF_DEVICE_ID, ) from homeassistant.core import HomeAssistant, callback, split_entity_id -from homeassistant.helpers import ( - config_validation as cv, -) from homeassistant.helpers import ( device_registry as dr, ) From 7a28038db335fddd24c1f93c1ae71947f676803d Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 15:01:22 +0000 Subject: [PATCH 054/235] Update entity options comment for legacy v1 support clarification --- custom_components/battery_notes/sensor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 1be468fdd..826e1de39 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -209,8 +209,7 @@ async def async_added_to_hass(self) -> None: if state: self._attr_native_value = state.native_value - # TODO: Investigate why this is needed - # Update entity options + # Update entity options, this is needed for legacy v1 support registry = er.async_get(self.hass) if registry.async_get(self.entity_id) is not None: registry.async_update_entity_options( From 90ccef550f8773b3cdc15e7fea200d76be8c41ca Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 15:29:35 +0000 Subject: [PATCH 055/235] Refactor battery replaced and battery low service handlers to improve entity lookup and streamline event firing --- custom_components/battery_notes/services.py | 259 +++++++++++--------- 1 file changed, 138 insertions(+), 121 deletions(-) diff --git a/custom_components/battery_notes/services.py b/custom_components/battery_notes/services.py index 411c18be3..a87280e5d 100644 --- a/custom_components/battery_notes/services.py +++ b/custom_components/battery_notes/services.py @@ -70,6 +70,7 @@ def async_setup_services(hass: HomeAssistant) -> None: SERVICE_CHECK_BATTERY_LOW, _async_battery_low, ) + return None async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: @@ -97,44 +98,49 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: ) return None - # entity_id is the associated entity, now need to find the config entry for battery notes - config_entry: BatteryNotesConfigEntry - for config_entry in call.hass.config_entries.async_loaded_entries(DOMAIN): - coordinator = config_entry.runtime_data.coordinator - assert(coordinator) - if coordinator.source_entity_id and coordinator.source_entity_id == source_entity_id: - - coordinator.last_replaced =datetime_replaced - await coordinator.async_request_refresh() - - _LOGGER.debug( - "Entity %s battery replaced on %s", - source_entity_id, - str(datetime_replaced), - ) - - call.hass.bus.async_fire( - EVENT_BATTERY_REPLACED, - { - ATTR_DEVICE_ID: coordinator.device_id or "", - ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id - or "", - ATTR_DEVICE_NAME: coordinator.device_name, - ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, - ATTR_BATTERY_TYPE: coordinator.battery_type, - ATTR_BATTERY_QUANTITY: coordinator.battery_quantity, - }, - ) - - _LOGGER.debug( - "Raised event battery replaced %s", - coordinator.device_id, - ) + # Check if entity_id exists in any sub config entry + entity_found = False - return None - - _LOGGER.error("Entity %s not configured in Battery Notes", source_entity_id) - return None + for config_entry in call.hass.config_entries.async_loaded_entries(DOMAIN): + battery_notes_config_entry = cast(BatteryNotesConfigEntry, config_entry) + if not battery_notes_config_entry.runtime_data.subentry_coordinators: + continue + + for coordinator in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): + if coordinator.source_entity_id and coordinator.source_entity_id == source_entity_id: + entity_found = True + coordinator.last_replaced = datetime_replaced + await coordinator.async_request_refresh() + + _LOGGER.debug( + "Entity %s battery replaced on %s", + source_entity_id, + str(datetime_replaced), + ) + + call.hass.bus.async_fire( + EVENT_BATTERY_REPLACED, + { + ATTR_DEVICE_ID: coordinator.device_id or "", + ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id + or "", + ATTR_DEVICE_NAME: coordinator.device_name, + ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, + ATTR_BATTERY_TYPE: coordinator.battery_type, + ATTR_BATTERY_QUANTITY: coordinator.battery_quantity, + }, + ) + + _LOGGER.debug( + "Raised event battery replaced %s", + coordinator.device_id, + ) + + return None + + if not entity_found: + _LOGGER.error("Entity %s not configured in Battery Notes", source_entity_id) + return None else: device_entry = device_registry.async_get(device_id) @@ -145,117 +151,128 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: ) return None + # Check if device_id exists in any sub config entry + device_found = False for config_entry in call.hass.config_entries.async_loaded_entries(DOMAIN): - coordinator = config_entry.runtime_data.coordinator - assert(coordinator) - if coordinator.device_id == device_id: - coordinator.last_replaced = datetime_replaced - await coordinator.async_request_refresh() - - _LOGGER.debug( - "Device %s battery replaced on %s", + battery_notes_config_entry = cast(BatteryNotesConfigEntry, config_entry) + if not battery_notes_config_entry.runtime_data.subentry_coordinators: + continue + + for coordinator in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): + if coordinator.device_id == device_id: + device_found = True + coordinator.last_replaced = datetime_replaced + await coordinator.async_request_refresh() + + _LOGGER.debug( + "Device %s battery replaced on %s", + device_id, + str(datetime_replaced), + ) + + call.hass.bus.async_fire( + EVENT_BATTERY_REPLACED, + { + ATTR_DEVICE_ID: coordinator.device_id or "", + ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id + or "", + ATTR_DEVICE_NAME: coordinator.device_name, + ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, + ATTR_BATTERY_TYPE: coordinator.battery_type, + ATTR_BATTERY_QUANTITY: coordinator.battery_quantity, + }, + ) + + _LOGGER.debug( + "Raised event battery replaced %s", + coordinator.device_id, + ) + + # Found and dealt with, exit + return None + + if not device_found: + _LOGGER.error( + "Device %s not configured in Battery Notes", device_id, - str(datetime_replaced), - ) - - call.hass.bus.async_fire( - EVENT_BATTERY_REPLACED, - { - ATTR_DEVICE_ID: coordinator.device_id or "", - ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id - or "", - ATTR_DEVICE_NAME: coordinator.device_name, - ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, - ATTR_BATTERY_TYPE: coordinator.battery_type, - ATTR_BATTERY_QUANTITY: coordinator.battery_quantity, - }, ) - - _LOGGER.debug( - "Raised event battery replaced %s", - coordinator.device_id, - ) - - # Found and dealt with, exit return None - - _LOGGER.error( - "Device %s not configured in Battery Notes", - device_id, - ) return None + return None async def _async_battery_last_reported(call: ServiceCall) -> ServiceResponse: """Handle the service call.""" days_last_reported = cast(int, call.data.get(SERVICE_DATA_DAYS_LAST_REPORTED)) - config_entry: BatteryNotesConfigEntry for config_entry in call.hass.config_entries.async_loaded_entries(DOMAIN): - coordinator = config_entry.runtime_data.coordinator - assert(coordinator) + battery_notes_config_entry = cast(BatteryNotesConfigEntry, config_entry) + if not battery_notes_config_entry.runtime_data.subentry_coordinators: + continue + + for coordinator in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): + if coordinator.wrapped_battery and coordinator.last_reported: + time_since_lastreported = ( + datetime.fromisoformat(str(utcnow_no_timezone()) + "+00:00") + - coordinator.last_reported + ) - if coordinator.wrapped_battery and coordinator.last_reported: - time_since_lastreported = ( - datetime.fromisoformat(str(utcnow_no_timezone()) + "+00:00") - - coordinator.last_reported - ) + if time_since_lastreported.days > days_last_reported: + call.hass.bus.async_fire( + EVENT_BATTERY_NOT_REPORTED, + { + ATTR_DEVICE_ID: coordinator.device_id or "", + ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id + or "", + ATTR_DEVICE_NAME: coordinator.device_name, + ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, + ATTR_BATTERY_TYPE: coordinator.battery_type, + ATTR_BATTERY_QUANTITY: coordinator.battery_quantity, + ATTR_BATTERY_LAST_REPORTED: coordinator.last_reported, + ATTR_BATTERY_LAST_REPORTED_DAYS: time_since_lastreported.days, + ATTR_BATTERY_LAST_REPORTED_LEVEL: coordinator.last_reported_level, + ATTR_BATTERY_LAST_REPLACED: coordinator.last_replaced, + }, + ) + + _LOGGER.debug( + "Raised event device %s not reported since %s", + coordinator.device_id, + str(coordinator.last_reported), + ) + return None - if time_since_lastreported.days > days_last_reported: +async def _async_battery_low(call: ServiceCall) -> ServiceResponse: + """Handle the service call.""" + + for config_entry in call.hass.config_entries.async_loaded_entries(DOMAIN): + battery_notes_config_entry = cast(BatteryNotesConfigEntry, config_entry) + if not battery_notes_config_entry.runtime_data.subentry_coordinators: + continue + + for coordinator in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): + if coordinator.battery_low is True: call.hass.bus.async_fire( - EVENT_BATTERY_NOT_REPORTED, + EVENT_BATTERY_THRESHOLD, { ATTR_DEVICE_ID: coordinator.device_id or "", + ATTR_DEVICE_NAME: coordinator.device_name, ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id or "", - ATTR_DEVICE_NAME: coordinator.device_name, + ATTR_BATTERY_LOW: coordinator.battery_low, + ATTR_BATTERY_LOW_THRESHOLD: coordinator.battery_low_threshold, ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, ATTR_BATTERY_TYPE: coordinator.battery_type, ATTR_BATTERY_QUANTITY: coordinator.battery_quantity, - ATTR_BATTERY_LAST_REPORTED: coordinator.last_reported, - ATTR_BATTERY_LAST_REPORTED_DAYS: time_since_lastreported.days, - ATTR_BATTERY_LAST_REPORTED_LEVEL: coordinator.last_reported_level, + ATTR_BATTERY_LEVEL: coordinator.rounded_battery_level, + ATTR_PREVIOUS_BATTERY_LEVEL: coordinator.rounded_previous_battery_level, ATTR_BATTERY_LAST_REPLACED: coordinator.last_replaced, + ATTR_BATTERY_THRESHOLD_REMINDER: True, }, ) _LOGGER.debug( - "Raised event device %s not reported since %s", + "Raised event device %s battery low", coordinator.device_id, - str(coordinator.last_reported), ) - return None - -async def _async_battery_low(call: ServiceCall) -> ServiceResponse: - """Handle the service call.""" - - config_entry: BatteryNotesConfigEntry - for config_entry in call.hass.config_entries.async_loaded_entries(DOMAIN): - coordinator = config_entry.runtime_data.coordinator - assert(coordinator) - - if coordinator.battery_low is True: - call.hass.bus.async_fire( - EVENT_BATTERY_THRESHOLD, - { - ATTR_DEVICE_ID: coordinator.device_id or "", - ATTR_DEVICE_NAME: coordinator.device_name, - ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id - or "", - ATTR_BATTERY_LOW: coordinator.battery_low, - ATTR_BATTERY_LOW_THRESHOLD: coordinator.battery_low_threshold, - ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, - ATTR_BATTERY_TYPE: coordinator.battery_type, - ATTR_BATTERY_QUANTITY: coordinator.battery_quantity, - ATTR_BATTERY_LEVEL: coordinator.rounded_battery_level, - ATTR_PREVIOUS_BATTERY_LEVEL: coordinator.rounded_previous_battery_level, - ATTR_BATTERY_LAST_REPLACED: coordinator.last_replaced, - ATTR_BATTERY_THRESHOLD_REMINDER: True, - }, - ) - - _LOGGER.debug( - "Raised event device %s battery low", - coordinator.device_id, - ) return None \ No newline at end of file From 065f8880a806894c01bf199b5a4a96b5eda3f824 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 16:12:32 +0000 Subject: [PATCH 056/235] Clarify TODO comment for async_remove_entry in update_listener function --- custom_components/battery_notes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 564efc748..eb21a6fc4 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -366,7 +366,7 @@ async def update_listener( subentry, ) - # TODO: Remove the stuff in async_remove_entry + # TODO: Remove the stuff in async_remove_entry here if subentry in config_entry.runtime_data.subentry_coordinators: del config_entry.runtime_data.subentry_coordinators[subentry] From b59ea0e2be95bd792fc12f203e24010afae2b139 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 17:14:27 +0000 Subject: [PATCH 057/235] Update default battery low threshold description for clarity --- custom_components/battery_notes/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 3b1175a3f..2504b6380 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -127,7 +127,7 @@ "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", "round_battery": "Round battery+ to whole percentages.", - "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired, can be overriden per device in device configuration.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, "sections": { From eb3666679cf188ebd7ae3aea84ead47b5a20da6c Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 18:16:55 +0000 Subject: [PATCH 058/235] Update configuration flow to use subentry title for name defaults and add reconfiguration success message --- custom_components/battery_notes/config_flow.py | 4 ++-- custom_components/battery_notes/translations/en.json | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index d294194d0..34d50ec07 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -842,7 +842,7 @@ async def async_step_reconfigure( if self.data.get(CONF_BATTERY_LOW_TEMPLATE, None) is None: data_schema = vol.Schema( { - vol.Optional(CONF_NAME, default=config_entry.title): selector.TextSelector( + vol.Optional(CONF_NAME, default=config_subentry.title): selector.TextSelector( selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), ), vol.Required(CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE]): selector.TextSelector( @@ -865,7 +865,7 @@ async def async_step_reconfigure( else: data_schema = vol.Schema( { - vol.Optional(CONF_NAME, default=config_entry.title): selector.TextSelector( + vol.Optional(CONF_NAME, default=config_subentry.title): selector.TextSelector( selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), ), vol.Required(CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE]): selector.TextSelector( diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 2504b6380..c2fa7ab27 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -104,6 +104,7 @@ } }, "abort": { + "reconfigure_successful": "Re-configuration was successful", "already_configured": "Device is already configured" }, "error": { From 569836a398a4f5f1e4635ec624c684935c6d38dc Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 10 Aug 2025 19:38:15 +0000 Subject: [PATCH 059/235] Add filtered battery sensor and enhance coordinator with unique ID and outlier filtering --- custom_components/battery_notes/__init__.py | 20 ++++- .../battery_notes/binary_sensor.py | 88 ++++++++++++++----- .../battery_notes/coordinator.py | 10 +++ custom_components/battery_notes/entity.py | 12 ++- .../battery_notes/translations/en.json | 3 + 5 files changed, 106 insertions(+), 27 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index eb21a6fc4..07176145b 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -17,8 +17,10 @@ from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv +from homeassistant.helpers import device_registry as dr from homeassistant.helpers import entity_registry as er from homeassistant.helpers import issue_registry as ir +from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.typing import ConfigType from .config_flow import CONFIG_VERSION @@ -37,12 +39,11 @@ DEFAULT_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD, DOMAIN, + MANUFACTURER, MIN_HA_VERSION, PLATFORMS, ) -from .const import ( - NAME as INTEGRATION_NAME, -) +from .const import NAME as INTEGRATION_NAME from .coordinator import ( MY_KEY, BatteryNotesConfigEntry, @@ -171,9 +172,22 @@ async def async_setup_entry( config_entry.runtime_data.subentry_coordinators = {} for subentry in config_entry.subentries.values(): if subentry.subentry_type == "battery_note": + coordinator = BatteryNotesCoordinator(hass, config_entry, subentry) config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator + assert subentry.unique_id + device_registry = dr.async_get(hass) + device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + config_subentry_id= subentry.subentry_id, + identifiers={(DOMAIN, coordinator.unique_id)}, + entry_type=DeviceEntryType.SERVICE, + manufacturer=MANUFACTURER, + name=subentry.title + ) + + await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index fe57211f4..689840413 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -86,7 +86,7 @@ class BatteryNotesBinarySensorEntityDescription( BatteryNotesEntityDescription, BinarySensorEntityDescription, ): - """Describes Battery Notes button entity.""" + """Describes Battery Notes binary sensor entity.""" unique_id_suffix: str @@ -133,7 +133,16 @@ async def async_setup_entry( ) assert coordinator - description = BatteryNotesBinarySensorEntityDescription( + battery_filtered_entity_description = BatteryNotesBinarySensorEntityDescription( + unique_id_suffix="_battery_outliers_filtered", + key="_battery_outliers_filtered", + translation_key="battery_outliers_filtered", + entity_category=EntityCategory.DIAGNOSTIC, + entity_type="binary_sensor", + attach_to_source_device=False, + ) + + battery_low_entity_description = BatteryNotesBinarySensorEntityDescription( unique_id_suffix="_battery_low", key="_battery_plus_low", translation_key="battery_low", @@ -144,36 +153,45 @@ async def async_setup_entry( entities: list[BatteryNotesBatteryLowTemplateSensor | BatteryNotesBatteryLowSensor | BatteryNotesBatteryBinaryLowSensor] = [] - if coordinator.battery_low_template is not None: - entities = [ - BatteryNotesBatteryLowTemplateSensor( + entities = [ + BatteryNotesFilteredSensor( hass, coordinator, - description, - f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", - coordinator.battery_low_template, + battery_filtered_entity_description, + f"{config_entry.entry_id}{subentry.unique_id}{battery_filtered_entity_description.unique_id_suffix}", + ) + ] + + if coordinator.battery_low_template is not None: + entities.append( + BatteryNotesBatteryLowTemplateSensor( + hass, + coordinator, + battery_low_entity_description, + f"{config_entry.entry_id}{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", + coordinator.battery_low_template, + ) ) - ] elif coordinator.wrapped_battery is not None: - entities = [ - BatteryNotesBatteryLowSensor( - hass, - coordinator, - description, - f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + entities.append( + BatteryNotesBatteryLowSensor( + hass, + coordinator, + battery_low_entity_description, + f"{config_entry.entry_id}{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", + ) ) - ] elif coordinator.wrapped_battery_low is not None: - entities = [ - BatteryNotesBatteryBinaryLowSensor( - hass, - coordinator, - description, - f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + entities.append( + BatteryNotesBatteryBinaryLowSensor( + hass, + coordinator, + battery_low_entity_description, + f"{config_entry.entry_id}{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", + ) ) - ] if entities: async_add_entities( @@ -181,6 +199,29 @@ async def async_setup_entry( config_subentry_id=subentry.subentry_id, ) +class BatteryNotesFilteredSensor(BatteryNotesEntity, BinarySensorEntity): + """Represents a filtered battery sensor.""" + + entity_description: BatteryNotesBinarySensorEntityDescription + + def __init__( + self, + hass: HomeAssistant, + coordinator: BatteryNotesCoordinator, + entity_description: BatteryNotesBinarySensorEntityDescription, + unique_id: str, + ) -> None: + """Create a filtered battery sensor.""" + super().__init__(hass, entity_description=entity_description, coordinator=coordinator) + + self._attr_unique_id = unique_id + + @property + def is_on(self) -> bool | None: + """Return true if sensor is on.""" + return self.coordinator.filter_outliers + + class _TemplateAttribute: """Attribute value linked to template result.""" @@ -861,3 +902,4 @@ def _handle_coordinator_update(self) -> None: def is_on(self) -> bool | None: """Return true if sensor is on.""" return self._attr_is_on + diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index c4d8455b0..4aa97e476 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -329,6 +329,11 @@ def _link_device(self) -> bool: return True + @property + def unique_id(self) -> str: + """Return a unique ID for the coordinator.""" + return f"{self.config_entry.entry_id}_{self.subentry.subentry_id}" + @property def fake_device(self) -> bool: """Return if an actual device registry entry.""" @@ -337,6 +342,11 @@ def fake_device(self) -> bool: return True return False + @property + def filter_outliers(self) -> bool: + """Return if outlier filtering is enabled.""" + return self.subentry.data.get(CONF_FILTER_OUTLIERS, False) + @property def source_entity_name(self): """Get the current name of the source_entity_id.""" diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index 0ba39d58e..b3536860b 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -7,9 +7,11 @@ from homeassistant.core import HomeAssistant, split_entity_id from homeassistant.helpers import device_registry as dr from homeassistant.helpers.device import async_entity_id_to_device_id +from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.update_coordinator import CoordinatorEntity +from .const import DOMAIN from .coordinator import BatteryNotesCoordinator @@ -20,6 +22,7 @@ class BatteryNotesRequiredKeysMixin: unique_id_suffix: str entity_type: str require_device: bool = False + attach_to_source_device: bool = True @dataclass(frozen=True, kw_only=True) @@ -53,7 +56,14 @@ def __init__( self._set_entity_id(entity_description) # Set up device association - self._associate_device(hass, device_registry) + if entity_description.attach_to_source_device: + self._associate_device(hass, device_registry) + else: + self.device_entry = None + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, coordinator.unique_id)}, + ) + def _set_entity_id(self, entity_description: BatteryNotesEntityDescription) -> None: """Set up entity naming and translation placeholders.""" diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index c2fa7ab27..b1967e71c 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -186,6 +186,9 @@ "name": "Battery low threshold" } } + }, + "battery_outliers_filtered": { + "name": "Battery outliers filtered" } }, "button": { From 6d038c422ce410c01747df88eb2f611846589b30 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 11 Aug 2025 08:04:00 +0000 Subject: [PATCH 060/235] Add BINARY_SENSOR platform to supported platforms list --- custom_components/battery_notes/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 290a66063..e7c66c0ee 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -109,7 +109,7 @@ ) PLATFORMS: Final = [ + Platform.BINARY_SENSOR, Platform.BUTTON, Platform.SENSOR, - Platform.BINARY_SENSOR, ] From 14ac034d8d27b6d3c0b41de5e3dde1b22f629943 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 07:21:14 +0000 Subject: [PATCH 061/235] Update poetry --- poetry.lock | 695 ++++++++++++++++++++++++++-------------------------- 1 file changed, 343 insertions(+), 352 deletions(-) diff --git a/poetry.lock b/poetry.lock index a29ea1e78..f87b9da25 100644 --- a/poetry.lock +++ b/poetry.lock @@ -538,14 +538,14 @@ typecheck = ["mypy"] [[package]] name = "bleak" -version = "1.0.1" +version = "1.1.0" description = "Bluetooth Low Energy platform Agnostic Klient" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "bleak-1.0.1-py3-none-any.whl", hash = "sha256:8f99bcb2fb74950466622b1f932ab661c74dcd48a3d122e95b661aa0705e5a6a"}, - {file = "bleak-1.0.1.tar.gz", hash = "sha256:6177487c4eb08743a155e1295ff871eb2a61669b538bdbf35db45ea29cf7a41d"}, + {file = "bleak-1.1.0-py3-none-any.whl", hash = "sha256:174e7836e1ab0879860cd24ddd0ac604bd192bcc1acb978892e27359f3f18304"}, + {file = "bleak-1.1.0.tar.gz", hash = "sha256:0ace59c8cf5a2d8aa66a2493419b59ac6a119c2f72f6e57be8dbdd3f2c0270e0"}, ] [package.dependencies] @@ -562,6 +562,9 @@ winrt-runtime = {version = ">=3.1", markers = "platform_system == \"Windows\""} "winrt-Windows.Foundation.Collections" = {version = ">=3.1", markers = "platform_system == \"Windows\""} "winrt-Windows.Storage.Streams" = {version = ">=3.1", markers = "platform_system == \"Windows\""} +[package.extras] +pythonista = ["bleak-pythonista (>=0.1.1)"] + [[package]] name = "bleak-retry-connector" version = "4.0.0" @@ -690,18 +693,18 @@ docs = ["Sphinx (>=5,<9)", "myst-parser (>=0.18,<4.1)", "sphinx-rtd-theme (>=1,< [[package]] name = "boto3" -version = "1.40.4" +version = "1.40.7" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "boto3-1.40.4-py3-none-any.whl", hash = "sha256:95cdc86454e9ff43e0693c5d807a54ce6813b6711d3543a0052ead5216b93367"}, - {file = "boto3-1.40.4.tar.gz", hash = "sha256:6eceffe4ae67c2cb077574289c0efe3ba60e8446646893a974fc3c2fa1130e7c"}, + {file = "boto3-1.40.7-py3-none-any.whl", hash = "sha256:8727cac601a679d2885dc78b8119a0548bbbe04e49b72f7d94021a629154c080"}, + {file = "boto3-1.40.7.tar.gz", hash = "sha256:61b15f70761f1eadd721c6ba41a92658f003eaaef09500ca7642f5ae68ec8945"}, ] [package.dependencies] -botocore = ">=1.40.4,<1.41.0" +botocore = ">=1.40.7,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -710,14 +713,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.4" +version = "1.40.7" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "botocore-1.40.4-py3-none-any.whl", hash = "sha256:4e131c52731e10a6af998c2ac3bfbda12e6ecef0e3633268c7752d0502c74197"}, - {file = "botocore-1.40.4.tar.gz", hash = "sha256:f1dacde69ec8b08f39bcdb62247bab4554938b5d7f8805ade78447da55c9df36"}, + {file = "botocore-1.40.7-py3-none-any.whl", hash = "sha256:a06956f3d7222e80ef6ae193608f358c3b7898e1a2b88553479d8f9737fbb03e"}, + {file = "botocore-1.40.7.tar.gz", hash = "sha256:33793696680cf3a0c4b5ace4f9070c67c4d4fcb19c999fd85cfee55de3dcf913"}, ] [package.dependencies] @@ -852,104 +855,91 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.4.2" +version = "3.4.3" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, - {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, - {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca"}, + {file = "charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a"}, + {file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"}, ] [[package]] @@ -1388,72 +1378,72 @@ files = [ [[package]] name = "greenlet" -version = "3.2.3" +version = "3.2.4" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.9" groups = ["main"] markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\"" files = [ - {file = "greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be"}, - {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:761917cac215c61e9dc7324b2606107b3b292a8349bdebb31503ab4de3f559ac"}, - {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a433dbc54e4a37e4fff90ef34f25a8c00aed99b06856f0119dcf09fbafa16392"}, - {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:72e77ed69312bab0434d7292316d5afd6896192ac4327d44f3d613ecb85b037c"}, - {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:68671180e3849b963649254a882cd544a3c75bfcd2c527346ad8bb53494444db"}, - {file = "greenlet-3.2.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49c8cfb18fb419b3d08e011228ef8a25882397f3a859b9fe1436946140b6756b"}, - {file = "greenlet-3.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:efc6dc8a792243c31f2f5674b670b3a95d46fa1c6a912b8e310d6f542e7b0712"}, - {file = "greenlet-3.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:731e154aba8e757aedd0781d4b240f1225b075b4409f1bb83b05ff410582cf00"}, - {file = "greenlet-3.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:96c20252c2f792defe9a115d3287e14811036d51e78b3aaddbee23b69b216302"}, - {file = "greenlet-3.2.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:784ae58bba89fa1fa5733d170d42486580cab9decda3484779f4759345b29822"}, - {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0921ac4ea42a5315d3446120ad48f90c3a6b9bb93dd9b3cf4e4d84a66e42de83"}, - {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d2971d93bb99e05f8c2c0c2f4aa9484a18d98c4c3bd3c62b65b7e6ae33dfcfaf"}, - {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c667c0bf9d406b77a15c924ef3285e1e05250948001220368e039b6aa5b5034b"}, - {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:592c12fb1165be74592f5de0d70f82bc5ba552ac44800d632214b76089945147"}, - {file = "greenlet-3.2.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29e184536ba333003540790ba29829ac14bb645514fbd7e32af331e8202a62a5"}, - {file = "greenlet-3.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:93c0bb79844a367782ec4f429d07589417052e621aa39a5ac1fb99c5aa308edc"}, - {file = "greenlet-3.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:751261fc5ad7b6705f5f76726567375bb2104a059454e0226e1eef6c756748ba"}, - {file = "greenlet-3.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:83a8761c75312361aa2b5b903b79da97f13f556164a7dd2d5448655425bd4c34"}, - {file = "greenlet-3.2.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d"}, - {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b"}, - {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d"}, - {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264"}, - {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688"}, - {file = "greenlet-3.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb"}, - {file = "greenlet-3.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c"}, - {file = "greenlet-3.2.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163"}, - {file = "greenlet-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849"}, - {file = "greenlet-3.2.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad"}, - {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef"}, - {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3"}, - {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95"}, - {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb"}, - {file = "greenlet-3.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b"}, - {file = "greenlet-3.2.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0"}, - {file = "greenlet-3.2.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36"}, - {file = "greenlet-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3"}, - {file = "greenlet-3.2.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86"}, - {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97"}, - {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728"}, - {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a"}, - {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892"}, - {file = "greenlet-3.2.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141"}, - {file = "greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a"}, - {file = "greenlet-3.2.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:42efc522c0bd75ffa11a71e09cd8a399d83fafe36db250a87cf1dacfaa15dc64"}, - {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d760f9bdfe79bff803bad32b4d8ffb2c1d2ce906313fc10a83976ffb73d64ca7"}, - {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8324319cbd7b35b97990090808fdc99c27fe5338f87db50514959f8059999805"}, - {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:8c37ef5b3787567d322331d5250e44e42b58c8c713859b8a04c6065f27efbf72"}, - {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ce539fb52fb774d0802175d37fcff5c723e2c7d249c65916257f0a940cee8904"}, - {file = "greenlet-3.2.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:003c930e0e074db83559edc8705f3a2d066d4aa8c2f198aff1e454946efd0f26"}, - {file = "greenlet-3.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7e70ea4384b81ef9e84192e8a77fb87573138aa5d4feee541d8014e452b434da"}, - {file = "greenlet-3.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:22eb5ba839c4b2156f18f76768233fe44b23a31decd9cc0d4cc8141c211fd1b4"}, - {file = "greenlet-3.2.3-cp39-cp39-win32.whl", hash = "sha256:4532f0d25df67f896d137431b13f4cdce89f7e3d4a96387a41290910df4d3a57"}, - {file = "greenlet-3.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:aaa7aae1e7f75eaa3ae400ad98f8644bb81e1dc6ba47ce8a93d3f17274e08322"}, - {file = "greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365"}, + {file = "greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c"}, + {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590"}, + {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c"}, + {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b"}, + {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31"}, + {file = "greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d"}, + {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5"}, + {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f"}, + {file = "greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c"}, + {file = "greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2"}, + {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246"}, + {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3"}, + {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633"}, + {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079"}, + {file = "greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8"}, + {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52"}, + {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa"}, + {file = "greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9"}, + {file = "greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd"}, + {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb"}, + {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968"}, + {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9"}, + {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6"}, + {file = "greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0"}, + {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0"}, + {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f"}, + {file = "greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02"}, + {file = "greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31"}, + {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945"}, + {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc"}, + {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a"}, + {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504"}, + {file = "greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671"}, + {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b"}, + {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae"}, + {file = "greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b"}, + {file = "greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0"}, + {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f"}, + {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5"}, + {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1"}, + {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735"}, + {file = "greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337"}, + {file = "greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01"}, + {file = "greenlet-3.2.4-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c"}, + {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d"}, + {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58"}, + {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4"}, + {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433"}, + {file = "greenlet-3.2.4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df"}, + {file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594"}, + {file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98"}, + {file = "greenlet-3.2.4-cp39-cp39-win32.whl", hash = "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b"}, + {file = "greenlet-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb"}, + {file = "greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d"}, ] [package.extras] docs = ["Sphinx", "furo"] -test = ["objgraph", "psutil"] +test = ["objgraph", "psutil", "setuptools"] [[package]] name = "h11" @@ -1469,60 +1459,60 @@ files = [ [[package]] name = "habluetooth" -version = "4.0.2" +version = "5.0.1" description = "High availability Bluetooth" optional = false python-versions = ">=3.11" groups = ["main"] files = [ - {file = "habluetooth-4.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:943b5bb533a49cb1bce627dfdad52e4c2547c84a62a20248f18ff92c5d557ac4"}, - {file = "habluetooth-4.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c389b1674b977c2e142d05f97a2e6c2f146cce9ed3579b2f50854b601915ad76"}, - {file = "habluetooth-4.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:579c77e25859b17c93926da10ae8292d662cc36b8d5cf0649cc7882209d72f08"}, - {file = "habluetooth-4.0.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b4a308d5f31e5494312fc108cc264ab461e2b17ea9bddd633f92fae2197578f1"}, - {file = "habluetooth-4.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a88a3aa36c3f3566f0116cf80eced5b178881513db7f2db970329022df7ed8f"}, - {file = "habluetooth-4.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:22ff7e21d33116a9415e80b29b31cb0471a83a8acad631fab110d3f6d2b78f65"}, - {file = "habluetooth-4.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5941a865f77960d999caeb14c715ec4d4583097f3776bc4b4d38539448810aad"}, - {file = "habluetooth-4.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2137042806417a781183f5f8361dff1178a5ff6c6b7bf1f8c31b309d20b0489"}, - {file = "habluetooth-4.0.2-cp311-cp311-win32.whl", hash = "sha256:4fb7ec381a54e56d78ffcb96b00bc326cbe936180deafe37dd3fbd28e489bbb0"}, - {file = "habluetooth-4.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:a63a1955f032ccbdd5fcc53c1d6e14227796068aa47e78c2b110cad3d83650c9"}, - {file = "habluetooth-4.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef51e756a18f3cab134cb965267aeca87ff86d05e9ecb8c6c6aea87819f4ca1e"}, - {file = "habluetooth-4.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3f9af20c32bb8fc4f93b82c43c66b35941f1c1dd4257ef2cb50e2b3e3a07afb1"}, - {file = "habluetooth-4.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:168d9dae743b05b7cc83286b5e2d881fb6c00354768e6bb31e68a554092f09c2"}, - {file = "habluetooth-4.0.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c55ac9cea6a2c846cefd0137c05608926783e0a4ba8588d2adf55ea8a8be9e63"}, - {file = "habluetooth-4.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2ec89851efbf982f8cdf273afb4bbaaeaeb52f5285ce4684235b42b4d68e"}, - {file = "habluetooth-4.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c12affa73c5d4743eab53eebb95b6a31806ffb03b0b339975a55a260f1598f7"}, - {file = "habluetooth-4.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4c05ed10a4175fd182477bf9f5be6a50f265ffbd68f3c388db6cf4e85ea3e90e"}, - {file = "habluetooth-4.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:28febb8a637a66d7b41b2ae73f53a335efec4eee3daa6acec6677290b7b386e6"}, - {file = "habluetooth-4.0.2-cp312-cp312-win32.whl", hash = "sha256:1b8f53c893b79ba4be1aca34714007fb3ccb0631f4a6965c789c0d93e0d93274"}, - {file = "habluetooth-4.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:943eace066d7a6621b46616b0d56d74d8b602900d4a2e3a9bf7f5cf1702bc283"}, - {file = "habluetooth-4.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fa5cb9988e520f4e417f846af0224078a5cec52374771190dc2a68eab2b4c7bb"}, - {file = "habluetooth-4.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f667402a93bbe791291f1803945232ff889180982cbb46131a92ae4965fd32a"}, - {file = "habluetooth-4.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:06f2b0bbbc454e98a7ce55f3a3f0f8a95ac93f239a46d42910cdfd3c68d58b75"}, - {file = "habluetooth-4.0.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21ff0614cbf6713fddabaf825d1f28540865c385600a4828f8a4b78a523642ae"}, - {file = "habluetooth-4.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05689102deb193e39c600fcedd42d4ff38571116014599e0a8f0a47551aefb4f"}, - {file = "habluetooth-4.0.2-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:2c6c6b59b508b22f48ce5e903b05209278cad76085588ad12508d613e01a87ab"}, - {file = "habluetooth-4.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5036fb92bc60bfd10552633d0958e8f9e6230c0a07b054ff033c0d0ff8307e7f"}, - {file = "habluetooth-4.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c2874a8432ea1232e691d7075169219e84fd6228f0b6e8cdb6f83e31403d2513"}, - {file = "habluetooth-4.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71043f0185d129713798b4b2785b386cc077fc259014a1cb5e66dcd3818c195c"}, - {file = "habluetooth-4.0.2-cp313-cp313-win32.whl", hash = "sha256:c38c9d1e4c664d53315b8cbb74cb0143f2dedf23c4c39b24fcb41ce7c8f18383"}, - {file = "habluetooth-4.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:a0eda4d430bea3f2d27eaba38c64094f1f5308d9a74c8d3e37fd71479f1f730c"}, - {file = "habluetooth-4.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:83e8c8b8662c78f41a0b8d699f08881895795180beefd5cccd83082e5bf11ebe"}, - {file = "habluetooth-4.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c8b28ad298f07f72e955c37724fc4fc5383e685760540228f3ccffd07410c983"}, - {file = "habluetooth-4.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca156ef9378646409f864ded4daded1f353d91ef5cf0a9d26353b040441b3ecc"}, - {file = "habluetooth-4.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a20795f97f7c91da03c6083069cd62052ffb3c0a1f12cf172a787fcdff5be561"}, - {file = "habluetooth-4.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de1a066013ddeb28ef858a37b86a25b6c2835279076c9b40518d43903f9ab618"}, - {file = "habluetooth-4.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:994370adde9e1910516a0c2ae8952c12c7844f7d6f80f33970fca966ebf496ba"}, - {file = "habluetooth-4.0.2-cp314-cp314-win32.whl", hash = "sha256:533bd23369a7853ebe6229875b47723adbd3a489297607ffa1195b4f01d9f724"}, - {file = "habluetooth-4.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:45b1ce825089f600fe7ef5efc788a7e122bd2e8f46d656ae4208f494be63621c"}, - {file = "habluetooth-4.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8a32f3bdc6b5705e73cd6f501dfa13fdd6faafb184fc66b41094e4963a1b69f2"}, - {file = "habluetooth-4.0.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fb47e1d116a06e7d3a9a33070594214fa1c6a3b0f77b1279411c05918e015bd4"}, - {file = "habluetooth-4.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1983397093e49773bc3c0018bb2d9b2bf74f338bf2ecca9c3c5ee794e398a4ce"}, - {file = "habluetooth-4.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b449f8dc33241047c585fa639ecaff8e7c593775324bcecfddff5b1380ef9746"}, - {file = "habluetooth-4.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7ff82d793aef7079634eccb928498d10b4e22e953174dd2c2360409b52fa490b"}, - {file = "habluetooth-4.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:09b53be688183745e20a0529d5958c51604aee897f349bfb6b933eaa82fa0827"}, - {file = "habluetooth-4.0.2-cp314-cp314t-win32.whl", hash = "sha256:b65167aaed991c0d1c23472566682bbe8287bfb51fff7030d840555a5cfacf3a"}, - {file = "habluetooth-4.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:8d2bce29fa7f36bf3ce2df85e8fae46aacac9e784ba6f9fa720aee09d9c97969"}, - {file = "habluetooth-4.0.2.tar.gz", hash = "sha256:64209ef20acc366afbdc3cbb14dbf2283c9df90e0f751ed16a91b74a8bac9eda"}, + {file = "habluetooth-5.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fbc44abedfd4d462d7b2cafa71c9b29b1f7293967cf6ae0f8379b94a0a1bf751"}, + {file = "habluetooth-5.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f20812a973c903b80e9864223dfb228dfdbfe446173b762181c463bd8be9e407"}, + {file = "habluetooth-5.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d7f25e33f4f230917a1a96d5c1e77f25b3ea3fca3f4284816b35dc03922a7595"}, + {file = "habluetooth-5.0.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6c4cb947003e92041503ff51a02ebe457177ea19b484435640c0dded98f60343"}, + {file = "habluetooth-5.0.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e97bfc5ac6cf2ca22fdad622a26984ff7ed01acc7c61b223dc69f0a82f9f128b"}, + {file = "habluetooth-5.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8f41adec778f522c51a27fa9ec8b539683a2d151d43f6957f00ba2a06656d526"}, + {file = "habluetooth-5.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d13dc369c3381d190c0cf21a7b3262a8f2c044474e54d665d904a20abe34bb63"}, + {file = "habluetooth-5.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96dc5ff1fdab8f20112a3db00a3822ace758688ac6b39ad1632d5943df20a50c"}, + {file = "habluetooth-5.0.1-cp311-cp311-win32.whl", hash = "sha256:15ec534969436e04f859a0fd60b9bb813f4d082fb77d1e1c57f3e607fd1641c9"}, + {file = "habluetooth-5.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bb375cadcfc4ffc90cec6f71af9ec9a665ebf9564c43d8b367e643802da2cac2"}, + {file = "habluetooth-5.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:43585141e2de4a9b0b866049acf116bf8b84651a6479f0d1cd3eabdf885e6d37"}, + {file = "habluetooth-5.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e55481e405489aafea5ac77744db920b29afdae770e8a6f8e4c0e94d48cd8f1b"}, + {file = "habluetooth-5.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:05a398922580abe6a7eb72860a9b4ccc623d77f78c0aed06e8a845bbf1edca6b"}, + {file = "habluetooth-5.0.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:30dd7705e7732bc439d3e053da46335a8addbee477352c75987cc622eeef65d0"}, + {file = "habluetooth-5.0.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:485f985e3dc7e325fff46ee58a62a5fca7d55579ab3d67bd27345ab2d5112539"}, + {file = "habluetooth-5.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6bc118d7535014e45d6a2763392118ef51ee23f6105fcf4a1569339d54d7000e"}, + {file = "habluetooth-5.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e4e981732c6483fedecd5773ddaa010e48e5abfe9e3d1a1b160c386b31fed4d8"}, + {file = "habluetooth-5.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad3a38ba90e1d94c0520c73244b00329f1db68f684990c13176507f144ca0dca"}, + {file = "habluetooth-5.0.1-cp312-cp312-win32.whl", hash = "sha256:c7ad7d9613d6d74d639cae05ae3686098d6a0c86e557fe1233dabf2fee19ce8a"}, + {file = "habluetooth-5.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:7e462e1bcbc0a7dbf2e526f44dc4b08344ed67e40f398cc932eeae828934741a"}, + {file = "habluetooth-5.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f6aac5b5d904ccf7a0cb8d2353ffbdcd9384e403c21a11d999e514f21d310bb"}, + {file = "habluetooth-5.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95fca9eb3a8bcdbb86990228129f7cf2159d100b2cccd862a961f3f22c1e042c"}, + {file = "habluetooth-5.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18ac447c09c0f2edcdd9152e15b707338ea3e6c903e35fee14a5f4820e6d64e1"}, + {file = "habluetooth-5.0.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c55c6b7de8c64a2a23522d40fea7f60ccc0040d91b377e635f4ad4f26925ce49"}, + {file = "habluetooth-5.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62263daf0bed0c227bab14924e624f9ca8af483939a9be847844ea388fab971d"}, + {file = "habluetooth-5.0.1-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:ee08ae031f594683a236c359ed6d5fe2fa53fe1dca57229df5bd4b238cba61f3"}, + {file = "habluetooth-5.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e8e45c746e31d86c93347054bd6a36d802ca873238b7f1da0a9a9830bc4caca7"}, + {file = "habluetooth-5.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7aa09c6252f5a1f2bcb94c22ec6c9ac5e3e25369a11674e43de60afe7b345568"}, + {file = "habluetooth-5.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0fa229e2f0f09407f1471afecd4d318cfaf4e50c8f5d9bdc73a65226ab4810c6"}, + {file = "habluetooth-5.0.1-cp313-cp313-win32.whl", hash = "sha256:173df6fb4cba6cef2605a1a6e178417143ecaf82ad7f3086693d13b0638743a0"}, + {file = "habluetooth-5.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:7690ea34c16ce37d9e7c9ad59c662d8f17d6069d235a72d323d6febe664ce764"}, + {file = "habluetooth-5.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d46c67de552d3db96e000ce4031e388735681882a2d95a437b6e0138db918e9"}, + {file = "habluetooth-5.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ddc5644c6c6b2a80ff9c826f901ca15748a020b8c7e162ab39fc35b49bbecf17"}, + {file = "habluetooth-5.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86825b3c10e0fa43a469af6b5aad6dbfb012d90dcc039936ec441b9e908b70c1"}, + {file = "habluetooth-5.0.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:beda16e0c9272a077771c12f4b50cf43a3aa5173d71dbc4794ae68dc98aa3cad"}, + {file = "habluetooth-5.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:30cbd5f37cc8aa2644db93c3a01c4f2843befc12962c2aa3f8b9aac8b6dfd3c2"}, + {file = "habluetooth-5.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1df1af9448deeead2b7ca9cfb89a5e44d6c5068a6a818211eaefb6a8a4ff808"}, + {file = "habluetooth-5.0.1-cp314-cp314-win32.whl", hash = "sha256:23740047240da1ebf5a1ba9f99d337310670ae5070c8f960c2bbc3aef061be95"}, + {file = "habluetooth-5.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:8327354cbb4a645b63595f8ae04767b97827376389a2c44bc0bfbc37c91f143e"}, + {file = "habluetooth-5.0.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:50ee71822ab1bd6b3bbbe449c32701a9cbe5b224560ec8aa2cbde318bdcc51da"}, + {file = "habluetooth-5.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:137484d72fd96829c5d16cf3f179ee218fc5155bda56d8c4563accda0094e816"}, + {file = "habluetooth-5.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f0de147f3a393adee328459ee66663783a4b92e994789d37f594e415a047e07"}, + {file = "habluetooth-5.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:458ad7112caee189ef5ec22766ab1d9f788a0a6c02ef9a8507b344385a5802f0"}, + {file = "habluetooth-5.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a838a76e71f7962c33865c6ed0990c6170def2a72de17d2f4986cc8064370a61"}, + {file = "habluetooth-5.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d7557cbbb53a3b40fa626eca475c3d95a7fee43d90357655cbad15e7fc3a759d"}, + {file = "habluetooth-5.0.1-cp314-cp314t-win32.whl", hash = "sha256:b7f96471c2ea4949300fa4abcda3a35a6d7132634fe93378c6a9b9d45cc32c90"}, + {file = "habluetooth-5.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f2d9a13a13b105ee3712bdfbec3ac17baffd311c24d5a29c8e9c129eb362252e"}, + {file = "habluetooth-5.0.1.tar.gz", hash = "sha256:dfa720b0c2b03d6380ae3d474061c4fe78e58523f4baa208d0f8f5f8f3a8663c"}, ] [package.dependencies] @@ -1532,6 +1522,7 @@ bleak-retry-connector = ">=4" bluetooth-adapters = ">=2" bluetooth-auto-recovery = ">=1.5.1" bluetooth-data-tools = ">=1.28.0" +btsocket = ">=0.3.0" dbus-fast = {version = ">=2.30.2", markers = "platform_system == \"Linux\""} [[package]] @@ -1693,14 +1684,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "identify" -version = "2.6.12" +version = "2.6.13" description = "File identification library for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2"}, - {file = "identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6"}, + {file = "identify-2.6.13-py2.py3-none-any.whl", hash = "sha256:60381139b3ae39447482ecc406944190f690d4a2997f2584062089848361b33b"}, + {file = "identify-2.6.13.tar.gz", hash = "sha256:da8d6c828e773620e13bfa86ea601c5a5310ba4bcd65edf378198b56a1f9fb32"}, ] [package.extras] @@ -1997,122 +1988,122 @@ files = [ [[package]] name = "multidict" -version = "6.6.3" +version = "6.6.4" description = "multidict implementation" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "multidict-6.6.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a2be5b7b35271f7fff1397204ba6708365e3d773579fe2a30625e16c4b4ce817"}, - {file = "multidict-6.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12f4581d2930840295c461764b9a65732ec01250b46c6b2c510d7ee68872b140"}, - {file = "multidict-6.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dd7793bab517e706c9ed9d7310b06c8672fd0aeee5781bfad612f56b8e0f7d14"}, - {file = "multidict-6.6.3-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:72d8815f2cd3cf3df0f83cac3f3ef801d908b2d90409ae28102e0553af85545a"}, - {file = "multidict-6.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:531e331a2ee53543ab32b16334e2deb26f4e6b9b28e41f8e0c87e99a6c8e2d69"}, - {file = "multidict-6.6.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:42ca5aa9329a63be8dc49040f63817d1ac980e02eeddba763a9ae5b4027b9c9c"}, - {file = "multidict-6.6.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:208b9b9757060b9faa6f11ab4bc52846e4f3c2fb8b14d5680c8aac80af3dc751"}, - {file = "multidict-6.6.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:acf6b97bd0884891af6a8b43d0f586ab2fcf8e717cbd47ab4bdddc09e20652d8"}, - {file = "multidict-6.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:68e9e12ed00e2089725669bdc88602b0b6f8d23c0c95e52b95f0bc69f7fe9b55"}, - {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:05db2f66c9addb10cfa226e1acb363450fab2ff8a6df73c622fefe2f5af6d4e7"}, - {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0db58da8eafb514db832a1b44f8fa7906fdd102f7d982025f816a93ba45e3dcb"}, - {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14117a41c8fdb3ee19c743b1c027da0736fdb79584d61a766da53d399b71176c"}, - {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:877443eaaabcd0b74ff32ebeed6f6176c71850feb7d6a1d2db65945256ea535c"}, - {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:70b72e749a4f6e7ed8fb334fa8d8496384840319512746a5f42fa0aec79f4d61"}, - {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43571f785b86afd02b3855c5ac8e86ec921b760298d6f82ff2a61daf5a35330b"}, - {file = "multidict-6.6.3-cp310-cp310-win32.whl", hash = "sha256:20c5a0c3c13a15fd5ea86c42311859f970070e4e24de5a550e99d7c271d76318"}, - {file = "multidict-6.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab0a34a007704c625e25a9116c6770b4d3617a071c8a7c30cd338dfbadfe6485"}, - {file = "multidict-6.6.3-cp310-cp310-win_arm64.whl", hash = "sha256:769841d70ca8bdd140a715746199fc6473414bd02efd678d75681d2d6a8986c5"}, - {file = "multidict-6.6.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:18f4eba0cbac3546b8ae31e0bbc55b02c801ae3cbaf80c247fcdd89b456ff58c"}, - {file = "multidict-6.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef43b5dd842382329e4797c46f10748d8c2b6e0614f46b4afe4aee9ac33159df"}, - {file = "multidict-6.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf9bd1fd5eec01494e0f2e8e446a74a85d5e49afb63d75a9934e4a5423dba21d"}, - {file = "multidict-6.6.3-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5bd8d6f793a787153956cd35e24f60485bf0651c238e207b9a54f7458b16d539"}, - {file = "multidict-6.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bf99b4daf908c73856bd87ee0a2499c3c9a3d19bb04b9c6025e66af3fd07462"}, - {file = "multidict-6.6.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b9e59946b49dafaf990fd9c17ceafa62976e8471a14952163d10a7a630413a9"}, - {file = "multidict-6.6.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e2db616467070d0533832d204c54eea6836a5e628f2cb1e6dfd8cd6ba7277cb7"}, - {file = "multidict-6.6.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7394888236621f61dcdd25189b2768ae5cc280f041029a5bcf1122ac63df79f9"}, - {file = "multidict-6.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f114d8478733ca7388e7c7e0ab34b72547476b97009d643644ac33d4d3fe1821"}, - {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cdf22e4db76d323bcdc733514bf732e9fb349707c98d341d40ebcc6e9318ef3d"}, - {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e995a34c3d44ab511bfc11aa26869b9d66c2d8c799fa0e74b28a473a692532d6"}, - {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:766a4a5996f54361d8d5a9050140aa5362fe48ce51c755a50c0bc3706460c430"}, - {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3893a0d7d28a7fe6ca7a1f760593bc13038d1d35daf52199d431b61d2660602b"}, - {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:934796c81ea996e61914ba58064920d6cad5d99140ac3167901eb932150e2e56"}, - {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9ed948328aec2072bc00f05d961ceadfd3e9bfc2966c1319aeaf7b7c21219183"}, - {file = "multidict-6.6.3-cp311-cp311-win32.whl", hash = "sha256:9f5b28c074c76afc3e4c610c488e3493976fe0e596dd3db6c8ddfbb0134dcac5"}, - {file = "multidict-6.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc7f6fbc61b1c16050a389c630da0b32fc6d4a3d191394ab78972bf5edc568c2"}, - {file = "multidict-6.6.3-cp311-cp311-win_arm64.whl", hash = "sha256:d4e47d8faffaae822fb5cba20937c048d4f734f43572e7079298a6c39fb172cb"}, - {file = "multidict-6.6.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:056bebbeda16b2e38642d75e9e5310c484b7c24e3841dc0fb943206a72ec89d6"}, - {file = "multidict-6.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e5f481cccb3c5c5e5de5d00b5141dc589c1047e60d07e85bbd7dea3d4580d63f"}, - {file = "multidict-6.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10bea2ee839a759ee368b5a6e47787f399b41e70cf0c20d90dfaf4158dfb4e55"}, - {file = "multidict-6.6.3-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:2334cfb0fa9549d6ce2c21af2bfbcd3ac4ec3646b1b1581c88e3e2b1779ec92b"}, - {file = "multidict-6.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8fee016722550a2276ca2cb5bb624480e0ed2bd49125b2b73b7010b9090e888"}, - {file = "multidict-6.6.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5511cb35f5c50a2db21047c875eb42f308c5583edf96bd8ebf7d770a9d68f6d"}, - {file = "multidict-6.6.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:712b348f7f449948e0a6c4564a21c7db965af900973a67db432d724619b3c680"}, - {file = "multidict-6.6.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e4e15d2138ee2694e038e33b7c3da70e6b0ad8868b9f8094a72e1414aeda9c1a"}, - {file = "multidict-6.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8df25594989aebff8a130f7899fa03cbfcc5d2b5f4a461cf2518236fe6f15961"}, - {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:159ca68bfd284a8860f8d8112cf0521113bffd9c17568579e4d13d1f1dc76b65"}, - {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e098c17856a8c9ade81b4810888c5ad1914099657226283cab3062c0540b0643"}, - {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:67c92ed673049dec52d7ed39f8cf9ebbadf5032c774058b4406d18c8f8fe7063"}, - {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:bd0578596e3a835ef451784053cfd327d607fc39ea1a14812139339a18a0dbc3"}, - {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:346055630a2df2115cd23ae271910b4cae40f4e336773550dca4889b12916e75"}, - {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:555ff55a359302b79de97e0468e9ee80637b0de1fce77721639f7cd9440b3a10"}, - {file = "multidict-6.6.3-cp312-cp312-win32.whl", hash = "sha256:73ab034fb8d58ff85c2bcbadc470efc3fafeea8affcf8722855fb94557f14cc5"}, - {file = "multidict-6.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:04cbcce84f63b9af41bad04a54d4cc4e60e90c35b9e6ccb130be2d75b71f8c17"}, - {file = "multidict-6.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:0f1130b896ecb52d2a1e615260f3ea2af55fa7dc3d7c3003ba0c3121a759b18b"}, - {file = "multidict-6.6.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:540d3c06d48507357a7d57721e5094b4f7093399a0106c211f33540fdc374d55"}, - {file = "multidict-6.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9c19cea2a690f04247d43f366d03e4eb110a0dc4cd1bbeee4d445435428ed35b"}, - {file = "multidict-6.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7af039820cfd00effec86bda5d8debef711a3e86a1d3772e85bea0f243a4bd65"}, - {file = "multidict-6.6.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:500b84f51654fdc3944e936f2922114349bf8fdcac77c3092b03449f0e5bc2b3"}, - {file = "multidict-6.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3fc723ab8a5c5ed6c50418e9bfcd8e6dceba6c271cee6728a10a4ed8561520c"}, - {file = "multidict-6.6.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:94c47ea3ade005b5976789baaed66d4de4480d0a0bf31cef6edaa41c1e7b56a6"}, - {file = "multidict-6.6.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dbc7cf464cc6d67e83e136c9f55726da3a30176f020a36ead246eceed87f1cd8"}, - {file = "multidict-6.6.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:900eb9f9da25ada070f8ee4a23f884e0ee66fe4e1a38c3af644256a508ad81ca"}, - {file = "multidict-6.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c6df517cf177da5d47ab15407143a89cd1a23f8b335f3a28d57e8b0a3dbb884"}, - {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ef421045f13879e21c994b36e728d8e7d126c91a64b9185810ab51d474f27e7"}, - {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6c1e61bb4f80895c081790b6b09fa49e13566df8fbff817da3f85b3a8192e36b"}, - {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e5e8523bb12d7623cd8300dbd91b9e439a46a028cd078ca695eb66ba31adee3c"}, - {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ef58340cc896219e4e653dade08fea5c55c6df41bcc68122e3be3e9d873d9a7b"}, - {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc9dc435ec8699e7b602b94fe0cd4703e69273a01cbc34409af29e7820f777f1"}, - {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9e864486ef4ab07db5e9cb997bad2b681514158d6954dd1958dfb163b83d53e6"}, - {file = "multidict-6.6.3-cp313-cp313-win32.whl", hash = "sha256:5633a82fba8e841bc5c5c06b16e21529573cd654f67fd833650a215520a6210e"}, - {file = "multidict-6.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:e93089c1570a4ad54c3714a12c2cef549dc9d58e97bcded193d928649cab78e9"}, - {file = "multidict-6.6.3-cp313-cp313-win_arm64.whl", hash = "sha256:c60b401f192e79caec61f166da9c924e9f8bc65548d4246842df91651e83d600"}, - {file = "multidict-6.6.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:02fd8f32d403a6ff13864b0851f1f523d4c988051eea0471d4f1fd8010f11134"}, - {file = "multidict-6.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f3aa090106b1543f3f87b2041eef3c156c8da2aed90c63a2fbed62d875c49c37"}, - {file = "multidict-6.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e924fb978615a5e33ff644cc42e6aa241effcf4f3322c09d4f8cebde95aff5f8"}, - {file = "multidict-6.6.3-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:b9fe5a0e57c6dbd0e2ce81ca66272282c32cd11d31658ee9553849d91289e1c1"}, - {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b24576f208793ebae00280c59927c3b7c2a3b1655e443a25f753c4611bc1c373"}, - {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:135631cb6c58eac37d7ac0df380294fecdc026b28837fa07c02e459c7fb9c54e"}, - {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:274d416b0df887aef98f19f21578653982cfb8a05b4e187d4a17103322eeaf8f"}, - {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e252017a817fad7ce05cafbe5711ed40faeb580e63b16755a3a24e66fa1d87c0"}, - {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4cc8d848cd4fe1cdee28c13ea79ab0ed37fc2e89dd77bac86a2e7959a8c3bc"}, - {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9e236a7094b9c4c1b7585f6b9cca34b9d833cf079f7e4c49e6a4a6ec9bfdc68f"}, - {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e0cb0ab69915c55627c933f0b555a943d98ba71b4d1c57bc0d0a66e2567c7471"}, - {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:81ef2f64593aba09c5212a3d0f8c906a0d38d710a011f2f42759704d4557d3f2"}, - {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:b9cbc60010de3562545fa198bfc6d3825df430ea96d2cc509c39bd71e2e7d648"}, - {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:70d974eaaa37211390cd02ef93b7e938de564bbffa866f0b08d07e5e65da783d"}, - {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3713303e4a6663c6d01d648a68f2848701001f3390a030edaaf3fc949c90bf7c"}, - {file = "multidict-6.6.3-cp313-cp313t-win32.whl", hash = "sha256:639ecc9fe7cd73f2495f62c213e964843826f44505a3e5d82805aa85cac6f89e"}, - {file = "multidict-6.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:9f97e181f344a0ef3881b573d31de8542cc0dbc559ec68c8f8b5ce2c2e91646d"}, - {file = "multidict-6.6.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ce8b7693da41a3c4fde5871c738a81490cea5496c671d74374c8ab889e1834fb"}, - {file = "multidict-6.6.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c8161b5a7778d3137ea2ee7ae8a08cce0010de3b00ac671c5ebddeaa17cefd22"}, - {file = "multidict-6.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1328201ee930f069961ae707d59c6627ac92e351ed5b92397cf534d1336ce557"}, - {file = "multidict-6.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b1db4d2093d6b235de76932febf9d50766cf49a5692277b2c28a501c9637f616"}, - {file = "multidict-6.6.3-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53becb01dd8ebd19d1724bebe369cfa87e4e7f29abbbe5c14c98ce4c383e16cd"}, - {file = "multidict-6.6.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41bb9d1d4c303886e2d85bade86e59885112a7f4277af5ad47ab919a2251f306"}, - {file = "multidict-6.6.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:775b464d31dac90f23192af9c291dc9f423101857e33e9ebf0020a10bfcf4144"}, - {file = "multidict-6.6.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d04d01f0a913202205a598246cf77826fe3baa5a63e9f6ccf1ab0601cf56eca0"}, - {file = "multidict-6.6.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d25594d3b38a2e6cabfdcafef339f754ca6e81fbbdb6650ad773ea9775af35ab"}, - {file = "multidict-6.6.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:35712f1748d409e0707b165bf49f9f17f9e28ae85470c41615778f8d4f7d9609"}, - {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1c8082e5814b662de8589d6a06c17e77940d5539080cbab9fe6794b5241b76d9"}, - {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:61af8a4b771f1d4d000b3168c12c3120ccf7284502a94aa58c68a81f5afac090"}, - {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:448e4a9afccbf297577f2eaa586f07067441e7b63c8362a3540ba5a38dc0f14a"}, - {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:233ad16999afc2bbd3e534ad8dbe685ef8ee49a37dbc2cdc9514e57b6d589ced"}, - {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:bb933c891cd4da6bdcc9733d048e994e22e1883287ff7540c2a0f3b117605092"}, - {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:37b09ca60998e87734699e88c2363abfd457ed18cfbf88e4009a4e83788e63ed"}, - {file = "multidict-6.6.3-cp39-cp39-win32.whl", hash = "sha256:f54cb79d26d0cd420637d184af38f0668558f3c4bbe22ab7ad830e67249f2e0b"}, - {file = "multidict-6.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:295adc9c0551e5d5214b45cf29ca23dbc28c2d197a9c30d51aed9e037cb7c578"}, - {file = "multidict-6.6.3-cp39-cp39-win_arm64.whl", hash = "sha256:15332783596f227db50fb261c2c251a58ac3873c457f3a550a95d5c0aa3c770d"}, - {file = "multidict-6.6.3-py3-none-any.whl", hash = "sha256:8db10f29c7541fc5da4defd8cd697e1ca429db743fa716325f236079b96f775a"}, - {file = "multidict-6.6.3.tar.gz", hash = "sha256:798a9eb12dab0a6c2e29c1de6f3468af5cb2da6053a20dfa3344907eed0937cc"}, + {file = "multidict-6.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8aa6f0bd8125ddd04a6593437bad6a7e70f300ff4180a531654aa2ab3f6d58f"}, + {file = "multidict-6.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9e5853bbd7264baca42ffc53391b490d65fe62849bf2c690fa3f6273dbcd0cb"}, + {file = "multidict-6.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0af5f9dee472371e36d6ae38bde009bd8ce65ac7335f55dcc240379d7bed1495"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:d24f351e4d759f5054b641c81e8291e5d122af0fca5c72454ff77f7cbe492de8"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db6a3810eec08280a172a6cd541ff4a5f6a97b161d93ec94e6c4018917deb6b7"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a1b20a9d56b2d81e2ff52ecc0670d583eaabaa55f402e8d16dd062373dbbe796"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8c9854df0eaa610a23494c32a6f44a3a550fb398b6b51a56e8c6b9b3689578db"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4bb7627fd7a968f41905a4d6343b0d63244a0623f006e9ed989fa2b78f4438a0"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caebafea30ed049c57c673d0b36238b1748683be2593965614d7b0e99125c877"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ad887a8250eb47d3ab083d2f98db7f48098d13d42eb7a3b67d8a5c795f224ace"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ed8358ae7d94ffb7c397cecb62cbac9578a83ecefc1eba27b9090ee910e2efb6"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ecab51ad2462197a4c000b6d5701fc8585b80eecb90583635d7e327b7b6923eb"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c5c97aa666cf70e667dfa5af945424ba1329af5dd988a437efeb3a09430389fb"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9a950b7cf54099c1209f455ac5970b1ea81410f2af60ed9eb3c3f14f0bfcf987"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:163c7ea522ea9365a8a57832dea7618e6cbdc3cd75f8c627663587459a4e328f"}, + {file = "multidict-6.6.4-cp310-cp310-win32.whl", hash = "sha256:17d2cbbfa6ff20821396b25890f155f40c986f9cfbce5667759696d83504954f"}, + {file = "multidict-6.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:ce9a40fbe52e57e7edf20113a4eaddfacac0561a0879734e636aa6d4bb5e3fb0"}, + {file = "multidict-6.6.4-cp310-cp310-win_arm64.whl", hash = "sha256:01d0959807a451fe9fdd4da3e139cb5b77f7328baf2140feeaf233e1d777b729"}, + {file = "multidict-6.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c7a0e9b561e6460484318a7612e725df1145d46b0ef57c6b9866441bf6e27e0c"}, + {file = "multidict-6.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6bf2f10f70acc7a2446965ffbc726e5fc0b272c97a90b485857e5c70022213eb"}, + {file = "multidict-6.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66247d72ed62d5dd29752ffc1d3b88f135c6a8de8b5f63b7c14e973ef5bda19e"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:105245cc6b76f51e408451a844a54e6823bbd5a490ebfe5bdfc79798511ceded"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cbbc54e58b34c3bae389ef00046be0961f30fef7cb0dd9c7756aee376a4f7683"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:56c6b3652f945c9bc3ac6c8178cd93132b8d82dd581fcbc3a00676c51302bc1a"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b95494daf857602eccf4c18ca33337dd2be705bccdb6dddbfc9d513e6addb9d9"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e5b1413361cef15340ab9dc61523e653d25723e82d488ef7d60a12878227ed50"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e167bf899c3d724f9662ef00b4f7fef87a19c22b2fead198a6f68b263618df52"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aaea28ba20a9026dfa77f4b80369e51cb767c61e33a2d4043399c67bd95fb7c6"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8c91cdb30809a96d9ecf442ec9bc45e8cfaa0f7f8bdf534e082c2443a196727e"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a0ccbfe93ca114c5d65a2471d52d8829e56d467c97b0e341cf5ee45410033b3"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:55624b3f321d84c403cb7d8e6e982f41ae233d85f85db54ba6286f7295dc8a9c"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4a1fb393a2c9d202cb766c76208bd7945bc194eba8ac920ce98c6e458f0b524b"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:43868297a5759a845fa3a483fb4392973a95fb1de891605a3728130c52b8f40f"}, + {file = "multidict-6.6.4-cp311-cp311-win32.whl", hash = "sha256:ed3b94c5e362a8a84d69642dbeac615452e8af9b8eb825b7bc9f31a53a1051e2"}, + {file = "multidict-6.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:d8c112f7a90d8ca5d20213aa41eac690bb50a76da153e3afb3886418e61cb22e"}, + {file = "multidict-6.6.4-cp311-cp311-win_arm64.whl", hash = "sha256:3bb0eae408fa1996d87247ca0d6a57b7fc1dcf83e8a5c47ab82c558c250d4adf"}, + {file = "multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8"}, + {file = "multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3"}, + {file = "multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24"}, + {file = "multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793"}, + {file = "multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e"}, + {file = "multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364"}, + {file = "multidict-6.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f46a6e8597f9bd71b31cc708195d42b634c8527fecbcf93febf1052cacc1f16e"}, + {file = "multidict-6.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:22e38b2bc176c5eb9c0a0e379f9d188ae4cd8b28c0f53b52bce7ab0a9e534657"}, + {file = "multidict-6.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5df8afd26f162da59e218ac0eefaa01b01b2e6cd606cffa46608f699539246da"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:49517449b58d043023720aa58e62b2f74ce9b28f740a0b5d33971149553d72aa"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9408439537c5afdca05edd128a63f56a62680f4b3c234301055d7a2000220f"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87a32d20759dc52a9e850fe1061b6e41ab28e2998d44168a8a341b99ded1dba0"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52e3c8d43cdfff587ceedce9deb25e6ae77daba560b626e97a56ddcad3756879"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ad8850921d3a8d8ff6fbef790e773cecfc260bbfa0566998980d3fa8f520bc4a"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:497a2954adc25c08daff36f795077f63ad33e13f19bfff7736e72c785391534f"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:024ce601f92d780ca1617ad4be5ac15b501cc2414970ffa2bb2bbc2bd5a68fa5"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a693fc5ed9bdd1c9e898013e0da4dcc640de7963a371c0bd458e50e046bf6438"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:190766dac95aab54cae5b152a56520fd99298f32a1266d66d27fdd1b5ac00f4e"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8f2a5ffdceab9dcd97c7a016deb2308531d5f0fced2bb0c9e1df45b3363d7"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:59e8d40ab1f5a8597abcef00d04845155a5693b5da00d2c93dbe88f2050f2812"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:467fe64138cfac771f0e949b938c2e1ada2b5af22f39692aa9258715e9ea613a"}, + {file = "multidict-6.6.4-cp313-cp313-win32.whl", hash = "sha256:14616a30fe6d0a48d0a48d1a633ab3b8bec4cf293aac65f32ed116f620adfd69"}, + {file = "multidict-6.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:40cd05eaeb39e2bc8939451f033e57feaa2ac99e07dbca8afe2be450a4a3b6cf"}, + {file = "multidict-6.6.4-cp313-cp313-win_arm64.whl", hash = "sha256:f6eb37d511bfae9e13e82cb4d1af36b91150466f24d9b2b8a9785816deb16605"}, + {file = "multidict-6.6.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6c84378acd4f37d1b507dfa0d459b449e2321b3ba5f2338f9b085cf7a7ba95eb"}, + {file = "multidict-6.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0e0558693063c75f3d952abf645c78f3c5dfdd825a41d8c4d8156fc0b0da6e7e"}, + {file = "multidict-6.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3f8e2384cb83ebd23fd07e9eada8ba64afc4c759cd94817433ab8c81ee4b403f"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f996b87b420995a9174b2a7c1a8daf7db4750be6848b03eb5e639674f7963773"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc356250cffd6e78416cf5b40dc6a74f1edf3be8e834cf8862d9ed5265cf9b0e"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dadf95aa862714ea468a49ad1e09fe00fcc9ec67d122f6596a8d40caf6cec7d0"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dd57515bebffd8ebd714d101d4c434063322e4fe24042e90ced41f18b6d3395"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:967af5f238ebc2eb1da4e77af5492219fbd9b4b812347da39a7b5f5c72c0fa45"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a4c6875c37aae9794308ec43e3530e4aa0d36579ce38d89979bbf89582002bb"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f683a551e92bdb7fac545b9c6f9fa2aebdeefa61d607510b3533286fcab67f5"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:3ba5aaf600edaf2a868a391779f7a85d93bed147854925f34edd24cc70a3e141"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:580b643b7fd2c295d83cad90d78419081f53fd532d1f1eb67ceb7060f61cff0d"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:37b7187197da6af3ee0b044dbc9625afd0c885f2800815b228a0e70f9a7f473d"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e1b93790ed0bc26feb72e2f08299691ceb6da5e9e14a0d13cc74f1869af327a0"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a506a77ddee1efcca81ecbeae27ade3e09cdf21a8ae854d766c2bb4f14053f92"}, + {file = "multidict-6.6.4-cp313-cp313t-win32.whl", hash = "sha256:f93b2b2279883d1d0a9e1bd01f312d6fc315c5e4c1f09e112e4736e2f650bc4e"}, + {file = "multidict-6.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:6d46a180acdf6e87cc41dc15d8f5c2986e1e8739dc25dbb7dac826731ef381a4"}, + {file = "multidict-6.6.4-cp313-cp313t-win_arm64.whl", hash = "sha256:756989334015e3335d087a27331659820d53ba432befdef6a718398b0a8493ad"}, + {file = "multidict-6.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:af7618b591bae552b40dbb6f93f5518328a949dac626ee75927bba1ecdeea9f4"}, + {file = "multidict-6.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b6819f83aef06f560cb15482d619d0e623ce9bf155115150a85ab11b8342a665"}, + {file = "multidict-6.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4d09384e75788861e046330308e7af54dd306aaf20eb760eb1d0de26b2bea2cb"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:a59c63061f1a07b861c004e53869eb1211ffd1a4acbca330e3322efa6dd02978"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:350f6b0fe1ced61e778037fdc7613f4051c8baf64b1ee19371b42a3acdb016a0"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0c5cbac6b55ad69cb6aa17ee9343dfbba903118fd530348c330211dc7aa756d1"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:630f70c32b8066ddfd920350bc236225814ad94dfa493fe1910ee17fe4365cbb"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8d4916a81697faec6cb724a273bd5457e4c6c43d82b29f9dc02c5542fd21fc9"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e42332cf8276bb7645d310cdecca93a16920256a5b01bebf747365f86a1675b"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f3be27440f7644ab9a13a6fc86f09cdd90b347c3c5e30c6d6d860de822d7cb53"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:21f216669109e02ef3e2415ede07f4f8987f00de8cdfa0cc0b3440d42534f9f0"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d9890d68c45d1aeac5178ded1d1cccf3bc8d7accf1f976f79bf63099fb16e4bd"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:edfdcae97cdc5d1a89477c436b61f472c4d40971774ac4729c613b4b133163cb"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0b2e886624be5773e69cf32bcb8534aecdeb38943520b240fed3d5596a430f2f"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:be5bf4b3224948032a845d12ab0f69f208293742df96dc14c4ff9b09e508fc17"}, + {file = "multidict-6.6.4-cp39-cp39-win32.whl", hash = "sha256:10a68a9191f284fe9d501fef4efe93226e74df92ce7a24e301371293bd4918ae"}, + {file = "multidict-6.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:ee25f82f53262f9ac93bd7e58e47ea1bdcc3393cef815847e397cba17e284210"}, + {file = "multidict-6.6.4-cp39-cp39-win_arm64.whl", hash = "sha256:f9867e55590e0855bcec60d4f9a092b69476db64573c9fe17e92b0c50614c16a"}, + {file = "multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c"}, + {file = "multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd"}, ] [[package]] @@ -2376,14 +2367,14 @@ type = ["mypy (>=1.14.1)"] [[package]] name = "pre-commit" -version = "4.2.0" +version = "4.3.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd"}, - {file = "pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146"}, + {file = "pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8"}, + {file = "pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16"}, ] [package.dependencies] @@ -2395,14 +2386,14 @@ virtualenv = ">=20.10.0" [[package]] name = "pre-commit-hooks" -version = "5.0.0" +version = "6.0.0" description = "Some out-of-the-box hooks for pre-commit." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pre_commit_hooks-5.0.0-py2.py3-none-any.whl", hash = "sha256:8d71cfb582c5c314a5498d94e0104b6567a8b93fb35903ea845c491f4e290a7a"}, - {file = "pre_commit_hooks-5.0.0.tar.gz", hash = "sha256:10626959a9eaf602fbfc22bc61b6e75801436f82326bfcee82bb1f2fc4bc646e"}, + {file = "pre_commit_hooks-6.0.0-py2.py3-none-any.whl", hash = "sha256:76161b76d321d2f8ee2a8e0b84c30ee8443e01376121fd1c90851e33e3bd7ee2"}, + {file = "pre_commit_hooks-6.0.0.tar.gz", hash = "sha256:76d8370c006f5026cdd638a397a678d26dda735a3c88137e05885a020f824034"}, ] [package.dependencies] @@ -2690,14 +2681,14 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pylint" -version = "3.3.7" +version = "3.3.8" description = "python code static checker" optional = false python-versions = ">=3.9.0" groups = ["dev"] files = [ - {file = "pylint-3.3.7-py3-none-any.whl", hash = "sha256:43860aafefce92fca4cf6b61fe199cdc5ae54ea28f9bf4cd49de267b5195803d"}, - {file = "pylint-3.3.7.tar.gz", hash = "sha256:2b11de8bde49f9c5059452e0c310c079c746a0a8eeaa789e5aa966ecc23e4559"}, + {file = "pylint-3.3.8-py3-none-any.whl", hash = "sha256:7ef94aa692a600e82fabdd17102b73fc226758218c97473c7ad67bd4cb905d83"}, + {file = "pylint-3.3.8.tar.gz", hash = "sha256:26698de19941363037e2937d3db9ed94fb3303fdadf7d98847875345a8bb6b05"}, ] [package.dependencies] @@ -3158,30 +3149,30 @@ files = [ [[package]] name = "ruff" -version = "0.12.4" +version = "0.12.8" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.12.4-py3-none-linux_armv6l.whl", hash = "sha256:cb0d261dac457ab939aeb247e804125a5d521b21adf27e721895b0d3f83a0d0a"}, - {file = "ruff-0.12.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:55c0f4ca9769408d9b9bac530c30d3e66490bd2beb2d3dae3e4128a1f05c7442"}, - {file = "ruff-0.12.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a8224cc3722c9ad9044da7f89c4c1ec452aef2cfe3904365025dd2f51daeae0e"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9949d01d64fa3672449a51ddb5d7548b33e130240ad418884ee6efa7a229586"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:be0593c69df9ad1465e8a2d10e3defd111fdb62dcd5be23ae2c06da77e8fcffb"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7dea966bcb55d4ecc4cc3270bccb6f87a337326c9dcd3c07d5b97000dbff41c"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afcfa3ab5ab5dd0e1c39bf286d829e042a15e966b3726eea79528e2e24d8371a"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c057ce464b1413c926cdb203a0f858cd52f3e73dcb3270a3318d1630f6395bb3"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e64b90d1122dc2713330350626b10d60818930819623abbb56535c6466cce045"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2abc48f3d9667fdc74022380b5c745873499ff827393a636f7a59da1515e7c57"}, - {file = "ruff-0.12.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2b2449dc0c138d877d629bea151bee8c0ae3b8e9c43f5fcaafcd0c0d0726b184"}, - {file = "ruff-0.12.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:56e45bb11f625db55f9b70477062e6a1a04d53628eda7784dce6e0f55fd549eb"}, - {file = "ruff-0.12.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:478fccdb82ca148a98a9ff43658944f7ab5ec41c3c49d77cd99d44da019371a1"}, - {file = "ruff-0.12.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0fc426bec2e4e5f4c4f182b9d2ce6a75c85ba9bcdbe5c6f2a74fcb8df437df4b"}, - {file = "ruff-0.12.4-py3-none-win32.whl", hash = "sha256:4de27977827893cdfb1211d42d84bc180fceb7b72471104671c59be37041cf93"}, - {file = "ruff-0.12.4-py3-none-win_amd64.whl", hash = "sha256:fe0b9e9eb23736b453143d72d2ceca5db323963330d5b7859d60d101147d461a"}, - {file = "ruff-0.12.4-py3-none-win_arm64.whl", hash = "sha256:0618ec4442a83ab545e5b71202a5c0ed7791e8471435b94e655b570a5031a98e"}, - {file = "ruff-0.12.4.tar.gz", hash = "sha256:13efa16df6c6eeb7d0f091abae50f58e9522f3843edb40d56ad52a5a4a4b6873"}, + {file = "ruff-0.12.8-py3-none-linux_armv6l.whl", hash = "sha256:63cb5a5e933fc913e5823a0dfdc3c99add73f52d139d6cd5cc8639d0e0465513"}, + {file = "ruff-0.12.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a9bbe28f9f551accf84a24c366c1aa8774d6748438b47174f8e8565ab9dedbc"}, + {file = "ruff-0.12.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2fae54e752a3150f7ee0e09bce2e133caf10ce9d971510a9b925392dc98d2fec"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0acbcf01206df963d9331b5838fb31f3b44fa979ee7fa368b9b9057d89f4a53"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae3e7504666ad4c62f9ac8eedb52a93f9ebdeb34742b8b71cd3cccd24912719f"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb82efb5d35d07497813a1c5647867390a7d83304562607f3579602fa3d7d46f"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dbea798fc0065ad0b84a2947b0aff4233f0cb30f226f00a2c5850ca4393de609"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49ebcaccc2bdad86fd51b7864e3d808aad404aab8df33d469b6e65584656263a"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ac9c570634b98c71c88cb17badd90f13fc076a472ba6ef1d113d8ed3df109fb"}, + {file = "ruff-0.12.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560e0cd641e45591a3e42cb50ef61ce07162b9c233786663fdce2d8557d99818"}, + {file = "ruff-0.12.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:71c83121512e7743fba5a8848c261dcc454cafb3ef2934a43f1b7a4eb5a447ea"}, + {file = "ruff-0.12.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:de4429ef2ba091ecddedd300f4c3f24bca875d3d8b23340728c3cb0da81072c3"}, + {file = "ruff-0.12.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a2cab5f60d5b65b50fba39a8950c8746df1627d54ba1197f970763917184b161"}, + {file = "ruff-0.12.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:45c32487e14f60b88aad6be9fd5da5093dbefb0e3e1224131cb1d441d7cb7d46"}, + {file = "ruff-0.12.8-py3-none-win32.whl", hash = "sha256:daf3475060a617fd5bc80638aeaf2f5937f10af3ec44464e280a9d2218e720d3"}, + {file = "ruff-0.12.8-py3-none-win_amd64.whl", hash = "sha256:7209531f1a1fcfbe8e46bcd7ab30e2f43604d8ba1c49029bb420b103d0b5f76e"}, + {file = "ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749"}, + {file = "ruff-0.12.8.tar.gz", hash = "sha256:4cb3a45525176e1009b2b64126acf5f9444ea59066262791febf55e40493a033"}, ] [[package]] @@ -4102,4 +4093,4 @@ ifaddr = ">=0.1.7" [metadata] lock-version = "2.1" python-versions = ">=3.13.2,<3.14" -content-hash = "174aedcf17fad6e796736fe1070f3750a397a3ac28359b5da3e4461de2f8b9a9" +content-hash = "792fb2f76bfc132e921609b4f3b404b48ad3d69fb04826ae8434446ee18aeb97" From f32f3615549d5a5c06f04cabce62d7ab2f027c60 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 07:44:24 +0000 Subject: [PATCH 062/235] Remove fake device and filter outliers --- custom_components/battery_notes/__init__.py | 20 +++--- .../battery_notes/binary_sensor.py | 68 +++++++++---------- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 07176145b..0d5230b78 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -177,15 +177,17 @@ async def async_setup_entry( config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator assert subentry.unique_id - device_registry = dr.async_get(hass) - device_registry.async_get_or_create( - config_entry_id=config_entry.entry_id, - config_subentry_id= subentry.subentry_id, - identifiers={(DOMAIN, coordinator.unique_id)}, - entry_type=DeviceEntryType.SERVICE, - manufacturer=MANUFACTURER, - name=subentry.title - ) + + # Create a device, only needed if we want entities that are not added to the source device + # device_registry = dr.async_get(hass) + # device_registry.async_get_or_create( + # config_entry_id=config_entry.entry_id, + # config_subentry_id= subentry.subentry_id, + # identifiers={(DOMAIN, coordinator.unique_id)}, + # entry_type=DeviceEntryType.SERVICE, + # manufacturer=MANUFACTURER, + # name=subentry.title + # ) await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 689840413..bfac782ce 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -133,14 +133,14 @@ async def async_setup_entry( ) assert coordinator - battery_filtered_entity_description = BatteryNotesBinarySensorEntityDescription( - unique_id_suffix="_battery_outliers_filtered", - key="_battery_outliers_filtered", - translation_key="battery_outliers_filtered", - entity_category=EntityCategory.DIAGNOSTIC, - entity_type="binary_sensor", - attach_to_source_device=False, - ) + # battery_filtered_entity_description = BatteryNotesBinarySensorEntityDescription( + # unique_id_suffix="_battery_outliers_filtered", + # key="_battery_outliers_filtered", + # translation_key="battery_outliers_filtered", + # entity_category=EntityCategory.DIAGNOSTIC, + # entity_type="binary_sensor", + # attach_to_source_device=False, + # ) battery_low_entity_description = BatteryNotesBinarySensorEntityDescription( unique_id_suffix="_battery_low", @@ -151,16 +151,16 @@ async def async_setup_entry( entity_type="binary_sensor", ) - entities: list[BatteryNotesBatteryLowTemplateSensor | BatteryNotesBatteryLowSensor | BatteryNotesBatteryBinaryLowSensor] = [] + entities = [] - entities = [ - BatteryNotesFilteredSensor( - hass, - coordinator, - battery_filtered_entity_description, - f"{config_entry.entry_id}{subentry.unique_id}{battery_filtered_entity_description.unique_id_suffix}", - ) - ] + # entities = [ + # BatteryNotesFilteredSensor( + # hass, + # coordinator, + # battery_filtered_entity_description, + # f"{config_entry.entry_id}{subentry.unique_id}{battery_filtered_entity_description.unique_id_suffix}", + # ) + # ] if coordinator.battery_low_template is not None: entities.append( @@ -199,27 +199,27 @@ async def async_setup_entry( config_subentry_id=subentry.subentry_id, ) -class BatteryNotesFilteredSensor(BatteryNotesEntity, BinarySensorEntity): - """Represents a filtered battery sensor.""" +# class BatteryNotesFilteredSensor(BatteryNotesEntity, BinarySensorEntity): +# """Represents a filtered battery sensor.""" - entity_description: BatteryNotesBinarySensorEntityDescription +# entity_description: BatteryNotesBinarySensorEntityDescription - def __init__( - self, - hass: HomeAssistant, - coordinator: BatteryNotesCoordinator, - entity_description: BatteryNotesBinarySensorEntityDescription, - unique_id: str, - ) -> None: - """Create a filtered battery sensor.""" - super().__init__(hass, entity_description=entity_description, coordinator=coordinator) +# def __init__( +# self, +# hass: HomeAssistant, +# coordinator: BatteryNotesCoordinator, +# entity_description: BatteryNotesBinarySensorEntityDescription, +# unique_id: str, +# ) -> None: +# """Create a filtered battery sensor.""" +# super().__init__(hass, entity_description=entity_description, coordinator=coordinator) - self._attr_unique_id = unique_id +# self._attr_unique_id = unique_id - @property - def is_on(self) -> bool | None: - """Return true if sensor is on.""" - return self.coordinator.filter_outliers +# @property +# def is_on(self) -> bool | None: +# """Return true if sensor is on.""" +# return self.coordinator.filter_outliers class _TemplateAttribute: From 9492a03cb26b5b255585cfdda870a20b46cd3108 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 08:54:04 +0000 Subject: [PATCH 063/235] Support removing of sub entries --- custom_components/battery_notes/__init__.py | 84 +++++++++---------- .../battery_notes/coordinator.py | 2 +- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 0d5230b78..b14b533d1 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -166,7 +166,7 @@ async def async_setup_entry( config_entry.runtime_data = BatteryNotesData( domain_config=domain_config, store=domain_config.store, - subentries=config_entry.subentries.copy(), + loaded_subentries=config_entry.subentries.copy(), ) config_entry.runtime_data.subentry_coordinators = {} @@ -214,43 +214,9 @@ async def async_unload_entry( async def async_remove_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry ) -> None: - """Device removed, tidy up store.""" + """Battery Notes integration removed.""" - # TODO: Make this sub config entry aware - # Instead of remove_entry, we should listen for the config_entry being updated and compare old/new - # sub entries, then remove any that are no longer present - - # Remove any issues raised - ir.async_delete_issue(hass, DOMAIN, f"missing_device_{config_entry.entry_id}") - - store = await async_get_registry(hass) - coordinator = BatteryNotesCoordinator(hass, config_entry) - - if coordinator.source_entity_id: - store.async_delete_entity(coordinator.source_entity_id) - else: - if coordinator.device_id: - store.async_delete_device(coordinator.device_id) - - _LOGGER.debug("Removed battery note %s", config_entry.entry_id) - - # Unhide the battery - entity_registry = er.async_get(hass) - if not coordinator.wrapped_battery: - return - - if not ( - wrapped_battery_entity_entry := entity_registry.async_get( - coordinator.wrapped_battery.entity_id - ) - ): - return - - if wrapped_battery_entity_entry.hidden_by == er.RegistryEntryHider.INTEGRATION: - entity_registry.async_update_entity( - coordinator.wrapped_battery.entity_id, hidden_by=None - ) - _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) + # TODO: Decide what we want to delete, could be all of store async def async_migrate_entry( @@ -370,24 +336,50 @@ async def update_listener( ) -> None: """Update the device and related entities. - Triggered when the device is renamed on the frontend. + Triggered when the device is renamed on the frontend, or when sub entries are updated. Look at sub entries and remove any that are no longer present. """ - for subentry in config_entry.runtime_data.subentries: + for subentry in config_entry.runtime_data.loaded_subentries.values(): if subentry not in config_entry.subentries: - _LOGGER.debug( - "Sub entry %s no longer present, removing it from runtime data", - subentry, - ) # TODO: Remove the stuff in async_remove_entry here - if subentry in config_entry.runtime_data.subentry_coordinators: - del config_entry.runtime_data.subentry_coordinators[subentry] + coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) + + # Remove any issues raised + ir.async_delete_issue(hass, DOMAIN, f"missing_device_{subentry.subentry_id}") + + # Delete the store entries + store = coordinator.config_entry.runtime_data.store + + if coordinator.source_entity_id: + store.async_delete_entity(coordinator.source_entity_id) + else: + if coordinator.device_id: + store.async_delete_device(coordinator.device_id) + + # Unhide the battery + entity_registry = er.async_get(hass) + if not coordinator.wrapped_battery: + return + + if ( + wrapped_battery_entity_entry := entity_registry.async_get( + coordinator.wrapped_battery.entity_id + ) + ): + if wrapped_battery_entity_entry.hidden_by == er.RegistryEntryHider.INTEGRATION: + entity_registry.async_update_entity( + coordinator.wrapped_battery.entity_id, hidden_by=None + ) + _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) + + config_entry.runtime_data.subentry_coordinators.pop(subentry, None) - config_entry.runtime_data.subentries = config_entry.subentries.copy() + # Update the config entry with the new sub entries + config_entry.runtime_data.loaded_subentries = config_entry.subentries.copy() await hass.config_entries.async_reload(config_entry.entry_id) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 4aa97e476..1ff9f2d3b 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -85,7 +85,7 @@ class BatteryNotesData: domain_config: BatteryNotesDomainConfig store: BatteryNotesStorage - subentries: dict[str, ConfigSubentry] + loaded_subentries: dict[str, ConfigSubentry] subentry_coordinators: dict[str, BatteryNotesCoordinator] | None = None class BatteryNotesCoordinator(DataUpdateCoordinator[None]): From 7c9e85dbb66edad451e3f6904180687d8359510e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 08:54:26 +0000 Subject: [PATCH 064/235] Remove todo --- custom_components/battery_notes/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index b14b533d1..b03ebf37d 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -343,9 +343,6 @@ async def update_listener( for subentry in config_entry.runtime_data.loaded_subentries.values(): if subentry not in config_entry.subentries: - - # TODO: Remove the stuff in async_remove_entry here - coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) # Remove any issues raised From d539808d65d06f87d190a9020327c0c04c8282c8 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 09:08:22 +0000 Subject: [PATCH 065/235] Enhance subentry removal process in Battery Notes integration --- custom_components/battery_notes/__init__.py | 72 ++++++++++++--------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index b03ebf37d..57b3ad650 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -12,7 +12,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigSubentry from homeassistant.const import CONF_SOURCE from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback @@ -216,7 +216,9 @@ async def async_remove_entry( ) -> None: """Battery Notes integration removed.""" - # TODO: Decide what we want to delete, could be all of store + for subentry in config_entry.subentries.values(): + if subentry not in config_entry.subentries: + await async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) async def async_migrate_entry( @@ -343,43 +345,53 @@ async def update_listener( for subentry in config_entry.runtime_data.loaded_subentries.values(): if subentry not in config_entry.subentries: - coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) + await async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) - # Remove any issues raised - ir.async_delete_issue(hass, DOMAIN, f"missing_device_{subentry.subentry_id}") + # Update the config entry with the new sub entries + config_entry.runtime_data.loaded_subentries = config_entry.subentries.copy() - # Delete the store entries - store = coordinator.config_entry.runtime_data.store + await hass.config_entries.async_reload(config_entry.entry_id) - if coordinator.source_entity_id: - store.async_delete_entity(coordinator.source_entity_id) - else: - if coordinator.device_id: - store.async_delete_device(coordinator.device_id) - # Unhide the battery - entity_registry = er.async_get(hass) - if not coordinator.wrapped_battery: - return +async def async_remove_subentry( + hass: HomeAssistant, + config_entry: BatteryNotesConfigEntry, + subentry: ConfigSubentry, + remove_store_entries: bool, +) -> None: + """Remove a sub entry.""" + _LOGGER.debug("Removing sub entry %s from config entry %s", subentry.subentry_id, config_entry.entry_id) - if ( - wrapped_battery_entity_entry := entity_registry.async_get( - coordinator.wrapped_battery.entity_id - ) - ): - if wrapped_battery_entity_entry.hidden_by == er.RegistryEntryHider.INTEGRATION: - entity_registry.async_update_entity( - coordinator.wrapped_battery.entity_id, hidden_by=None - ) - _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) + coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) - config_entry.runtime_data.subentry_coordinators.pop(subentry, None) + # Remove any issues raised + ir.async_delete_issue(hass, DOMAIN, f"missing_device_{subentry.subentry_id}") - # Update the config entry with the new sub entries - config_entry.runtime_data.loaded_subentries = config_entry.subentries.copy() + # Remove store entries + if remove_store_entries: + store = coordinator.config_entry.runtime_data.store - await hass.config_entries.async_reload(config_entry.entry_id) + if coordinator.source_entity_id: + store.async_delete_entity(coordinator.source_entity_id) + else: + if coordinator.device_id: + store.async_delete_device(coordinator.device_id) + + # Unhide the battery + entity_registry = er.async_get(hass) + + if ( + wrapped_battery_entity_entry := entity_registry.async_get( + coordinator.wrapped_battery.entity_id + ) + ): + if wrapped_battery_entity_entry.hidden_by == er.RegistryEntryHider.INTEGRATION: + entity_registry.async_update_entity( + coordinator.wrapped_battery.entity_id, hidden_by=None + ) + _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) + config_entry.runtime_data.subentry_coordinators.pop(subentry, None) @callback async def async_update_options( From d04f1a63227bef5c9768e2bdca0b63829da2fa74 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 09:08:54 +0000 Subject: [PATCH 066/235] Remove unused imports from __init__.py --- custom_components/battery_notes/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 57b3ad650..f241d3a7e 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -17,10 +17,8 @@ from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv -from homeassistant.helpers import device_registry as dr from homeassistant.helpers import entity_registry as er from homeassistant.helpers import issue_registry as ir -from homeassistant.helpers.device_registry import DeviceEntryType from homeassistant.helpers.typing import ConfigType from .config_flow import CONFIG_VERSION @@ -39,7 +37,6 @@ DEFAULT_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD, DOMAIN, - MANUFACTURER, MIN_HA_VERSION, PLATFORMS, ) From 1b2de69f12ea7b77e88ce3ffce210e7c858665fc Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 10:01:47 +0000 Subject: [PATCH 067/235] Create new config entry if old removed when we have discovered items --- custom_components/battery_notes/__init__.py | 1 - .../battery_notes/config_flow.py | 29 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index f241d3a7e..34130eaaf 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -217,7 +217,6 @@ async def async_remove_entry( if subentry not in config_entry.subentries: await async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) - async def async_migrate_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry ): diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 34d50ec07..2d455a452 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -184,7 +184,33 @@ async def async_step_integration_discovery( unique_id = f"bn_{discovery_info[CONF_DEVICE_ID]}" # Check if unique_id already exists as sub entry - config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] + config_entries = self.hass.config_entries.async_entries(domain=DOMAIN) + if not config_entries: + _LOGGER.debug("No existing single config entry found, creating new one") + + # Init defaults + options = { + CONF_SHOW_ALL_DEVICES: False, + CONF_HIDE_BATTERY: False, + CONF_ROUND_BATTERY: False, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, + CONF_ADVANCED_SETTINGS: { + CONF_ENABLE_AUTODISCOVERY: True, + CONF_ENABLE_REPLACED: True, + CONF_USER_LIBRARY: "", + } + } + + self.async_create_entry( + title=APP_NAME, + data={}, + options=options + ) + + config_entries = self.hass.config_entries.async_entries(domain=DOMAIN) + + config_entry = config_entries[0] for existing_subentry in config_entry.subentries.values(): if existing_subentry.unique_id == unique_id: _LOGGER.debug("Subentry with unique_id %s already exists", unique_id) @@ -792,6 +818,7 @@ async def async_step_reconfigure( self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input[CONF_BATTERY_LOW_TEMPLATE] self.data[CONF_FILTER_OUTLIERS] = user_input.get(CONF_FILTER_OUTLIERS, False) + # TODO: Review and remove this # Update the subentry with new data # config_subentry.data.update(self.data) # config_subentry.title = self.data.get(CONF_NAME, config_subentry.title) From cfa534b3f8097cedd8979e4b702924a8092aa2ca Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 10:02:54 +0000 Subject: [PATCH 068/235] Remove unused code --- custom_components/battery_notes/config_flow.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 2d455a452..3eb9f77d7 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -803,7 +803,6 @@ async def async_step_reconfigure( """User flow to modify an existing battery note.""" errors: dict[str, str] = {} - config_entry = self._get_entry() config_subentry = self._get_reconfigure_subentry() if user_input is not None: @@ -818,20 +817,9 @@ async def async_step_reconfigure( self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input[CONF_BATTERY_LOW_TEMPLATE] self.data[CONF_FILTER_OUTLIERS] = user_input.get(CONF_FILTER_OUTLIERS, False) - # TODO: Review and remove this - # Update the subentry with new data - # config_subentry.data.update(self.data) - # config_subentry.title = self.data.get(CONF_NAME, config_subentry.title) - # Save the updated subentry new_title = user_input.pop(CONF_NAME) - # self.hass.config_entries.async_update_subentry( - # entry=config_entry, - # subentry=config_subentry, - # data=user_input, - # title=new_title) - return self.async_update_and_abort( self._get_entry(), self._get_reconfigure_subentry(), From 9300007b806941297973c69ef9acc002bfb87e39 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 11:21:56 +0000 Subject: [PATCH 069/235] Fix migration entry versioning in async_migrate_entry function --- custom_components/battery_notes/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 34130eaaf..637e84697 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -244,13 +244,13 @@ async def async_migrate_entry( new_data[CONF_BATTERY_QUANTITY] = _qty hass.config_entries.async_update_entry( - config_entry, version=new_version, title=config_entry.title, data=new_data + config_entry, version=2, title=config_entry.title, data=new_data ) _LOGGER.info( "Entry %s successfully migrated to version %s.", config_entry.entry_id, - new_version, + 2, ) if config_entry.version < 3: From 81510c97544eac09ae8338330c77ba22951539b5 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 13:13:24 +0000 Subject: [PATCH 070/235] Work on migration --- custom_components/battery_notes/__init__.py | 47 +++++++++++---------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 637e84697..75d10b4c8 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -112,19 +112,19 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: DOMAIN, context={CONF_SOURCE: SOURCE_IMPORT}, data={ - CONF_SHOW_ALL_DEVICES: yaml_domain_config.get(CONF_SHOW_ALL_DEVICES, False), - CONF_HIDE_BATTERY: yaml_domain_config.get(CONF_HIDE_BATTERY, False), - CONF_ROUND_BATTERY: yaml_domain_config.get(CONF_ROUND_BATTERY, False), - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: yaml_domain_config.get( + CONF_SHOW_ALL_DEVICES: yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), + CONF_HIDE_BATTERY: yaml_domain_config[0].get(CONF_HIDE_BATTERY, False), + CONF_ROUND_BATTERY: yaml_domain_config[0].get(CONF_ROUND_BATTERY, False), + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: yaml_domain_config[0].get( CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD ), - CONF_BATTERY_INCREASE_THRESHOLD: yaml_domain_config.get( + CONF_BATTERY_INCREASE_THRESHOLD: yaml_domain_config[0].get( CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD ), CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: yaml_domain_config.get(CONF_ENABLE_AUTODISCOVERY, True), - CONF_ENABLE_REPLACED: yaml_domain_config.get(CONF_ENABLE_REPLACED, True), - CONF_USER_LIBRARY: yaml_domain_config.get(CONF_USER_LIBRARY, ""), + CONF_ENABLE_AUTODISCOVERY: yaml_domain_config[0].get(CONF_ENABLE_AUTODISCOVERY, True), + CONF_ENABLE_REPLACED: yaml_domain_config[0].get(CONF_ENABLE_REPLACED, True), + CONF_USER_LIBRARY: yaml_domain_config[0].get(CONF_USER_LIBRARY, ""), }, } ) @@ -276,19 +276,19 @@ async def async_migrate_entry( if _yaml_domain_config: options={ - CONF_SHOW_ALL_DEVICES: _yaml_domain_config.get(CONF_SHOW_ALL_DEVICES, False), - CONF_HIDE_BATTERY: _yaml_domain_config.get(CONF_HIDE_BATTERY, False), - CONF_ROUND_BATTERY: _yaml_domain_config.get(CONF_ROUND_BATTERY, False), - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: _yaml_domain_config.get( + CONF_SHOW_ALL_DEVICES: _yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), + CONF_HIDE_BATTERY: _yaml_domain_config[0].get(CONF_HIDE_BATTERY, False), + CONF_ROUND_BATTERY: _yaml_domain_config[0].get(CONF_ROUND_BATTERY, False), + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: _yaml_domain_config[0].get( CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD ), - CONF_BATTERY_INCREASE_THRESHOLD: _yaml_domain_config.get( + CONF_BATTERY_INCREASE_THRESHOLD: _yaml_domain_config[0].get( CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD ), CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: _yaml_domain_config.get(CONF_ENABLE_AUTODISCOVERY, True), - CONF_ENABLE_REPLACED: _yaml_domain_config.get(CONF_ENABLE_REPLACED, True), - CONF_USER_LIBRARY: _yaml_domain_config.get(CONF_USER_LIBRARY, ""), + CONF_ENABLE_AUTODISCOVERY: _yaml_domain_config[0].get(CONF_ENABLE_AUTODISCOVERY, True), + CONF_ENABLE_REPLACED: _yaml_domain_config[0].get(CONF_ENABLE_REPLACED, True), + CONF_USER_LIBRARY: _yaml_domain_config[0].get(CONF_USER_LIBRARY, ""), }, } else: @@ -316,16 +316,19 @@ async def async_migrate_entry( assert _migrate_base_entry is not None, "Base entry should not be None" - # TODO: Change this config entry into a sub entry, add it to the base entry + # Update the base entry with the new subentry + subentry = ConfigSubentry(subentry_type="battery_note", data=config_entry.data, title=config_entry.title, unique_id=config_entry.unique_id) + hass.config_entries.async_add_subentry(config_entry, subentry) - _LOGGER.debug( - "Migrating config entry %s from version %s to version %s", + # Remove the old config entry + await hass.config_entries.async_remove(config_entry.entry_id) + + _LOGGER.info( + "Entry %s successfully migrated to subentry of %s.", config_entry.entry_id, - config_entry.version, - new_version, + _migrate_base_entry.entry_id, ) - return True From 14d68be2f11f6f5fc40873942312031727e2144e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 13:14:29 +0000 Subject: [PATCH 071/235] Remove unused variable in async_migrate_entry function --- custom_components/battery_notes/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 75d10b4c8..8fac8eb20 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -221,7 +221,6 @@ async def async_migrate_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry ): """Migrate old config.""" - new_version = CONFIG_VERSION if config_entry.version == 1: # Version 1 had a single config for qty & type, split them From 4ddc6df9acd547c66633080728aa4536a5648c34 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 13:14:43 +0000 Subject: [PATCH 072/235] Remove unused import of CONFIG_VERSION from __init__.py --- custom_components/battery_notes/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 8fac8eb20..020d04559 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -21,7 +21,6 @@ from homeassistant.helpers import issue_registry as ir from homeassistant.helpers.typing import ConfigType -from .config_flow import CONFIG_VERSION from .const import ( CONF_ADVANCED_SETTINGS, CONF_BATTERY_INCREASE_THRESHOLD, From 9f3dd500aa09d00c2a92c886aef33567c9053229 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 13:32:40 +0000 Subject: [PATCH 073/235] Refactor configuration handling in async_setup and async_migrate_entry functions --- custom_components/battery_notes/__init__.py | 23 ++++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 020d04559..d0ffc3c62 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -104,26 +104,27 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: store=store, ) - yaml_domain_config: list[dict[str, Any]] | None = config.get(DOMAIN) - if yaml_domain_config: + global _yaml_domain_config + _yaml_domain_config = config.get(DOMAIN) + if _yaml_domain_config: hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, context={CONF_SOURCE: SOURCE_IMPORT}, data={ - CONF_SHOW_ALL_DEVICES: yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), - CONF_HIDE_BATTERY: yaml_domain_config[0].get(CONF_HIDE_BATTERY, False), - CONF_ROUND_BATTERY: yaml_domain_config[0].get(CONF_ROUND_BATTERY, False), - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: yaml_domain_config[0].get( + CONF_SHOW_ALL_DEVICES: _yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), + CONF_HIDE_BATTERY: _yaml_domain_config[0].get(CONF_HIDE_BATTERY, False), + CONF_ROUND_BATTERY: _yaml_domain_config[0].get(CONF_ROUND_BATTERY, False), + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: _yaml_domain_config[0].get( CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD ), - CONF_BATTERY_INCREASE_THRESHOLD: yaml_domain_config[0].get( + CONF_BATTERY_INCREASE_THRESHOLD: _yaml_domain_config[0].get( CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD ), CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: yaml_domain_config[0].get(CONF_ENABLE_AUTODISCOVERY, True), - CONF_ENABLE_REPLACED: yaml_domain_config[0].get(CONF_ENABLE_REPLACED, True), - CONF_USER_LIBRARY: yaml_domain_config[0].get(CONF_USER_LIBRARY, ""), + CONF_ENABLE_AUTODISCOVERY: _yaml_domain_config[0].get(CONF_ENABLE_AUTODISCOVERY, True), + CONF_ENABLE_REPLACED: _yaml_domain_config[0].get(CONF_ENABLE_REPLACED, True), + CONF_USER_LIBRARY: _yaml_domain_config[0].get(CONF_USER_LIBRARY, ""), }, } ) @@ -253,6 +254,7 @@ async def async_migrate_entry( if config_entry.version < 3: # Get the current config entries, see if one is at V3 and hold onto it as the base + global _migrate_base_entry if not _migrate_base_entry: _LOGGER.debug("No base entry, looking for existing V3 entries") @@ -272,6 +274,7 @@ async def async_migrate_entry( "No existing V3 config entry found, creating a new one for migration" ) + global _yaml_domain_config if _yaml_domain_config: options={ CONF_SHOW_ALL_DEVICES: _yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), From b68581790e99f7b1c6a6551d2e586a5fbfa95813 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 13:38:34 +0000 Subject: [PATCH 074/235] Remove battery note from source device --- custom_components/battery_notes/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index d0ffc3c62..a8a102000 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -13,11 +13,12 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigSubentry -from homeassistant.const import CONF_SOURCE +from homeassistant.const import CONF_DEVICE_ID, CONF_SOURCE from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers import entity_registry as er +from homeassistant.helpers import helper_integration from homeassistant.helpers import issue_registry as ir from homeassistant.helpers.typing import ConfigType @@ -321,6 +322,11 @@ async def async_migrate_entry( subentry = ConfigSubentry(subentry_type="battery_note", data=config_entry.data, title=config_entry.title, unique_id=config_entry.unique_id) hass.config_entries.async_add_subentry(config_entry, subentry) + source_device_id = config_entry.data.get(CONF_DEVICE_ID, None) + + if source_device_id: + helper_integration.async_remove_helper_config_entry_from_source_device(hass, config_entry.entry_id, source_device_id) + # Remove the old config entry await hass.config_entries.async_remove(config_entry.entry_id) From 6ab2ea1b05d8c0dc0fa66ecc5538de8a196969fc Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 13:40:17 +0000 Subject: [PATCH 075/235] Add missing newline for improved readability in async_migrate_entry function --- custom_components/battery_notes/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index a8a102000..7e622f7b2 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -256,6 +256,7 @@ async def async_migrate_entry( if config_entry.version < 3: # Get the current config entries, see if one is at V3 and hold onto it as the base global _migrate_base_entry + if not _migrate_base_entry: _LOGGER.debug("No base entry, looking for existing V3 entries") From d7ed04fa8d7aa5aab50cc483516cd6f0e94eda05 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 12 Aug 2025 13:41:11 +0000 Subject: [PATCH 076/235] Refactor variable names in async_migrate_entry for clarity --- custom_components/battery_notes/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 7e622f7b2..e50f938ce 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -231,17 +231,17 @@ async def async_migrate_entry( r"^(\d+)(?=x)(?:x\s)(\w+$)|([\s\S]+)", config_entry.data[CONF_BATTERY_TYPE] ) if matches: - _qty = matches.group(1) if matches.group(1) is not None else "1" - _type = ( + qty = matches.group(1) if matches.group(1) is not None else "1" + type = ( matches.group(2) if matches.group(2) is not None else matches.group(3) ) else: - _qty = 1 - _type = config_entry.data[CONF_BATTERY_TYPE] + qty = 1 + type = config_entry.data[CONF_BATTERY_TYPE] new_data = {**config_entry.data} - new_data[CONF_BATTERY_TYPE] = _type - new_data[CONF_BATTERY_QUANTITY] = _qty + new_data[CONF_BATTERY_TYPE] = type + new_data[CONF_BATTERY_QUANTITY] = qty hass.config_entries.async_update_entry( config_entry, version=2, title=config_entry.title, data=new_data From 7da34a5379dd67803b17157ffe5d52c422ca907a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 08:45:41 +0000 Subject: [PATCH 077/235] Rename BatteryNotesCoordinator to BatteryNotesSubentryCoordinator for consistency across components --- custom_components/battery_notes/__init__.py | 4 ++-- custom_components/battery_notes/binary_sensor.py | 10 +++++----- custom_components/battery_notes/button.py | 4 ++-- custom_components/battery_notes/coordinator.py | 4 ++-- custom_components/battery_notes/entity.py | 8 ++++---- custom_components/battery_notes/sensor.py | 12 ++++++++---- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index e50f938ce..3f9961781 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -44,9 +44,9 @@ from .coordinator import ( MY_KEY, BatteryNotesConfigEntry, - BatteryNotesCoordinator, BatteryNotesData, BatteryNotesDomainConfig, + BatteryNotesSubentryCoordinator, ) from .discovery import DiscoveryManager from .library_updater import LibraryUpdater @@ -171,7 +171,7 @@ async def async_setup_entry( for subentry in config_entry.subentries.values(): if subentry.subentry_type == "battery_note": - coordinator = BatteryNotesCoordinator(hass, config_entry, subentry) + coordinator = BatteryNotesSubentryCoordinator(hass, config_entry, subentry) config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator assert subentry.unique_id diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index bfac782ce..f5615e608 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -74,7 +74,7 @@ from .coordinator import ( MY_KEY, BatteryNotesConfigEntry, - BatteryNotesCoordinator, + BatteryNotesSubentryCoordinator, ) from .entity import BatteryNotesEntity, BatteryNotesEntityDescription @@ -327,7 +327,7 @@ class BatteryNotesBatteryLowBaseSensor( def __init__( self, hass: HomeAssistant, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, entity_description: BatteryNotesBinarySensorEntityDescription, ): """Initialize the low battery binary sensor.""" @@ -386,7 +386,7 @@ class BatteryNotesBatteryLowTemplateSensor( def __init__( self, hass: HomeAssistant, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, entity_description: BatteryNotesBinarySensorEntityDescription, unique_id: str, template: str, @@ -581,7 +581,7 @@ class BatteryNotesBatteryLowSensor(BatteryNotesBatteryLowBaseSensor): def __init__( self, hass: HomeAssistant, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, entity_description: BatteryNotesBinarySensorEntityDescription, unique_id: str, ) -> None: @@ -661,7 +661,7 @@ class BatteryNotesBatteryBinaryLowSensor(BatteryNotesBatteryLowBaseSensor): def __init__( self, hass: HomeAssistant, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, entity_description: BatteryNotesBinarySensorEntityDescription, unique_id: str, ) -> None: diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 9f97f0c32..1bb3c61ec 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -33,7 +33,7 @@ DOMAIN, EVENT_BATTERY_REPLACED, ) -from .coordinator import BatteryNotesConfigEntry, BatteryNotesCoordinator +from .coordinator import BatteryNotesConfigEntry, BatteryNotesSubentryCoordinator from .entity import BatteryNotesEntity, BatteryNotesEntityDescription _LOGGER = logging.getLogger(__name__) @@ -113,7 +113,7 @@ class BatteryNotesButton(BatteryNotesEntity, ButtonEntity): def __init__( self, hass: HomeAssistant, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, entity_description: BatteryNotesButtonEntityDescription, unique_id: str, ) -> None: diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 1ff9f2d3b..626f8f499 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -86,9 +86,9 @@ class BatteryNotesData: domain_config: BatteryNotesDomainConfig store: BatteryNotesStorage loaded_subentries: dict[str, ConfigSubentry] - subentry_coordinators: dict[str, BatteryNotesCoordinator] | None = None + subentry_coordinators: dict[str, BatteryNotesSubentryCoordinator] | None = None -class BatteryNotesCoordinator(DataUpdateCoordinator[None]): +class BatteryNotesSubentryCoordinator(DataUpdateCoordinator[None]): """Define an object to hold Battery Notes device.""" config_entry: BatteryNotesConfigEntry diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index b3536860b..532657b6e 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -12,7 +12,7 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN -from .coordinator import BatteryNotesCoordinator +from .coordinator import BatteryNotesSubentryCoordinator @dataclass(frozen=True, kw_only=True) @@ -30,17 +30,17 @@ class BatteryNotesEntityDescription(EntityDescription, BatteryNotesRequiredKeysM """Generic Battery Notes entity description.""" -class BatteryNotesEntity(CoordinatorEntity[BatteryNotesCoordinator]): +class BatteryNotesEntity(CoordinatorEntity[BatteryNotesSubentryCoordinator]): """Base class for Battery Notes entities.""" - coordinator: BatteryNotesCoordinator + coordinator: BatteryNotesSubentryCoordinator entity_description: BatteryNotesEntityDescription def __init__( self, hass: HomeAssistant, entity_description: BatteryNotesEntityDescription, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, ) -> None: """Initialize the base entity.""" super().__init__(coordinator) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 826e1de39..85a5506d8 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -66,7 +66,11 @@ CONF_SOURCE_ENTITY_ID, DOMAIN, ) -from .coordinator import MY_KEY, BatteryNotesConfigEntry, BatteryNotesCoordinator +from .coordinator import ( + MY_KEY, + BatteryNotesConfigEntry, + BatteryNotesSubentryCoordinator, +) from .entity import BatteryNotesEntity, BatteryNotesEntityDescription @@ -190,7 +194,7 @@ def __init__( config_entry: BatteryNotesConfigEntry, subentry: ConfigSubentry, entity_description: BatteryNotesEntityDescription, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, unique_id: str, ) -> None: # pylint: disable=unused-argument @@ -253,7 +257,7 @@ def __init__( config_entry: BatteryNotesConfigEntry, subentry: ConfigSubentry, entity_description: BatteryNotesEntityDescription, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, description: BatteryNotesSensorEntityDescription, unique_id: str, ) -> None: @@ -327,7 +331,7 @@ def __init__( config_entry: BatteryNotesConfigEntry, subentry: ConfigSubentry, entity_description: BatteryNotesEntityDescription, - coordinator: BatteryNotesCoordinator, + coordinator: BatteryNotesSubentryCoordinator, unique_id: str, enable_replaced: bool, round_battery: bool, From 899c7621d8f08d05d4f5954a946b3985b01ad674 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 09:06:33 +0000 Subject: [PATCH 078/235] Update missing device repair flow to include subentry_id handling --- custom_components/battery_notes/coordinator.py | 3 ++- custom_components/battery_notes/repairs.py | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 626f8f499..c9bf76acb 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -213,7 +213,8 @@ def _link_device(self) -> bool: DOMAIN, f"missing_device_{self.subentry.subentry_id}", data={ - "entry_id": self.subentry.subentry_id, + "entry_id": self.config_entry.entry_id, + "subentry_id": self.subentry.subentry_id, "device_id": self.device_id, "source_entity_id": self.source_entity_id, }, diff --git a/custom_components/battery_notes/repairs.py b/custom_components/battery_notes/repairs.py index 70372687f..a53c513bd 100644 --- a/custom_components/battery_notes/repairs.py +++ b/custom_components/battery_notes/repairs.py @@ -20,6 +20,7 @@ def __init__(self, data: dict[str, str | int | float | None] | None) -> None: if not data or any(key not in data for key in REQUIRED_KEYS): raise ValueError("Missing data") self.entry_id = cast(str, data["entry_id"]) + self.subentry_id = cast(str, data["subentry_id"]) self.device_id = cast(str, data["device_id"]) self.source_entity_id = cast(str, data["source_entity_id"]) @@ -35,9 +36,10 @@ async def async_step_confirm( ) -> data_entry_flow.FlowResult: """Handle the confirm step of a fix flow.""" if user_input is not None: - await self.hass.config_entries.async_remove(self.entry_id) + entry = self.hass.config_entries.async_get_entry(self.entry_id) + self.hass.config_entries.async_remove_subentry(entry, self.subentry_id) - return self.async_create_entry(title="", data={}) + return self.async_create_entry(data={}) issue_registry = ir.async_get(self.hass) description_placeholders = None @@ -59,5 +61,6 @@ async def async_create_fix_flow( """Create flow.""" if issue_id.startswith("missing_device_"): assert data + return MissingDeviceRepairFlow(data) raise ValueError(f"unknown repair {issue_id}") From c79fb84ff7a348e8c90d1032e76ad96878f2d49b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 09:22:32 +0000 Subject: [PATCH 079/235] Add exception handling for unconfigured entities in Battery Notes --- custom_components/battery_notes/services.py | 26 +++++++++++-------- .../battery_notes/translations/en.json | 5 ++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/custom_components/battery_notes/services.py b/custom_components/battery_notes/services.py index a87280e5d..223a9e036 100644 --- a/custom_components/battery_notes/services.py +++ b/custom_components/battery_notes/services.py @@ -10,6 +10,7 @@ ServiceResponse, callback, ) +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import device_registry as dr from homeassistant.helpers import entity_registry as er from homeassistant.util import dt as dt_util @@ -139,17 +140,21 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: return None if not entity_found: - _LOGGER.error("Entity %s not configured in Battery Notes", source_entity_id) - return None + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="not_configured_in_battery_notes", + translation_placeholders={"source": source_entity_id}, + ) + return None else: device_entry = device_registry.async_get(device_id) if not device_entry: - _LOGGER.error( - "Device %s not found", - device_id, + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="not_configured_in_battery_notes", + translation_placeholders={"source": device_id}, ) - return None # Check if device_id exists in any sub config entry device_found = False @@ -192,13 +197,12 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: return None if not device_found: - _LOGGER.error( - "Device %s not configured in Battery Notes", - device_id, + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="not_configured_in_battery_notes", + translation_placeholders={"source": device_id}, ) - return None return None - return None async def _async_battery_last_reported(call: ServiceCall) -> ServiceResponse: diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index b1967e71c..440c79085 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -301,5 +301,10 @@ "title": "The {integration_title} YAML configuration is being removed", "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." + } } } \ No newline at end of file From b097809fe9f992ea752e498675881537f9018311 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 10:00:11 +0000 Subject: [PATCH 080/235] WIP --- .gitignore | 1 + custom_components/battery_notes/__init__.py | 21 +++++++++---------- .../battery_notes/config_flow.py | 8 +++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 539c959a0..ee42580ea 100644 --- a/.gitignore +++ b/.gitignore @@ -16,5 +16,6 @@ config/* !config/configuration.yaml .DS_Store config/configuration.yaml +backup/* custom_components/battery_notes/frontend/node_modules diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 3f9961781..f1c063f21 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -308,28 +308,27 @@ async def async_migrate_entry( }, } - _migrate_base_entry = ConfigEntry( - domain=DOMAIN, - title=INTEGRATION_NAME, - version=3, - unique_id=DOMAIN, - options=options, - ) - await hass.config_entries.async_add(_migrate_base_entry) + # Convert the first entry to the base entry then immediately add the subentry + hass.config_entries.async_update_entry( + config_entry, version=3, title=INTEGRATION_NAME, data={}, options=options + ) + + _migrate_base_entry = config_entry assert _migrate_base_entry is not None, "Base entry should not be None" # Update the base entry with the new subentry subentry = ConfigSubentry(subentry_type="battery_note", data=config_entry.data, title=config_entry.title, unique_id=config_entry.unique_id) - hass.config_entries.async_add_subentry(config_entry, subentry) + hass.config_entries.async_add_subentry(_migrate_base_entry, subentry) source_device_id = config_entry.data.get(CONF_DEVICE_ID, None) if source_device_id: - helper_integration.async_remove_helper_config_entry_from_source_device(hass, config_entry.entry_id, source_device_id) + helper_integration.async_remove_helper_config_entry_from_source_device(hass=hass, helper_config_entry_id=config_entry.entry_id, source_device_id=source_device_id) # Remove the old config entry - await hass.config_entries.async_remove(config_entry.entry_id) + if config_entry.entry_id != _migrate_base_entry.entry_id: + hass.config_entries.async_remove(config_entry.entry_id) _LOGGER.info( "Entry %s successfully migrated to subentry of %s.", diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 3eb9f77d7..33a40d152 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -56,7 +56,7 @@ DOMAIN, ISSUE_DEPRECATED_YAML, ) -from .const import NAME as APP_NAME +from .const import NAME as INTEGRATION_NAME from .coordinator import MY_KEY from .library import Library, ModelInfo from .library_updater import LibraryUpdater @@ -203,7 +203,7 @@ async def async_step_integration_discovery( } self.async_create_entry( - title=APP_NAME, + title=INTEGRATION_NAME, data={}, options=options ) @@ -243,7 +243,7 @@ async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResu translation_key=ISSUE_DEPRECATED_YAML, translation_placeholders={ "domain": DOMAIN, - "integration_title": APP_NAME, + "integration_title": INTEGRATION_NAME, }, ) @@ -279,7 +279,7 @@ async def async_step_user( options = user_input return self.async_create_entry( - title=APP_NAME, + title=INTEGRATION_NAME, data={}, options=options ) From a0dee29cda13d0550f0a3c96aca7b5f061ab4b41 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 11:58:49 +0000 Subject: [PATCH 081/235] Migrate integration --- custom_components/battery_notes/__init__.py | 211 +++++++++--------- .../battery_notes/config_flow.py | 52 +---- 2 files changed, 117 insertions(+), 146 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index f1c063f21..10a158d81 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -12,14 +12,19 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigSubentry -from homeassistant.const import CONF_DEVICE_ID, CONF_SOURCE +from homeassistant.config_entries import ConfigEntry, ConfigSubentry +from homeassistant.const import CONF_DEVICE_ID from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers import entity_registry as er from homeassistant.helpers import helper_integration from homeassistant.helpers import issue_registry as ir +from homeassistant.helpers.device import ( + async_entity_id_to_device_id, + async_remove_stale_devices_links_keep_entity_device, +) +from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.typing import ConfigType from .const import ( @@ -37,6 +42,7 @@ DEFAULT_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD, DOMAIN, + ISSUE_DEPRECATED_YAML, MIN_HA_VERSION, PLATFORMS, ) @@ -83,9 +89,6 @@ extra=vol.ALLOW_EXTRA, ) -_migrate_base_entry: ConfigEntry | None = None -_yaml_domain_config: list[dict[str, Any]] | None = None - async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Integration setup.""" @@ -98,39 +101,14 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: _LOGGER.critical(msg) return False + await async_migrate_integration(hass, config) + store = await async_get_registry(hass) domain_config = BatteryNotesDomainConfig( - user_library=config.get(DOMAIN, {}).get(CONF_USER_LIBRARY, ""), store=store, ) - global _yaml_domain_config - _yaml_domain_config = config.get(DOMAIN) - if _yaml_domain_config: - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={CONF_SOURCE: SOURCE_IMPORT}, - data={ - CONF_SHOW_ALL_DEVICES: _yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), - CONF_HIDE_BATTERY: _yaml_domain_config[0].get(CONF_HIDE_BATTERY, False), - CONF_ROUND_BATTERY: _yaml_domain_config[0].get(CONF_ROUND_BATTERY, False), - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: _yaml_domain_config[0].get( - CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD - ), - CONF_BATTERY_INCREASE_THRESHOLD: _yaml_domain_config[0].get( - CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD - ), - CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: _yaml_domain_config[0].get(CONF_ENABLE_AUTODISCOVERY, True), - CONF_ENABLE_REPLACED: _yaml_domain_config[0].get(CONF_ENABLE_REPLACED, True), - CONF_USER_LIBRARY: _yaml_domain_config[0].get(CONF_USER_LIBRARY, ""), - }, - } - ) - ) - hass.data[MY_KEY] = domain_config library_updater = LibraryUpdater(hass) @@ -218,80 +196,46 @@ async def async_remove_entry( if subentry not in config_entry.subentries: await async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) -async def async_migrate_entry( - hass: HomeAssistant, config_entry: BatteryNotesConfigEntry -): - """Migrate old config.""" - - if config_entry.version == 1: - # Version 1 had a single config for qty & type, split them - _LOGGER.debug("Migrating config entry from version %s", config_entry.version) +async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> None: + """Migrate integration entry structure.""" - matches = re.search( - r"^(\d+)(?=x)(?:x\s)(\w+$)|([\s\S]+)", config_entry.data[CONF_BATTERY_TYPE] - ) - if matches: - qty = matches.group(1) if matches.group(1) is not None else "1" - type = ( - matches.group(2) if matches.group(2) is not None else matches.group(3) - ) - else: - qty = 1 - type = config_entry.data[CONF_BATTERY_TYPE] + migrate_base_entry: ConfigEntry | None = None - new_data = {**config_entry.data} - new_data[CONF_BATTERY_TYPE] = type - new_data[CONF_BATTERY_QUANTITY] = qty + entries = hass.config_entries.async_entries(DOMAIN) + if not any(entry.version < 3 for entry in entries): + return - hass.config_entries.async_update_entry( - config_entry, version=2, title=config_entry.title, data=new_data - ) + for entry in entries: + if entry.version == 3 and entry.unique_id == DOMAIN: + # We have a V3 entry, so we can use this as the base + migrate_base_entry = entry + break - _LOGGER.info( - "Entry %s successfully migrated to version %s.", - config_entry.entry_id, - 2, + for entry in entries: + subentry = ConfigSubentry( + data=entry.data, + subentry_type="battery_note", + title=entry.title, + unique_id=entry.unique_id, ) - if config_entry.version < 3: - # Get the current config entries, see if one is at V3 and hold onto it as the base - global _migrate_base_entry - - if not _migrate_base_entry: - _LOGGER.debug("No base entry, looking for existing V3 entries") - - existing_entries = hass.config_entries.async_entries(DOMAIN) - for entry in existing_entries: - if entry.version == 3 and entry.unique_id == DOMAIN: - # We have a V3 entry, so we can use this as the base - _LOGGER.debug( - "Found existing V3 config entry %s, using it as the base for migration", - entry.entry_id, - ) - _migrate_base_entry = entry - break - # If no V3 then create one and hold onto it as the base - if not _migrate_base_entry: - _LOGGER.debug( - "No existing V3 config entry found, creating a new one for migration" - ) - - global _yaml_domain_config - if _yaml_domain_config: + if not migrate_base_entry: + yaml_domain_config = config.get(DOMAIN) + if yaml_domain_config: options={ - CONF_SHOW_ALL_DEVICES: _yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), - CONF_HIDE_BATTERY: _yaml_domain_config[0].get(CONF_HIDE_BATTERY, False), - CONF_ROUND_BATTERY: _yaml_domain_config[0].get(CONF_ROUND_BATTERY, False), - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: _yaml_domain_config[0].get( + CONF_SHOW_ALL_DEVICES: yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), + CONF_HIDE_BATTERY: yaml_domain_config[0].get(CONF_HIDE_BATTERY, False), + CONF_ROUND_BATTERY: yaml_domain_config[0].get(CONF_ROUND_BATTERY, False), + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: yaml_domain_config[0].get( CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD ), - CONF_BATTERY_INCREASE_THRESHOLD: _yaml_domain_config[0].get( + CONF_BATTERY_INCREASE_THRESHOLD: yaml_domain_config[0].get( CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD ), CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: _yaml_domain_config[0].get(CONF_ENABLE_AUTODISCOVERY, True), - CONF_ENABLE_REPLACED: _yaml_domain_config[0].get(CONF_ENABLE_REPLACED, True), - CONF_USER_LIBRARY: _yaml_domain_config[0].get(CONF_USER_LIBRARY, ""), + CONF_ENABLE_AUTODISCOVERY: yaml_domain_config[0].get(CONF_ENABLE_AUTODISCOVERY, True), + CONF_ENABLE_REPLACED: yaml_domain_config[0].get(CONF_ENABLE_REPLACED, True), + CONF_USER_LIBRARY: yaml_domain_config[0].get(CONF_USER_LIBRARY, ""), }, } else: @@ -308,32 +252,87 @@ async def async_migrate_entry( }, } - # Convert the first entry to the base entry then immediately add the subentry hass.config_entries.async_update_entry( - config_entry, version=3, title=INTEGRATION_NAME, data={}, options=options + entry, + version=3, + title=INTEGRATION_NAME, + data={}, + options=options, + unique_id=DOMAIN, ) - _migrate_base_entry = config_entry + async_create_issue( + hass, + DOMAIN, + ISSUE_DEPRECATED_YAML, + is_fixable=False, + issue_domain=DOMAIN, + severity=IssueSeverity.WARNING, + translation_key=ISSUE_DEPRECATED_YAML, + translation_placeholders={ + "domain": DOMAIN, + "integration_title": INTEGRATION_NAME, + }, + ) - assert _migrate_base_entry is not None, "Base entry should not be None" + migrate_base_entry = entry - # Update the base entry with the new subentry - subentry = ConfigSubentry(subentry_type="battery_note", data=config_entry.data, title=config_entry.title, unique_id=config_entry.unique_id) - hass.config_entries.async_add_subentry(_migrate_base_entry, subentry) + hass.config_entries.async_add_subentry(migrate_base_entry, subentry) - source_device_id = config_entry.data.get(CONF_DEVICE_ID, None) + source_device_id = subentry.data.get(CONF_DEVICE_ID, None) + source_entity_id = subentry.data.get("source_entity_id", None) + if source_entity_id: + source_device_id = async_entity_id_to_device_id( + hass, source_entity_id + ) if source_device_id: - helper_integration.async_remove_helper_config_entry_from_source_device(hass=hass, helper_config_entry_id=config_entry.entry_id, source_device_id=source_device_id) + helper_integration.async_remove_helper_config_entry_from_source_device(hass=hass, helper_config_entry_id=entry.entry_id, source_device_id=source_device_id) # Remove the old config entry - if config_entry.entry_id != _migrate_base_entry.entry_id: - hass.config_entries.async_remove(config_entry.entry_id) + if entry.entry_id != migrate_base_entry.entry_id: + await hass.config_entries.async_remove(entry.entry_id) _LOGGER.info( "Entry %s successfully migrated to subentry of %s.", + entry.entry_id, + migrate_base_entry.entry_id, + ) + + +async def async_migrate_entry( + hass: HomeAssistant, config_entry: BatteryNotesConfigEntry +): + """Migrate old config.""" + + if config_entry.version == 1: + # Version 1 had a single config for qty & type, split them + _LOGGER.debug("Migrating config entry from version %s", config_entry.version) + + matches = re.search( + r"^(\d+)(?=x)(?:x\s)(\w+$)|([\s\S]+)", config_entry.data[CONF_BATTERY_TYPE] + ) + if matches: + qty = matches.group(1) if matches.group(1) is not None else "1" + type = ( + matches.group(2) if matches.group(2) is not None else matches.group(3) + ) + else: + qty = 1 + type = config_entry.data[CONF_BATTERY_TYPE] + + new_data = {**config_entry.data} + new_data[CONF_BATTERY_TYPE] = type + new_data[CONF_BATTERY_QUANTITY] = qty + + hass.config_entries.async_update_entry( + config_entry, version=2, title=config_entry.title, data=new_data + ) + + _LOGGER.info( + "Entry %s successfully migrated to version %s.", config_entry.entry_id, - _migrate_base_entry.entry_id, + 2, ) return True diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 33a40d152..3514cb7dd 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -225,30 +225,6 @@ async def async_step_integration_discovery( return await self.async_step_device(discovery_info) - # triggered by async_setup() from __init__.py - async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult: - """Handle import of config entry from configuration.yaml.""" - - config_flow_result: ConfigFlowResult = await self.async_step_user( - import_data - ) - - async_create_issue( - self.hass, - DOMAIN, - ISSUE_DEPRECATED_YAML, - is_fixable=False, - issue_domain=DOMAIN, - severity=IssueSeverity.WARNING, - translation_key=ISSUE_DEPRECATED_YAML, - translation_placeholders={ - "domain": DOMAIN, - "integration_title": INTEGRATION_NAME, - }, - ) - - return config_flow_result - async def async_step_user( self, user_input: dict | None = None, @@ -260,23 +236,19 @@ async def async_step_user( return self.async_abort(reason="already_configured") if user_input is not None: - if len(user_input) == 0: - # Init defaults - options = { - CONF_SHOW_ALL_DEVICES: False, - CONF_HIDE_BATTERY: False, - CONF_ROUND_BATTERY: False, - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, - CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, - CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: True, - CONF_ENABLE_REPLACED: True, - CONF_USER_LIBRARY: "", - } + # Init defaults + options = { + CONF_SHOW_ALL_DEVICES: False, + CONF_HIDE_BATTERY: False, + CONF_ROUND_BATTERY: False, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, + CONF_ADVANCED_SETTINGS: { + CONF_ENABLE_AUTODISCOVERY: True, + CONF_ENABLE_REPLACED: True, + CONF_USER_LIBRARY: "", } - else: - # From import - options = user_input + } return self.async_create_entry( title=INTEGRATION_NAME, From fafb0d758ef41820dfa65e50100ffa005f2a9786 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 13:00:25 +0000 Subject: [PATCH 082/235] Refactor migration and update listener functions for clarity and consistency --- custom_components/battery_notes/__init__.py | 40 ++++++++++--------- .../battery_notes/config_flow.py | 2 - 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 10a158d81..faf08708c 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -168,7 +168,7 @@ async def async_setup_entry( await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) - config_entry.async_on_unload(config_entry.add_update_listener(update_listener)) + config_entry.async_on_unload(config_entry.add_update_listener(_async_update_listener)) if domain_config.enable_autodiscovery: discovery_manager = DiscoveryManager(hass, domain_config) @@ -201,6 +201,22 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> migrate_base_entry: ConfigEntry | None = None + yaml_domain_config = config.get(DOMAIN) + if yaml_domain_config is not None: + async_create_issue( + hass, + DOMAIN, + ISSUE_DEPRECATED_YAML, + is_fixable=False, + issue_domain=DOMAIN, + severity=IssueSeverity.WARNING, + translation_key=ISSUE_DEPRECATED_YAML, + translation_placeholders={ + "domain": DOMAIN, + "integration_title": INTEGRATION_NAME, + }, + ) + entries = hass.config_entries.async_entries(DOMAIN) if not any(entry.version < 3 for entry in entries): return @@ -212,6 +228,9 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> break for entry in entries: + if entry.version >= 3: + continue + subentry = ConfigSubentry( data=entry.data, subentry_type="battery_note", @@ -220,7 +239,6 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> ) if not migrate_base_entry: - yaml_domain_config = config.get(DOMAIN) if yaml_domain_config: options={ CONF_SHOW_ALL_DEVICES: yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), @@ -261,20 +279,6 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> unique_id=DOMAIN, ) - async_create_issue( - hass, - DOMAIN, - ISSUE_DEPRECATED_YAML, - is_fixable=False, - issue_domain=DOMAIN, - severity=IssueSeverity.WARNING, - translation_key=ISSUE_DEPRECATED_YAML, - translation_placeholders={ - "domain": DOMAIN, - "integration_title": INTEGRATION_NAME, - }, - ) - migrate_base_entry = entry hass.config_entries.async_add_subentry(migrate_base_entry, subentry) @@ -338,7 +342,7 @@ async def async_migrate_entry( return True -async def update_listener( +async def _async_update_listener( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry ) -> None: """Update the device and related entities. @@ -349,7 +353,7 @@ async def update_listener( """ for subentry in config_entry.runtime_data.loaded_subentries.values(): - if subentry not in config_entry.subentries: + if subentry.subentry_id not in config_entry.subentries: await async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) # Update the config entry with the new sub entries diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 3514cb7dd..75ff969e7 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -27,7 +27,6 @@ from homeassistant.core import callback, split_entity_id from homeassistant.data_entry_flow import section from homeassistant.helpers import selector -from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.typing import DiscoveryInfoType from .common import get_device_model_id @@ -54,7 +53,6 @@ DEFAULT_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD, DOMAIN, - ISSUE_DEPRECATED_YAML, ) from .const import NAME as INTEGRATION_NAME from .coordinator import MY_KEY From 704a06821ab9feba9a33edf15e1eb29fa44ccde1 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 13:04:17 +0000 Subject: [PATCH 083/235] Refactor subentry removal functions for consistency and clarity --- custom_components/battery_notes/__init__.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index faf08708c..9ac9eaf46 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -194,7 +194,7 @@ async def async_remove_entry( for subentry in config_entry.subentries.values(): if subentry not in config_entry.subentries: - await async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) + await _async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> None: """Migrate integration entry structure.""" @@ -354,7 +354,7 @@ async def _async_update_listener( for subentry in config_entry.runtime_data.loaded_subentries.values(): if subentry.subentry_id not in config_entry.subentries: - await async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) + await _async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) # Update the config entry with the new sub entries config_entry.runtime_data.loaded_subentries = config_entry.subentries.copy() @@ -362,7 +362,7 @@ async def _async_update_listener( await hass.config_entries.async_reload(config_entry.entry_id) -async def async_remove_subentry( +async def _async_remove_subentry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, subentry: ConfigSubentry, @@ -401,10 +401,3 @@ async def async_remove_subentry( _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) config_entry.runtime_data.subentry_coordinators.pop(subentry, None) - -@callback -async def async_update_options( - hass: HomeAssistant, entry: BatteryNotesConfigEntry -) -> None: - """Update options.""" - await hass.config_entries.async_reload(entry.entry_id) From 205e5b1a10ca95a2ea4cf4eb28dc9d5b9a8b8e9b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 13:12:18 +0000 Subject: [PATCH 084/235] Refactor integration migration code for improved readability and consistency --- custom_components/battery_notes/__init__.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 9ac9eaf46..89a475dbe 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,21 +8,19 @@ import logging import re -from typing import Any import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion from homeassistant.config_entries import ConfigEntry, ConfigSubentry from homeassistant.const import CONF_DEVICE_ID from homeassistant.const import __version__ as HA_VERSION # noqa: N812 -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv from homeassistant.helpers import entity_registry as er from homeassistant.helpers import helper_integration from homeassistant.helpers import issue_registry as ir from homeassistant.helpers.device import ( async_entity_id_to_device_id, - async_remove_stale_devices_links_keep_entity_device, ) from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.typing import ConfigType @@ -241,19 +239,19 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if not migrate_base_entry: if yaml_domain_config: options={ - CONF_SHOW_ALL_DEVICES: yaml_domain_config[0].get(CONF_SHOW_ALL_DEVICES, False), - CONF_HIDE_BATTERY: yaml_domain_config[0].get(CONF_HIDE_BATTERY, False), - CONF_ROUND_BATTERY: yaml_domain_config[0].get(CONF_ROUND_BATTERY, False), - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: yaml_domain_config[0].get( + CONF_SHOW_ALL_DEVICES: yaml_domain_config.get(CONF_SHOW_ALL_DEVICES, False), + CONF_HIDE_BATTERY: yaml_domain_config.get(CONF_HIDE_BATTERY, False), + CONF_ROUND_BATTERY: yaml_domain_config.get(CONF_ROUND_BATTERY, False), + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: yaml_domain_config.get( CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD ), - CONF_BATTERY_INCREASE_THRESHOLD: yaml_domain_config[0].get( + CONF_BATTERY_INCREASE_THRESHOLD: yaml_domain_config.get( CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD ), CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: yaml_domain_config[0].get(CONF_ENABLE_AUTODISCOVERY, True), - CONF_ENABLE_REPLACED: yaml_domain_config[0].get(CONF_ENABLE_REPLACED, True), - CONF_USER_LIBRARY: yaml_domain_config[0].get(CONF_USER_LIBRARY, ""), + CONF_ENABLE_AUTODISCOVERY: yaml_domain_config.get(CONF_ENABLE_AUTODISCOVERY, True), + CONF_ENABLE_REPLACED: yaml_domain_config.get(CONF_ENABLE_REPLACED, True), + CONF_USER_LIBRARY: yaml_domain_config.get(CONF_USER_LIBRARY, ""), }, } else: From 3cf6e6d3759aab41521680c1711bc22081071934 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 13:22:29 +0000 Subject: [PATCH 085/235] MyPy --- custom_components/battery_notes/__init__.py | 25 +++++++++++-------- .../battery_notes/binary_sensor.py | 2 +- custom_components/battery_notes/repairs.py | 4 +-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 89a475dbe..e0f0f40c4 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -369,7 +369,9 @@ async def _async_remove_subentry( """Remove a sub entry.""" _LOGGER.debug("Removing sub entry %s from config entry %s", subentry.subentry_id, config_entry.entry_id) + assert config_entry.runtime_data.subentry_coordinators coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) + assert coordinator # Remove any issues raised ir.async_delete_issue(hass, DOMAIN, f"missing_device_{subentry.subentry_id}") @@ -387,15 +389,16 @@ async def _async_remove_subentry( # Unhide the battery entity_registry = er.async_get(hass) - if ( - wrapped_battery_entity_entry := entity_registry.async_get( - coordinator.wrapped_battery.entity_id - ) - ): - if wrapped_battery_entity_entry.hidden_by == er.RegistryEntryHider.INTEGRATION: - entity_registry.async_update_entity( - coordinator.wrapped_battery.entity_id, hidden_by=None + if coordinator.wrapped_battery: + if ( + wrapped_battery_entity_entry := entity_registry.async_get( + coordinator.wrapped_battery.entity_id ) - _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) - - config_entry.runtime_data.subentry_coordinators.pop(subentry, None) + ): + if wrapped_battery_entity_entry.hidden_by == er.RegistryEntryHider.INTEGRATION: + entity_registry.async_update_entity( + coordinator.wrapped_battery.entity_id, hidden_by=None + ) + _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) + + config_entry.runtime_data.subentry_coordinators.pop(subentry.subentry_id) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index f5615e608..2426b9cd9 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -151,7 +151,7 @@ async def async_setup_entry( entity_type="binary_sensor", ) - entities = [] + entities: list[BatteryNotesBatteryLowTemplateSensor | BatteryNotesBatteryLowSensor | BatteryNotesBatteryBinaryLowSensor] = [] # entities = [ # BatteryNotesFilteredSensor( diff --git a/custom_components/battery_notes/repairs.py b/custom_components/battery_notes/repairs.py index a53c513bd..7c72b7a35 100644 --- a/custom_components/battery_notes/repairs.py +++ b/custom_components/battery_notes/repairs.py @@ -36,8 +36,8 @@ async def async_step_confirm( ) -> data_entry_flow.FlowResult: """Handle the confirm step of a fix flow.""" if user_input is not None: - entry = self.hass.config_entries.async_get_entry(self.entry_id) - self.hass.config_entries.async_remove_subentry(entry, self.subentry_id) + if (entry:= self.hass.config_entries.async_get_entry(self.entry_id)): + self.hass.config_entries.async_remove_subentry(entry, self.subentry_id) return self.async_create_entry(data={}) From 486e8addf3c584540add4809e065217c114c8a04 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 13:23:08 +0000 Subject: [PATCH 086/235] Tidy --- custom_components/battery_notes/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index e0f0f40c4..4bf90e7c6 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -387,9 +387,8 @@ async def _async_remove_subentry( store.async_delete_device(coordinator.device_id) # Unhide the battery - entity_registry = er.async_get(hass) - if coordinator.wrapped_battery: + entity_registry = er.async_get(hass) if ( wrapped_battery_entity_entry := entity_registry.async_get( coordinator.wrapped_battery.entity_id From 0a086ab46b2c9404766ab9f6e5f988a3b0369a47 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 13:59:03 +0000 Subject: [PATCH 087/235] Refactor subentry type references to use constant for consistency --- custom_components/battery_notes/__init__.py | 5 +++-- custom_components/battery_notes/binary_sensor.py | 3 ++- custom_components/battery_notes/button.py | 3 ++- custom_components/battery_notes/config_flow.py | 5 +++-- custom_components/battery_notes/const.py | 2 ++ custom_components/battery_notes/sensor.py | 3 ++- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 4bf90e7c6..8ba5d1915 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -43,6 +43,7 @@ ISSUE_DEPRECATED_YAML, MIN_HA_VERSION, PLATFORMS, + SUBENTRY_BATTERY_NOTE, ) from .const import NAME as INTEGRATION_NAME from .coordinator import ( @@ -145,7 +146,7 @@ async def async_setup_entry( config_entry.runtime_data.subentry_coordinators = {} for subentry in config_entry.subentries.values(): - if subentry.subentry_type == "battery_note": + if subentry.subentry_type == SUBENTRY_BATTERY_NOTE: coordinator = BatteryNotesSubentryCoordinator(hass, config_entry, subentry) config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator @@ -231,7 +232,7 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> subentry = ConfigSubentry( data=entry.data, - subentry_type="battery_note", + subentry_type=SUBENTRY_BATTERY_NOTE, title=entry.title, unique_id=entry.unique_id, ) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 2426b9cd9..331ccbd96 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -70,6 +70,7 @@ ATTR_SOURCE_ENTITY_ID, CONF_SOURCE_ENTITY_ID, DOMAIN, + SUBENTRY_BATTERY_NOTE, ) from .coordinator import ( MY_KEY, @@ -124,7 +125,7 @@ async def async_setup_entry( """Initialize Battery Type config entry.""" for subentry in config_entry.subentries.values(): - if subentry.subentry_type != "battery_note": + if subentry.subentry_type != SUBENTRY_BATTERY_NOTE: continue assert config_entry.runtime_data.subentry_coordinators diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 1bb3c61ec..432ca148f 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -32,6 +32,7 @@ ATTR_SOURCE_ENTITY_ID, DOMAIN, EVENT_BATTERY_REPLACED, + SUBENTRY_BATTERY_NOTE, ) from .coordinator import BatteryNotesConfigEntry, BatteryNotesSubentryCoordinator from .entity import BatteryNotesEntity, BatteryNotesEntityDescription @@ -73,7 +74,7 @@ async def async_setup_entry( """Initialize Battery Type config entry.""" for subentry in config_entry.subentries.values(): - if subentry.subentry_type != "battery_note": + if subentry.subentry_type != SUBENTRY_BATTERY_NOTE: continue assert config_entry.runtime_data.subentry_coordinators diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 75ff969e7..b42b3d0f1 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -53,6 +53,7 @@ DEFAULT_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD, DOMAIN, + SUBENTRY_BATTERY_NOTE, ) from .const import NAME as INTEGRATION_NAME from .coordinator import MY_KEY @@ -169,7 +170,7 @@ def async_get_supported_subentry_types( ) -> dict[str, type[ConfigSubentryFlow]]: """Return subentries supported by this integration.""" return { - "battery_note": BatteryNotesSubentryFlowHandler, + SUBENTRY_BATTERY_NOTE: BatteryNotesSubentryFlowHandler, } async def async_step_integration_discovery( @@ -387,7 +388,7 @@ async def async_step_battery( config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] # Create a subentry - subentry = ConfigSubentry(subentry_type="battery_note", data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) + subentry = ConfigSubentry(subentry_type=SUBENTRY_BATTERY_NOTE, data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) self.hass.config_entries.async_add_subentry(config_entry, subentry) return self.async_abort(reason="created_sub_entry") diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index e7c66c0ee..5e81e9f60 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -113,3 +113,5 @@ Platform.BUTTON, Platform.SENSOR, ] + +SUBENTRY_BATTERY_NOTE = "battery_note" \ No newline at end of file diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 85a5506d8..8166d4bfb 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -65,6 +65,7 @@ CONF_ROUND_BATTERY, CONF_SOURCE_ENTITY_ID, DOMAIN, + SUBENTRY_BATTERY_NOTE, ) from .coordinator import ( MY_KEY, @@ -104,7 +105,7 @@ async def async_setup_entry( """Initialize Battery Type config entry.""" for subentry in config_entry.subentries.values(): - if subentry.subentry_type != "battery_note": + if subentry.subentry_type != SUBENTRY_BATTERY_NOTE: continue assert config_entry.runtime_data.subentry_coordinators From e90441720ee8740ef0a27c6d3cf8e192fb106364 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 14:26:16 +0000 Subject: [PATCH 088/235] Allow discovery ignore --- custom_components/battery_notes/config_flow.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index b42b3d0f1..79092e9ff 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -222,6 +222,8 @@ async def async_step_integration_discovery( "model_id": discovery_info[CONF_MODEL_ID], } + await self.async_set_unique_id(unique_id) + return await self.async_step_device(discovery_info) async def async_step_user( From 32d22ad3bda2464269ac854e5c8e13f0d5fb866b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 14:58:19 +0000 Subject: [PATCH 089/235] Add comprehensive AI coding instructions for Battery Notes integration --- .github/copilot-instructions.md | 140 ++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..b091f1530 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,140 @@ +# Battery Notes - AI Coding Instructions + +## Project Overview +Battery Notes is a Home Assistant custom integration that tracks battery information for IoT devices. It uses a **sub-entry architecture** where a single config entry can manage multiple battery devices via ConfigSubentry objects. + +## Architecture & Core Components + +### Config Entry Structure (Critical) +- **Main Config Entry**: Domain-level configuration (`BatteryNotesConfigEntry`) +- **Sub-entries**: Individual device configurations (`ConfigSubentry`) stored in `config_entry.runtime_data.subentries` +- **Coordinators**: Each sub-entry has its own `BatteryNotesSubentryCoordinator` in `config_entry.runtime_data.subentry_coordinators[subentry_id]` + +**Key Pattern**: Always iterate through `subentry_coordinators.values()` not the main coordinator when looking for devices. + +### Entity Inheritance Structure +- `BatteryNotesEntity` (base class in `entity.py`) - handles device association and common setup +- Sensor classes inherit from both `BatteryNotesEntity` and HA sensor classes +- Example: `class BatteryNotesTypeSensor(BatteryNotesEntity, RestoreSensor)` + +### Device Discovery & Library +- `library/library.json`: 10K+ device definitions with battery types +- `discovery.py`: Auto-discovers devices and creates config entries +- Device matching: `manufacturer` + `model` (+ optional `hw_version`) + +## Key File Responsibilities + +### Core Files +- `__init__.py`: Config entry setup, sub-entry management, platform loading +- `coordinator.py`: Data coordination, battery level tracking, event firing +- `config_flow.py`: UI configuration flows for manual device addition +- `services.py`: Battery replacement service handlers +- `entity.py`: Base entity class with device association logic + +### Platform Files +- `sensor.py`: Battery type, battery+, and last replaced sensors +- `binary_sensor.py`: Battery low binary sensors +- `button.py`: Battery replaced action buttons + +### Supporting Files +- `library.py`: Device library management and updates +- `discovery.py`: Automatic device discovery from library +- `const.py`: All constants, service schemas, event names +- `store.py`: Persistent storage for user data + +## Development Workflow + +### Local Development +```bash +# Start HA development server on port 8123 +./scripts/develop + +# Lint code +./scripts/lint + +# Check types (if mypy installed) +mypy custom_components/battery_notes/ --check-untyped-defs +``` + +### File Structure Conventions +- Put constants in `const.py` with proper categorization +- Use dataclasses for configuration objects +- Service schemas defined in `const.py`, handlers in `services.py` +- All entities extend `BatteryNotesEntity` base class + +## Critical Patterns + +### Sub-entry Iteration Pattern +```python +# CORRECT - iterate through sub-entry coordinators +for config_entry in hass.config_entries.async_loaded_entries(DOMAIN): + if not config_entry.runtime_data.subentry_coordinators: + continue + for coordinator in config_entry.runtime_data.subentry_coordinators.values(): + if coordinator.device_id == target_device_id: + # Process device +``` + +### Entity Registration Pattern +```python +# Use unique_id from coordinator + description suffix +self._attr_unique_id = f"{coordinator.device_id}_{description.unique_id_suffix}" + +# Handle entity naming based on device association +if coordinator.source_entity_id and not coordinator.device_id: + self._attr_translation_placeholders = {"device_name": coordinator.device_name + " "} +``` + +### Service Implementation Pattern +```python +# Always validate device exists before processing +device_found = False +for coordinator in subentry_coordinators.values(): + if coordinator.device_id == device_id: + device_found = True + # Process service call + break + +if not device_found: + _LOGGER.error("Device %s not configured in Battery Notes", device_id) + return None +``` + +## Testing & Validation + +### Type Checking +- Project uses mypy with `--check-untyped-defs` +- All major classes use type hints +- ConfigEntry typing: `BatteryNotesConfigEntry = ConfigEntry[BatteryNotesData]` + +### Linting +- Uses `ruff` for code formatting and linting +- Config in `pyproject.toml` +- Run `./scripts/lint` before commits + +## Integration Points + +### Home Assistant APIs +- Device Registry: Link entities to HA devices +- Entity Registry: Manage entity lifecycle +- Event Bus: Fire battery events (`EVENT_BATTERY_THRESHOLD`, `EVENT_BATTERY_REPLACED`) +- Config Flow: Handle UI configuration + +### External Dependencies +- Library updates from `https://battery-notes-data.codechimp.org/library.json` +- Version checking with `awesomeversion` +- Data validation with `voluptuous` + +## Common Tasks + +### Adding New Entity Types +1. Create entity description in appropriate platform file +2. Extend `BatteryNotesEntity` base class +3. Add to platform's `async_setup_entry` function +4. Register constants in `const.py` + +### Adding New Services +1. Define schema in `const.py` +2. Implement handler in `services.py` using sub-entry iteration pattern +3. Register in `__init__.py` `async_setup_entry` +4. Add service definition to `services.yaml` From fbc21f957d5b96552ded6243d2eb6c21524d4f04 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 13 Aug 2025 16:22:01 +0000 Subject: [PATCH 090/235] Fix subentry removal logic in Battery Notes integration --- custom_components/battery_notes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 8ba5d1915..34b8c3fd3 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -192,7 +192,7 @@ async def async_remove_entry( """Battery Notes integration removed.""" for subentry in config_entry.subentries.values(): - if subentry not in config_entry.subentries: + if subentry.subentry_id not in config_entry.subentries: await _async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> None: From 3dd93b6dbe7439d6c73729beb0e871a7e02e3265 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 14 Aug 2025 10:10:03 +0000 Subject: [PATCH 091/235] Subentry check for orphaned battery notes --- .../battery_notes/binary_sensor.py | 7 ++++++ custom_components/battery_notes/button.py | 7 ++++++ .../battery_notes/coordinator.py | 25 ++++++++++--------- custom_components/battery_notes/sensor.py | 7 ++++++ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 331ccbd96..c67297c49 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -134,6 +134,13 @@ async def async_setup_entry( ) assert coordinator + if coordinator.orphaned: + _LOGGER.debug( + "Skipping binary_sensor creation for orphaned subentry: %s", + subentry.title, + ) + continue + # battery_filtered_entity_description = BatteryNotesBinarySensorEntityDescription( # unique_id_suffix="_battery_outliers_filtered", # key="_battery_outliers_filtered", diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 432ca148f..43a00990b 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -83,6 +83,13 @@ async def async_setup_entry( ) assert coordinator + if coordinator.orphaned: + _LOGGER.debug( + "Skipping button creation for orphaned entry: %s", + subentry.title, + ) + continue + description = BatteryNotesButtonEntityDescription( unique_id_suffix="_battery_replaced_button", key="battery_replaced", diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index c9bf76acb..6b196421c 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -101,6 +101,7 @@ class BatteryNotesSubentryCoordinator(DataUpdateCoordinator[None]): battery_low_template: str | None wrapped_battery: RegistryEntry | None = None wrapped_battery_low: RegistryEntry | None = None + orphaned: bool = False _current_battery_level: str | None = None _previous_battery_low: bool | None = None _previous_battery_level: str | None = None @@ -128,7 +129,9 @@ def __init__( self.device_id = self.subentry.data.get(CONF_DEVICE_ID, None) self.source_entity_id = self.subentry.data.get(CONF_SOURCE_ENTITY_ID, None) - self._link_device() + if not self._link_device(): + self.orphaned = True + return assert(self.device_name) @@ -359,18 +362,16 @@ def source_entity_name(self): device_registry = dr.async_get(self.hass) registry_entry = entity_registry.async_get(self.source_entity_id) device_entry = device_registry.async_get(self.device_id) if self.device_id else None - assert(registry_entry) - - if registry_entry.name is None and registry_entry.has_entity_name and device_entry: - self._source_entity_name = ( - registry_entry.name or registry_entry.original_name or device_entry.name_by_user or device_entry.name or self.source_entity_id - ) - else: - self._source_entity_name = ( - registry_entry.name or registry_entry.original_name or self.source_entity_id - ) - assert(self._source_entity_name) + if registry_entry: + if registry_entry and registry_entry.name is None and registry_entry.has_entity_name and device_entry: + self._source_entity_name = ( + registry_entry.name or registry_entry.original_name or device_entry.name_by_user or device_entry.name or self.source_entity_id + ) + else: + self._source_entity_name = ( + registry_entry.name or registry_entry.original_name or self.source_entity_id + ) return self._source_entity_name diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 8166d4bfb..44edf2345 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -114,6 +114,13 @@ async def async_setup_entry( ) assert coordinator + if coordinator.orphaned: + _LOGGER.debug( + "Skipping sensor creation for orphaned subentry: %s", + subentry.title, + ) + continue + type_sensor_entity_description = BatteryNotesSensorEntityDescription( unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix key="battery_type", From 5e9d8ebb39ad19f72dcddedbb2c454cd0b22b86a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 14 Aug 2025 10:42:22 +0000 Subject: [PATCH 092/235] Refactor orphaned property to is_orphaned in coordinator and update related checks in binary_sensor, button, and sensor modules --- custom_components/battery_notes/binary_sensor.py | 2 +- custom_components/battery_notes/button.py | 2 +- custom_components/battery_notes/coordinator.py | 12 ++---------- custom_components/battery_notes/sensor.py | 2 +- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index c67297c49..04ed58de9 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -134,7 +134,7 @@ async def async_setup_entry( ) assert coordinator - if coordinator.orphaned: + if coordinator.is_orphaned: _LOGGER.debug( "Skipping binary_sensor creation for orphaned subentry: %s", subentry.title, diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 43a00990b..c7b7b6e7c 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -83,7 +83,7 @@ async def async_setup_entry( ) assert coordinator - if coordinator.orphaned: + if coordinator.is_orphaned: _LOGGER.debug( "Skipping button creation for orphaned entry: %s", subentry.title, diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 6b196421c..cf45076a2 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -101,7 +101,7 @@ class BatteryNotesSubentryCoordinator(DataUpdateCoordinator[None]): battery_low_template: str | None wrapped_battery: RegistryEntry | None = None wrapped_battery_low: RegistryEntry | None = None - orphaned: bool = False + is_orphaned: bool = False _current_battery_level: str | None = None _previous_battery_low: bool | None = None _previous_battery_level: str | None = None @@ -130,7 +130,7 @@ def __init__( self.source_entity_id = self.subentry.data.get(CONF_SOURCE_ENTITY_ID, None) if not self._link_device(): - self.orphaned = True + self.is_orphaned = True return assert(self.device_name) @@ -338,14 +338,6 @@ def unique_id(self) -> str: """Return a unique ID for the coordinator.""" return f"{self.config_entry.entry_id}_{self.subentry.subentry_id}" - @property - def fake_device(self) -> bool: - """Return if an actual device registry entry.""" - if self.subentry.data.get(CONF_SOURCE_ENTITY_ID, None): - if self.subentry.data.get(CONF_DEVICE_ID, None) is None: - return True - return False - @property def filter_outliers(self) -> bool: """Return if outlier filtering is enabled.""" diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 44edf2345..0eb8a9a5f 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -114,7 +114,7 @@ async def async_setup_entry( ) assert coordinator - if coordinator.orphaned: + if coordinator.is_orphaned: _LOGGER.debug( "Skipping sensor creation for orphaned subentry: %s", subentry.title, From eb73a1cb9d9c9c086fbbd0d1263ff49a2b12234b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 14 Aug 2025 10:48:28 +0000 Subject: [PATCH 093/235] Rename _link_device to _link_to_source for clarity and update related logic in BatteryNotesSubentryCoordinator --- custom_components/battery_notes/coordinator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index cf45076a2..582c37afb 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -129,7 +129,7 @@ def __init__( self.device_id = self.subentry.data.get(CONF_DEVICE_ID, None) self.source_entity_id = self.subentry.data.get(CONF_SOURCE_ENTITY_ID, None) - if not self._link_device(): + if not self._link_to_source(): self.is_orphaned = True return @@ -202,8 +202,8 @@ def __init__( ) self.last_reported = last_reported - def _link_device(self) -> bool: - """Get the device name.""" + def _link_to_source(self) -> bool: + """Get the source device or entity, determine name and associate our wrapped battery if available.""" device_registry = dr.async_get(self.hass) entity_registry = er.async_get(self.hass) From eb102ee9f0f4d24abb492de7dd9f4428e75e4d15 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 16 Aug 2025 07:48:01 +0000 Subject: [PATCH 094/235] Delay discovery until HA fully started --- custom_components/battery_notes/__init__.py | 36 +++++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 34b8c3fd3..1c46c2184 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -12,9 +12,12 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion from homeassistant.config_entries import ConfigEntry, ConfigSubentry -from homeassistant.const import CONF_DEVICE_ID +from homeassistant.const import ( + CONF_DEVICE_ID, + EVENT_HOMEASSISTANT_STARTED, +) from homeassistant.const import __version__ as HA_VERSION # noqa: N812 -from homeassistant.core import HomeAssistant +from homeassistant.core import Event, HomeAssistant, callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers import entity_registry as er from homeassistant.helpers import helper_integration @@ -110,10 +113,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: hass.data[MY_KEY] = domain_config - library_updater = LibraryUpdater(hass) - await library_updater.copy_schema() - await library_updater.get_library_updates(startup=True) - # Register custom services async_setup_services(hass) @@ -138,6 +137,10 @@ async def async_setup_entry( domain_config.enable_replaced = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_ENABLE_REPLACED] domain_config.user_library = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_USER_LIBRARY] + library_updater = LibraryUpdater(hass) + await library_updater.copy_schema() + await library_updater.get_library_updates(startup=True) + config_entry.runtime_data = BatteryNotesData( domain_config=domain_config, store=domain_config.store, @@ -169,9 +172,28 @@ async def async_setup_entry( config_entry.async_on_unload(config_entry.add_update_listener(_async_update_listener)) - if domain_config.enable_autodiscovery: + async def _discovery(_: Event) -> None: discovery_manager = DiscoveryManager(hass, domain_config) await discovery_manager.start_discovery() + + @callback + def _unsubscribe_discovery() -> None: + """Unsubscribe the discovery listener.""" + if discovery_unsub: + try: + discovery_unsub() + except ValueError: + _LOGGER.debug( + "Failed to unsubscribe discovery listener, " + "it might have already been removed or never registered.", + ) + + # Wait until Home Assistant is started, before doing discovery + if domain_config.enable_autodiscovery: + discovery_unsub = hass.bus.async_listen_once( + EVENT_HOMEASSISTANT_STARTED, _discovery + ) + config_entry.async_on_unload(_unsubscribe_discovery) else: _LOGGER.debug("Auto discovery disabled") From cd4c34ea2009f97f0b6fb3bb5b745775ff7405ad Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 16 Aug 2025 07:58:22 +0000 Subject: [PATCH 095/235] Moe library update to post HA start --- custom_components/battery_notes/__init__.py | 41 +++++++++++---------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 1c46c2184..e5acfcd3a 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -137,10 +137,6 @@ async def async_setup_entry( domain_config.enable_replaced = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_ENABLE_REPLACED] domain_config.user_library = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_USER_LIBRARY] - library_updater = LibraryUpdater(hass) - await library_updater.copy_schema() - await library_updater.get_library_updates(startup=True) - config_entry.runtime_data = BatteryNotesData( domain_config=domain_config, store=domain_config.store, @@ -172,30 +168,35 @@ async def async_setup_entry( config_entry.async_on_unload(config_entry.add_update_listener(_async_update_listener)) - async def _discovery(_: Event) -> None: - discovery_manager = DiscoveryManager(hass, domain_config) - await discovery_manager.start_discovery() + async def _after_start(_: Event) -> None: + """After Home Assistant has started, update library and do discovery.""" + library_updater = LibraryUpdater(hass) + await library_updater.copy_schema() + await library_updater.get_library_updates(startup=True) + + if domain_config.enable_autodiscovery: + discovery_manager = DiscoveryManager(hass, domain_config) + await discovery_manager.start_discovery() + else: + _LOGGER.debug("Auto discovery disabled") @callback - def _unsubscribe_discovery() -> None: - """Unsubscribe the discovery listener.""" - if discovery_unsub: + def _unsubscribe_ha_started() -> None: + """Unsubscribe the started listener.""" + if after_start_unsub: try: - discovery_unsub() + after_start_unsub() except ValueError: _LOGGER.debug( - "Failed to unsubscribe discovery listener, " + "Failed to unsubscribe started listener, " "it might have already been removed or never registered.", ) - # Wait until Home Assistant is started, before doing discovery - if domain_config.enable_autodiscovery: - discovery_unsub = hass.bus.async_listen_once( - EVENT_HOMEASSISTANT_STARTED, _discovery - ) - config_entry.async_on_unload(_unsubscribe_discovery) - else: - _LOGGER.debug("Auto discovery disabled") + # Wait until Home Assistant is started, before doing library and discovery + after_start_unsub = hass.bus.async_listen_once( + EVENT_HOMEASSISTANT_STARTED, _after_start + ) + config_entry.async_on_unload(_unsubscribe_ha_started) return True From 1200d4134c8db0a5234b62b42436c58f4fce5e14 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 13:56:47 +0000 Subject: [PATCH 096/235] Remove obsolete code --- custom_components/battery_notes/__init__.py | 12 ------ .../battery_notes/binary_sensor.py | 40 ------------------- .../battery_notes/coordinator.py | 5 --- custom_components/battery_notes/entity.py | 12 +----- 4 files changed, 1 insertion(+), 68 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index e5acfcd3a..6da831dbb 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -152,18 +152,6 @@ async def async_setup_entry( assert subentry.unique_id - # Create a device, only needed if we want entities that are not added to the source device - # device_registry = dr.async_get(hass) - # device_registry.async_get_or_create( - # config_entry_id=config_entry.entry_id, - # config_subentry_id= subentry.subentry_id, - # identifiers={(DOMAIN, coordinator.unique_id)}, - # entry_type=DeviceEntryType.SERVICE, - # manufacturer=MANUFACTURER, - # name=subentry.title - # ) - - await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) config_entry.async_on_unload(config_entry.add_update_listener(_async_update_listener)) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 04ed58de9..f7a44f476 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -141,15 +141,6 @@ async def async_setup_entry( ) continue - # battery_filtered_entity_description = BatteryNotesBinarySensorEntityDescription( - # unique_id_suffix="_battery_outliers_filtered", - # key="_battery_outliers_filtered", - # translation_key="battery_outliers_filtered", - # entity_category=EntityCategory.DIAGNOSTIC, - # entity_type="binary_sensor", - # attach_to_source_device=False, - # ) - battery_low_entity_description = BatteryNotesBinarySensorEntityDescription( unique_id_suffix="_battery_low", key="_battery_plus_low", @@ -161,15 +152,6 @@ async def async_setup_entry( entities: list[BatteryNotesBatteryLowTemplateSensor | BatteryNotesBatteryLowSensor | BatteryNotesBatteryBinaryLowSensor] = [] - # entities = [ - # BatteryNotesFilteredSensor( - # hass, - # coordinator, - # battery_filtered_entity_description, - # f"{config_entry.entry_id}{subentry.unique_id}{battery_filtered_entity_description.unique_id_suffix}", - # ) - # ] - if coordinator.battery_low_template is not None: entities.append( BatteryNotesBatteryLowTemplateSensor( @@ -207,28 +189,6 @@ async def async_setup_entry( config_subentry_id=subentry.subentry_id, ) -# class BatteryNotesFilteredSensor(BatteryNotesEntity, BinarySensorEntity): -# """Represents a filtered battery sensor.""" - -# entity_description: BatteryNotesBinarySensorEntityDescription - -# def __init__( -# self, -# hass: HomeAssistant, -# coordinator: BatteryNotesCoordinator, -# entity_description: BatteryNotesBinarySensorEntityDescription, -# unique_id: str, -# ) -> None: -# """Create a filtered battery sensor.""" -# super().__init__(hass, entity_description=entity_description, coordinator=coordinator) - -# self._attr_unique_id = unique_id - -# @property -# def is_on(self) -> bool | None: -# """Return true if sensor is on.""" -# return self.coordinator.filter_outliers - class _TemplateAttribute: """Attribute value linked to template result.""" diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 582c37afb..6b5764118 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -338,11 +338,6 @@ def unique_id(self) -> str: """Return a unique ID for the coordinator.""" return f"{self.config_entry.entry_id}_{self.subentry.subentry_id}" - @property - def filter_outliers(self) -> bool: - """Return if outlier filtering is enabled.""" - return self.subentry.data.get(CONF_FILTER_OUTLIERS, False) - @property def source_entity_name(self): """Get the current name of the source_entity_id.""" diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index 532657b6e..8b8e89f9c 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -7,11 +7,9 @@ from homeassistant.core import HomeAssistant, split_entity_id from homeassistant.helpers import device_registry as dr from homeassistant.helpers.device import async_entity_id_to_device_id -from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN from .coordinator import BatteryNotesSubentryCoordinator @@ -22,7 +20,6 @@ class BatteryNotesRequiredKeysMixin: unique_id_suffix: str entity_type: str require_device: bool = False - attach_to_source_device: bool = True @dataclass(frozen=True, kw_only=True) @@ -56,14 +53,7 @@ def __init__( self._set_entity_id(entity_description) # Set up device association - if entity_description.attach_to_source_device: - self._associate_device(hass, device_registry) - else: - self.device_entry = None - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, coordinator.unique_id)}, - ) - + self._associate_device(hass, device_registry) def _set_entity_id(self, entity_description: BatteryNotesEntityDescription) -> None: """Set up entity naming and translation placeholders.""" From d0f2dd01a6c104371490d67c56b7bb7d4f0285cc Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 13:58:25 +0000 Subject: [PATCH 097/235] mypy --- custom_components/battery_notes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 6da831dbb..ac08161e0 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -171,7 +171,7 @@ async def _after_start(_: Event) -> None: @callback def _unsubscribe_ha_started() -> None: """Unsubscribe the started listener.""" - if after_start_unsub: + if after_start_unsub is not None: try: after_start_unsub() except ValueError: From 77ccb6b714d37d4e70a5770b7bd1569c2f155f2e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 14:04:09 +0000 Subject: [PATCH 098/235] Add back from the future check --- custom_components/battery_notes/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index ac08161e0..155223308 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -316,9 +316,13 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> async def async_migrate_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry -): +) -> bool: """Migrate old config.""" + if config_entry.version > 3: + # This means the user has downgraded from a future version + return False + if config_entry.version == 1: # Version 1 had a single config for qty & type, split them _LOGGER.debug("Migrating config entry from version %s", config_entry.version) From 421f3d8ca3a9af19d1c88daa4f7b6e97698fdd0b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 15:05:20 +0000 Subject: [PATCH 099/235] Skip ignored config entries --- custom_components/battery_notes/__init__.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 155223308..9b770d133 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -11,7 +11,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import ConfigEntry, ConfigSubentry +from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry from homeassistant.const import ( CONF_DEVICE_ID, EVENT_HOMEASSISTANT_STARTED, @@ -227,7 +227,10 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> }, ) - entries = hass.config_entries.async_entries(DOMAIN) + entries = sorted( + hass.config_entries.async_entries(DOMAIN), + key=lambda e: e.disabled_by is not None, + ) if not any(entry.version < 3 for entry in entries): return @@ -241,6 +244,9 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if entry.version >= 3: continue + if entry.source == SOURCE_IGNORE: + continue + subentry = ConfigSubentry( data=entry.data, subentry_type=SUBENTRY_BATTERY_NOTE, From 37f1e6c3b00506531eed3c317523a26e4d651813 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 15:07:50 +0000 Subject: [PATCH 100/235] Only migrate user entries --- custom_components/battery_notes/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 9b770d133..4d841da3c 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -11,7 +11,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry +from homeassistant.config_entries import SOURCE_USER, ConfigEntry, ConfigSubentry from homeassistant.const import ( CONF_DEVICE_ID, EVENT_HOMEASSISTANT_STARTED, @@ -244,7 +244,7 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if entry.version >= 3: continue - if entry.source == SOURCE_IGNORE: + if entry.source != SOURCE_USER: continue subentry = ConfigSubentry( From b3943314a6b3e16569ac08bd041c19dcdbce5076 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 15:52:00 +0000 Subject: [PATCH 101/235] Filter entries by user source during migration and setup --- custom_components/battery_notes/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 4d841da3c..94bcd3bfe 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -19,6 +19,7 @@ from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import Event, HomeAssistant, callback from homeassistant.helpers import config_validation as cv +from homeassistant.helpers import device_registry as dr from homeassistant.helpers import entity_registry as er from homeassistant.helpers import helper_integration from homeassistant.helpers import issue_registry as ir @@ -124,6 +125,9 @@ async def async_setup_entry( ) -> bool: """Set up a config entry.""" + if config_entry.source != SOURCE_USER: + return False + domain_config = hass.data[MY_KEY] assert domain_config.store @@ -231,6 +235,9 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> hass.config_entries.async_entries(DOMAIN), key=lambda e: e.disabled_by is not None, ) + + entries = filter(lambda e: e.source == SOURCE_USER, entries) + if not any(entry.version < 3 for entry in entries): return @@ -300,6 +307,11 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> hass.config_entries.async_add_subentry(migrate_base_entry, subentry) source_device_id = subentry.data.get(CONF_DEVICE_ID, None) + device_registry = dr.async_get(hass) + source_device = device_registry.async_get(source_device_id) + if source_device is None: + source_device_id = None + source_entity_id = subentry.data.get("source_entity_id", None) if source_entity_id: source_device_id = async_entity_id_to_device_id( From 41d34682090f3c96c98fb471b39c1f6b956a3a43 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 16:23:01 +0000 Subject: [PATCH 102/235] Refactor migration logic to simplify entry filtering by user source --- custom_components/battery_notes/__init__.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 94bcd3bfe..468e04c09 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -231,14 +231,9 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> }, ) - entries = sorted( - hass.config_entries.async_entries(DOMAIN), - key=lambda e: e.disabled_by is not None, - ) - - entries = filter(lambda e: e.source == SOURCE_USER, entries) + entries = hass.config_entries.async_entries(DOMAIN) - if not any(entry.version < 3 for entry in entries): + if not any(entry.version < 3 and entry.source == SOURCE_USER for entry in entries): return for entry in entries: From 1ecda1758fd6b0646b325bd28bf2ac1248ac9bda Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 16:49:39 +0000 Subject: [PATCH 103/235] Refactor migration logic to handle ignored config entries --- custom_components/battery_notes/__init__.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 468e04c09..ff3385879 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -11,7 +11,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import SOURCE_USER, ConfigEntry, ConfigSubentry +from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry from homeassistant.const import ( CONF_DEVICE_ID, EVENT_HOMEASSISTANT_STARTED, @@ -125,9 +125,6 @@ async def async_setup_entry( ) -> bool: """Set up a config entry.""" - if config_entry.source != SOURCE_USER: - return False - domain_config = hass.data[MY_KEY] assert domain_config.store @@ -233,7 +230,7 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> entries = hass.config_entries.async_entries(DOMAIN) - if not any(entry.version < 3 and entry.source == SOURCE_USER for entry in entries): + if not any(entry.version < 3 for entry in entries): return for entry in entries: @@ -246,7 +243,7 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if entry.version >= 3: continue - if entry.source != SOURCE_USER: + if entry.source == SOURCE_IGNORE: continue subentry = ConfigSubentry( From ff514a1e8c81482a77ad20e94a1960e7e88652c4 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 16:54:41 +0000 Subject: [PATCH 104/235] Add default value for battery low template in coordinator --- custom_components/battery_notes/coordinator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 6b5764118..557c17abf 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -152,7 +152,7 @@ def __init__( self.battery_low_threshold = self.config_entry.runtime_data.domain_config.default_battery_low_threshold self.battery_low_template = self.subentry.data.get( - CONF_BATTERY_LOW_TEMPLATE + CONF_BATTERY_LOW_TEMPLATE, None ) if self.subentry.data.get(CONF_FILTER_OUTLIERS, False): From 570815c4b4810a26b5a93dd441e1e379f75443cb Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 16:55:36 +0000 Subject: [PATCH 105/235] Set default values for battery type and quantity in coordinator --- custom_components/battery_notes/coordinator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 557c17abf..02df4e2b5 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -135,10 +135,10 @@ def __init__( assert(self.device_name) - self.battery_type = cast(str, self.subentry.data.get(CONF_BATTERY_TYPE)) + self.battery_type = cast(str, self.subentry.data.get(CONF_BATTERY_TYPE, "")) try: self.battery_quantity = cast( - int, self.subentry.data.get(CONF_BATTERY_QUANTITY) + int, self.subentry.data.get(CONF_BATTERY_QUANTITY, 1) ) except ValueError: self.battery_quantity = 1 From dd5ce4761849106d84f8da79149274d34f4e7576 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 16:57:01 +0000 Subject: [PATCH 106/235] Add TODO comment to tidy up entry data from discovery --- custom_components/battery_notes/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index ff3385879..90aa8b9cc 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -246,6 +246,7 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if entry.source == SOURCE_IGNORE: continue + # TODO: tidy up the entry data, we had lots from discovery subentry = ConfigSubentry( data=entry.data, subentry_type=SUBENTRY_BATTERY_NOTE, From efe3896d11762be583c94a1beb35cc249205716b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 17 Aug 2025 16:57:34 +0000 Subject: [PATCH 107/235] Add example data --- custom_components/battery_notes/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 90aa8b9cc..e88f3d81d 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -247,6 +247,12 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> continue # TODO: tidy up the entry data, we had lots from discovery +# {"created_at":"2025-06-04T07:59:00.050540+00:00","data":{},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01JWWZ6QEJHTWBKM054G230H6V","minor_version":1,"modified_at":"2025-06-04T07:59:00.050556+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"ignore","subentries":[],"title":"Andrew iPhone","unique_id":"bn_2c435f4055acc0bba193cf9f33e86a33","version":2}, +# {"created_at":"2025-07-20T14:48:29.682036+00:00","data":{},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K0M4XK7H59AQ7QC42GEVY9WK","minor_version":1,"modified_at":"2025-07-20T14:48:29.682052+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"ignore","subentries":[],"title":"Andrew iPhone","unique_id":"bn_5cd3048fa97187702ced78372027b351","version":2}, +# {"created_at":"2025-07-26T09:31:15.677923+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"PP3","device_id":"3b9a68e12840b196c2c7880f74f4a6d3","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13151AXRZNXS1DCZXVR98QN","minor_version":1,"modified_at":"2025-07-26T09:31:15.677935+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"Sun","unique_id":"bn_3b9a68e12840b196c2c7880f74f4a6d3","version":2}, +# {"created_at":"2025-07-26T09:48:49.716087+00:00","data":{"battery_low_threshold":0,"battery_quantity":1,"battery_type":"CR2032","device_id":"27cab4eab4f9640128e035a3e0e4ccff","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13256NM2E3ACHADFV9CX5RP","minor_version":1,"modified_at":"2025-08-02T16:02:41.411041+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"IKEA of Sweden TRADFRI on/off switch","unique_id":"bn_27cab4eab4f9640128e035a3e0e4ccff","version":2}, +# {"created_at":"2025-08-05T12:41:14.589333+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"Rechargeable","device_id":"1a6d01cd769c974a939b8c6dbdc3390e","device_name":"Andrew’s iPad","filter_outliers":false,"manufacturer":"Apple","model":"iPad8,1","model_id":[null]},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K1X4032X1QNMYNKM6WV7EY5N","minor_version":1,"modified_at":"2025-08-05T12:41:14.589344+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"integration_discovery","subentries":[],"title":"Andrew’s iPad","unique_id":"bn_1a6d01cd769c974a939b8c6dbdc3390e","version":2}, + subentry = ConfigSubentry( data=entry.data, subentry_type=SUBENTRY_BATTERY_NOTE, From f90aafc3ffd18dfa390498512b7b6e1d323f4312 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 09:36:57 +0000 Subject: [PATCH 108/235] Remove discovery data from config entry --- custom_components/battery_notes/config_flow.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 79092e9ff..34465720a 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -388,6 +388,13 @@ async def async_step_battery( assert device_entry title = device_entry.name_by_user or device_entry.name + # Remove discovery data from data + self.data.pop(CONF_MANUFACTURER, None) + self.data.pop(CONF_MODEL, None) + self.data.pop(CONF_MODEL_ID, None) + self.data.pop(CONF_BATTERY_TYPE, None) + self.data.pop(CONF_BATTERY_QUANTITY, None) + config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] # Create a subentry subentry = ConfigSubentry(subentry_type=SUBENTRY_BATTERY_NOTE, data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) From 2fbcb381e1924b08cc63d8ba77579a106592f96f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 10:12:26 +0000 Subject: [PATCH 109/235] Remove manufacturer and model information from entry data in migration process --- custom_components/battery_notes/__init__.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index e88f3d81d..e582b3c9e 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,6 +8,7 @@ import logging import re +from types import MappingProxyType import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion @@ -38,6 +39,9 @@ CONF_ENABLE_AUTODISCOVERY, CONF_ENABLE_REPLACED, CONF_HIDE_BATTERY, + CONF_MANUFACTURER, + CONF_MODEL, + CONF_MODEL_ID, CONF_ROUND_BATTERY, CONF_SHOW_ALL_DEVICES, CONF_USER_LIBRARY, @@ -253,8 +257,16 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> # {"created_at":"2025-07-26T09:48:49.716087+00:00","data":{"battery_low_threshold":0,"battery_quantity":1,"battery_type":"CR2032","device_id":"27cab4eab4f9640128e035a3e0e4ccff","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13256NM2E3ACHADFV9CX5RP","minor_version":1,"modified_at":"2025-08-02T16:02:41.411041+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"IKEA of Sweden TRADFRI on/off switch","unique_id":"bn_27cab4eab4f9640128e035a3e0e4ccff","version":2}, # {"created_at":"2025-08-05T12:41:14.589333+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"Rechargeable","device_id":"1a6d01cd769c974a939b8c6dbdc3390e","device_name":"Andrew’s iPad","filter_outliers":false,"manufacturer":"Apple","model":"iPad8,1","model_id":[null]},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K1X4032X1QNMYNKM6WV7EY5N","minor_version":1,"modified_at":"2025-08-05T12:41:14.589344+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"integration_discovery","subentries":[],"title":"Andrew’s iPad","unique_id":"bn_1a6d01cd769c974a939b8c6dbdc3390e","version":2}, + entry_data_dict = dict(entry.data) + + entry_data_dict.pop(CONF_MANUFACTURER, None) + entry_data_dict.pop(CONF_MODEL, None) + entry_data_dict.pop(CONF_MODEL_ID, None) + + entry_data_dict = MappingProxyType(entry_data_dict) + subentry = ConfigSubentry( - data=entry.data, + data=entry_data_dict, subentry_type=SUBENTRY_BATTERY_NOTE, title=entry.title, unique_id=entry.unique_id, From aa56945675073a11481fa3926ef1db50c214438d Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 10:13:37 +0000 Subject: [PATCH 110/235] Fix config flow discovery --- custom_components/battery_notes/config_flow.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 34465720a..aa8d80d2f 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -392,8 +392,6 @@ async def async_step_battery( self.data.pop(CONF_MANUFACTURER, None) self.data.pop(CONF_MODEL, None) self.data.pop(CONF_MODEL_ID, None) - self.data.pop(CONF_BATTERY_TYPE, None) - self.data.pop(CONF_BATTERY_QUANTITY, None) config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] # Create a subentry From 014b621ebef6b4d7c465573a1ca346dd248de5a3 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 10:54:55 +0000 Subject: [PATCH 111/235] Update migration logic to exclude ignored entries from version check --- custom_components/battery_notes/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index e582b3c9e..7bc769384 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -234,7 +234,7 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> entries = hass.config_entries.async_entries(DOMAIN) - if not any(entry.version < 3 for entry in entries): + if not any(entry.version < 3 and entry.source != SOURCE_IGNORE for entry in entries): return for entry in entries: @@ -251,11 +251,11 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> continue # TODO: tidy up the entry data, we had lots from discovery -# {"created_at":"2025-06-04T07:59:00.050540+00:00","data":{},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01JWWZ6QEJHTWBKM054G230H6V","minor_version":1,"modified_at":"2025-06-04T07:59:00.050556+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"ignore","subentries":[],"title":"Andrew iPhone","unique_id":"bn_2c435f4055acc0bba193cf9f33e86a33","version":2}, -# {"created_at":"2025-07-20T14:48:29.682036+00:00","data":{},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K0M4XK7H59AQ7QC42GEVY9WK","minor_version":1,"modified_at":"2025-07-20T14:48:29.682052+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"ignore","subentries":[],"title":"Andrew iPhone","unique_id":"bn_5cd3048fa97187702ced78372027b351","version":2}, -# {"created_at":"2025-07-26T09:31:15.677923+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"PP3","device_id":"3b9a68e12840b196c2c7880f74f4a6d3","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13151AXRZNXS1DCZXVR98QN","minor_version":1,"modified_at":"2025-07-26T09:31:15.677935+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"Sun","unique_id":"bn_3b9a68e12840b196c2c7880f74f4a6d3","version":2}, -# {"created_at":"2025-07-26T09:48:49.716087+00:00","data":{"battery_low_threshold":0,"battery_quantity":1,"battery_type":"CR2032","device_id":"27cab4eab4f9640128e035a3e0e4ccff","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13256NM2E3ACHADFV9CX5RP","minor_version":1,"modified_at":"2025-08-02T16:02:41.411041+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"IKEA of Sweden TRADFRI on/off switch","unique_id":"bn_27cab4eab4f9640128e035a3e0e4ccff","version":2}, -# {"created_at":"2025-08-05T12:41:14.589333+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"Rechargeable","device_id":"1a6d01cd769c974a939b8c6dbdc3390e","device_name":"Andrew’s iPad","filter_outliers":false,"manufacturer":"Apple","model":"iPad8,1","model_id":[null]},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K1X4032X1QNMYNKM6WV7EY5N","minor_version":1,"modified_at":"2025-08-05T12:41:14.589344+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"integration_discovery","subentries":[],"title":"Andrew’s iPad","unique_id":"bn_1a6d01cd769c974a939b8c6dbdc3390e","version":2}, +# ignored {"created_at":"2025-06-04T07:59:00.050540+00:00","data":{},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01JWWZ6QEJHTWBKM054G230H6V","minor_version":1,"modified_at":"2025-06-04T07:59:00.050556+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"ignore","subentries":[],"title":"Andrew iPhone","unique_id":"bn_2c435f4055acc0bba193cf9f33e86a33","version":2}, +# ignored {"created_at":"2025-07-20T14:48:29.682036+00:00","data":{},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K0M4XK7H59AQ7QC42GEVY9WK","minor_version":1,"modified_at":"2025-07-20T14:48:29.682052+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"ignore","subentries":[],"title":"Andrew iPhone","unique_id":"bn_5cd3048fa97187702ced78372027b351","version":2}, +# user {"created_at":"2025-07-26T09:31:15.677923+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"PP3","device_id":"3b9a68e12840b196c2c7880f74f4a6d3","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13151AXRZNXS1DCZXVR98QN","minor_version":1,"modified_at":"2025-07-26T09:31:15.677935+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"Sun","unique_id":"bn_3b9a68e12840b196c2c7880f74f4a6d3","version":2}, +# user {"created_at":"2025-07-26T09:48:49.716087+00:00","data":{"battery_low_threshold":0,"battery_quantity":1,"battery_type":"CR2032","device_id":"27cab4eab4f9640128e035a3e0e4ccff","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13256NM2E3ACHADFV9CX5RP","minor_version":1,"modified_at":"2025-08-02T16:02:41.411041+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"IKEA of Sweden TRADFRI on/off switch","unique_id":"bn_27cab4eab4f9640128e035a3e0e4ccff","version":2}, +# discovery{"created_at":"2025-08-05T12:41:14.589333+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"Rechargeable","device_id":"1a6d01cd769c974a939b8c6dbdc3390e","device_name":"Andrew’s iPad","filter_outliers":false,"manufacturer":"Apple","model":"iPad8,1","model_id":[null]},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K1X4032X1QNMYNKM6WV7EY5N","minor_version":1,"modified_at":"2025-08-05T12:41:14.589344+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"integration_discovery","subentries":[],"title":"Andrew’s iPad","unique_id":"bn_1a6d01cd769c974a939b8c6dbdc3390e","version":2}, entry_data_dict = dict(entry.data) From cf617e2c0fe3570355e34d7b48418f4a35bd725e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 12:50:40 +0000 Subject: [PATCH 112/235] Fix for library hw_version matching --- custom_components/battery_notes/library.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 49c769028..84de01bc9 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -106,7 +106,7 @@ async def get_device_battery_details( return None # Test only - # device_to_find = ModelInfo("Espressif", "m5stack-atom", None, None) + # device_to_find = ModelInfo("Aqara", "Aqara Climate Sensor W100", "8196", None) # Get all devices matching manufacturer & model matching_devices = None @@ -135,7 +135,7 @@ async def get_device_battery_details( if fully_matching_devices and len(fully_matching_devices) > 0: matching_devices = fully_matching_devices - if not matching_devices or len(matching_devices) == 0: + if not matching_devices or len(matching_devices) != 1: return None matched_device = matching_devices[0] @@ -196,7 +196,7 @@ def device_partial_match( if ( device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() == str(model_info.hw_version).casefold() - and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() == str(model_info.model_id).casefold() ): return True @@ -204,7 +204,7 @@ def device_partial_match( if ( device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() == str(model_info.hw_version).casefold() - or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() == str(model_info.model_id).casefold() ): return True From 1d2a4622d853fee99660967849e98bbd8c833ec0 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 12:50:59 +0000 Subject: [PATCH 113/235] Update v2 ignored entries --- custom_components/battery_notes/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 7bc769384..aa6d6ff43 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -382,6 +382,11 @@ async def async_migrate_entry( 2, ) + if config_entry.version == 2 and config_entry.source == SOURCE_IGNORE: + hass.config_entries.async_update_entry( + config_entry, version=3, title=config_entry.title + ) + return True From 7b12051831011c9b497bdbf3ecbe723d0f48fdf6 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 12:53:59 +0000 Subject: [PATCH 114/235] Add new commented out test --- custom_components/battery_notes/library.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 84de01bc9..16986b03a 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -107,6 +107,8 @@ async def get_device_battery_details( # Test only # device_to_find = ModelInfo("Aqara", "Aqara Climate Sensor W100", "8196", None) + # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Battery") + # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Wired") # Get all devices matching manufacturer & model matching_devices = None From fd453e719b11c32d50674c9b163dbb34c3ca7948 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 13:46:21 +0000 Subject: [PATCH 115/235] Refactor device battery details retrieval to use constant for model_id --- custom_components/battery_notes/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 16986b03a..731beee0d 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -144,7 +144,7 @@ async def get_device_battery_details( return DeviceBatteryDetails( manufacturer=matched_device[LIBRARY_MANUFACTURER], model=matched_device[LIBRARY_MODEL], - model_id=matched_device.get("model_id", ""), + model_id=matched_device.get(LIBRARY_MODEL_ID, ""), hw_version=matched_device.get(LIBRARY_HW_VERSION, ""), battery_type=matched_device[LIBRARY_BATTERY_TYPE], battery_quantity=matched_device.get(LIBRARY_BATTERY_QUANTITY, 1), From 27435dd3e54f3d70ae89a7f2338eab88eb9f0065 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 14:45:34 +0000 Subject: [PATCH 116/235] Refactor migration logic to use MappingProxyType for entry data and improve discovery flow checks --- custom_components/battery_notes/__init__.py | 5 ++--- custom_components/battery_notes/discovery.py | 22 +++++++++----------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index aa6d6ff43..089a47787 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,6 +8,7 @@ import logging import re +from collections.abc import Mapping from types import MappingProxyType import voluptuous as vol @@ -263,10 +264,8 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> entry_data_dict.pop(CONF_MODEL, None) entry_data_dict.pop(CONF_MODEL_ID, None) - entry_data_dict = MappingProxyType(entry_data_dict) - subentry = ConfigSubentry( - data=entry_data_dict, + data=MappingProxyType(entry_data_dict), subentry_type=SUBENTRY_BATTERY_NOTE, title=entry.title, unique_id=entry.unique_id, diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index a9a8c0276..ea687c7b3 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -6,7 +6,7 @@ from typing import Any import homeassistant.helpers.device_registry as dr -from homeassistant.config_entries import SOURCE_INTEGRATION_DISCOVERY +from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_INTEGRATION_DISCOVERY from homeassistant.const import CONF_DEVICE_ID from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import discovery_flow @@ -133,17 +133,15 @@ def _init_entity_discovery( device_battery_details: DeviceBatteryDetails, ) -> None: """Dispatch the discovery flow for a given entity.""" - existing_entries = [ - entry - for entry in self.hass.config_entries.async_entries(DOMAIN) - if entry.unique_id == f"bn_{device_entry.id}" - ] - if existing_entries: - _LOGGER.debug( - "%s: Already setup, skipping new discovery", - f"bn_{device_entry.id}", - ) - return + for config_entry in self.hass.config_entries.async_entries(DOMAIN): + if config_entry.source != SOURCE_IGNORE: + for subentry in config_entry.subentries.values(): + if subentry.data.get(CONF_DEVICE_ID, "") == device_entry.id: + _LOGGER.debug( + "%s: Already setup, skipping new discovery", + f"bn_{device_entry.id}", + ) + return discovery_data: dict[str, Any] = { CONF_DEVICE_ID: device_entry.id, From c1aad30629530b2611c71f2575f1afe41a843162 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 14:49:53 +0000 Subject: [PATCH 117/235] Fix unique ID generation for battery sensor entities in async_setup_entry --- custom_components/battery_notes/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 0eb8a9a5f..dd97a6440 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -177,7 +177,7 @@ async def async_setup_entry( subentry, battery_plus_sensor_entity_description, coordinator, - f"{config_entry.entry_id}{battery_plus_sensor_entity_description.unique_id_suffix}", + f"{config_entry.entry_id}{subentry.unique_id}{battery_plus_sensor_entity_description.unique_id_suffix}", config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, False), ) From 05717a1e9cc2f65ba111c2160dd7bd13697233c1 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 18 Aug 2025 16:19:24 +0000 Subject: [PATCH 118/235] Ignore disable entries on migration --- custom_components/battery_notes/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 089a47787..f25291e1d 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -233,7 +233,10 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> }, ) - entries = hass.config_entries.async_entries(DOMAIN) + entries = sorted( + hass.config_entries.async_entries(DOMAIN), + key=lambda e: e.disabled_by is not None, + ) if not any(entry.version < 3 and entry.source != SOURCE_IGNORE for entry in entries): return @@ -248,6 +251,9 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if entry.version >= 3: continue + if entry.disabled_by is not None: + continue + if entry.source == SOURCE_IGNORE: continue From bd634b25cf83be91fbce1a4e001f57e4645f6937 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 19 Aug 2025 10:38:16 +0000 Subject: [PATCH 119/235] Migrate entity unique id's --- custom_components/battery_notes/__init__.py | 24 +++++++++++++++++++ .../battery_notes/binary_sensor.py | 6 ++--- custom_components/battery_notes/button.py | 2 +- custom_components/battery_notes/sensor.py | 8 +++---- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index f25291e1d..c19dbf3a6 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -322,6 +322,30 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> hass.config_entries.async_add_subentry(migrate_base_entry, subentry) + # Update entities unique_id to be the subentry + entity_registry = er.async_get(hass) + for entity_entry in entity_registry.entities.values(): + if entity_entry.config_entry_id == entry.entry_id: + # Update the unique_id to be the subentry unique_id + + if "_" not in entity_entry.unique_id: + new_unique_id = f"{subentry.unique_id}_battery_type" + else: + new_unique_id = f"{subentry.unique_id}_{entity_entry.unique_id.split("_", 1)[1]}" + + entity_disabled_by = entity_entry.disabled_by + if entity_disabled_by: + entity_disabled_by = er.RegistryEntryDisabler.USER + + entity_registry.async_update_entity( + entity_entry.entity_id, + config_entry_id=migrate_base_entry.entry_id, + config_subentry_id=subentry.subentry_id, + disabled_by=entity_disabled_by, + new_unique_id=new_unique_id, + ) + + # Remove the config entry from the device source_device_id = subentry.data.get(CONF_DEVICE_ID, None) device_registry = dr.async_get(hass) source_device = device_registry.async_get(source_device_id) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index f7a44f476..fd01a07fe 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -158,7 +158,7 @@ async def async_setup_entry( hass, coordinator, battery_low_entity_description, - f"{config_entry.entry_id}{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", + f"{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", coordinator.battery_low_template, ) ) @@ -169,7 +169,7 @@ async def async_setup_entry( hass, coordinator, battery_low_entity_description, - f"{config_entry.entry_id}{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", + f"{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", ) ) @@ -179,7 +179,7 @@ async def async_setup_entry( hass, coordinator, battery_low_entity_description, - f"{config_entry.entry_id}{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", + f"{subentry.unique_id}{battery_low_entity_description.unique_id_suffix}", ) ) diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index c7b7b6e7c..95eedeec4 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -105,7 +105,7 @@ async def async_setup_entry( hass, coordinator, description, - f"{config_entry.entry_id}{subentry.unique_id}{description.unique_id_suffix}", + f"{subentry.unique_id}{description.unique_id_suffix}", ) ], config_subentry_id=subentry.subentry_id, diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index dd97a6440..f07ea8d44 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -122,7 +122,7 @@ async def async_setup_entry( continue type_sensor_entity_description = BatteryNotesSensorEntityDescription( - unique_id_suffix="", # battery_type has uniqueId set to entityId in V1, never add a suffix + unique_id_suffix="_battery_type", key="battery_type", translation_key="battery_type", entity_category=EntityCategory.DIAGNOSTIC, @@ -156,7 +156,7 @@ async def async_setup_entry( subentry, type_sensor_entity_description, coordinator, - f"{config_entry.entry_id}{subentry.unique_id}{type_sensor_entity_description.unique_id_suffix}", + f"{subentry.unique_id}{type_sensor_entity_description.unique_id_suffix}", ), BatteryNotesLastReplacedSensor( hass, @@ -165,7 +165,7 @@ async def async_setup_entry( last_replaced_sensor_entity_description, coordinator, last_replaced_sensor_entity_description, - f"{config_entry.entry_id}{subentry.unique_id}{last_replaced_sensor_entity_description.unique_id_suffix}", + f"{subentry.unique_id}{last_replaced_sensor_entity_description.unique_id_suffix}", ), ] @@ -177,7 +177,7 @@ async def async_setup_entry( subentry, battery_plus_sensor_entity_description, coordinator, - f"{config_entry.entry_id}{subentry.unique_id}{battery_plus_sensor_entity_description.unique_id_suffix}", + f"{subentry.unique_id}{battery_plus_sensor_entity_description.unique_id_suffix}", config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, False), ) From 7cd16b8b0033fdef23a20cf20bb47530a9d8e226 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 20 Aug 2025 09:37:07 +0000 Subject: [PATCH 120/235] Delete disabled config entries --- custom_components/battery_notes/__init__.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index c19dbf3a6..eb80b92a1 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,7 +8,6 @@ import logging import re -from collections.abc import Mapping from types import MappingProxyType import voluptuous as vol @@ -251,21 +250,15 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if entry.version >= 3: continue - if entry.disabled_by is not None: - continue - if entry.source == SOURCE_IGNORE: continue - # TODO: tidy up the entry data, we had lots from discovery -# ignored {"created_at":"2025-06-04T07:59:00.050540+00:00","data":{},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01JWWZ6QEJHTWBKM054G230H6V","minor_version":1,"modified_at":"2025-06-04T07:59:00.050556+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"ignore","subentries":[],"title":"Andrew iPhone","unique_id":"bn_2c435f4055acc0bba193cf9f33e86a33","version":2}, -# ignored {"created_at":"2025-07-20T14:48:29.682036+00:00","data":{},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K0M4XK7H59AQ7QC42GEVY9WK","minor_version":1,"modified_at":"2025-07-20T14:48:29.682052+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"ignore","subentries":[],"title":"Andrew iPhone","unique_id":"bn_5cd3048fa97187702ced78372027b351","version":2}, -# user {"created_at":"2025-07-26T09:31:15.677923+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"PP3","device_id":"3b9a68e12840b196c2c7880f74f4a6d3","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13151AXRZNXS1DCZXVR98QN","minor_version":1,"modified_at":"2025-07-26T09:31:15.677935+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"Sun","unique_id":"bn_3b9a68e12840b196c2c7880f74f4a6d3","version":2}, -# user {"created_at":"2025-07-26T09:48:49.716087+00:00","data":{"battery_low_threshold":0,"battery_quantity":1,"battery_type":"CR2032","device_id":"27cab4eab4f9640128e035a3e0e4ccff","filter_outliers":false},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K13256NM2E3ACHADFV9CX5RP","minor_version":1,"modified_at":"2025-08-02T16:02:41.411041+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"user","subentries":[],"title":"IKEA of Sweden TRADFRI on/off switch","unique_id":"bn_27cab4eab4f9640128e035a3e0e4ccff","version":2}, -# discovery{"created_at":"2025-08-05T12:41:14.589333+00:00","data":{"battery_low_template":null,"battery_low_threshold":0,"battery_quantity":1,"battery_type":"Rechargeable","device_id":"1a6d01cd769c974a939b8c6dbdc3390e","device_name":"Andrew’s iPad","filter_outliers":false,"manufacturer":"Apple","model":"iPad8,1","model_id":[null]},"disabled_by":null,"discovery_keys":{},"domain":"battery_notes","entry_id":"01K1X4032X1QNMYNKM6WV7EY5N","minor_version":1,"modified_at":"2025-08-05T12:41:14.589344+00:00","options":{},"pref_disable_new_entities":false,"pref_disable_polling":false,"source":"integration_discovery","subentries":[],"title":"Andrew’s iPad","unique_id":"bn_1a6d01cd769c974a939b8c6dbdc3390e","version":2}, + if entry.disabled_by is not None: + # We cannot migrate a disabled entry to a subentry, delete it instead + await hass.config_entries.async_remove(entry.entry_id) + continue entry_data_dict = dict(entry.data) - entry_data_dict.pop(CONF_MANUFACTURER, None) entry_data_dict.pop(CONF_MODEL, None) entry_data_dict.pop(CONF_MODEL_ID, None) From 802c1518604d5cd4575bd1463f97000565a1d9f7 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 20 Aug 2025 12:14:02 +0000 Subject: [PATCH 121/235] Clean up accidental discovery data in migration process --- custom_components/battery_notes/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index eb80b92a1..1aca31119 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -258,6 +258,7 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> await hass.config_entries.async_remove(entry.entry_id) continue + # Tidy up data we accidentally added from discovery entry_data_dict = dict(entry.data) entry_data_dict.pop(CONF_MANUFACTURER, None) entry_data_dict.pop(CONF_MODEL, None) From 8737c4e2bd193cf89b97bb9ea1345eb2a82e51dd Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 20 Aug 2025 15:27:31 +0000 Subject: [PATCH 122/235] Refactor unique ID check to include ignored and disabled entries in config flow --- .../battery_notes/config_flow.py | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index aa8d80d2f..569393c91 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -12,6 +12,7 @@ from homeassistant import config_entries from homeassistant.components.sensor.const import SensorDeviceClass from homeassistant.config_entries import ( + SOURCE_IGNORE, ConfigEntry, ConfigFlowResult, ConfigSubentry, @@ -182,9 +183,17 @@ async def async_step_integration_discovery( unique_id = f"bn_{discovery_info[CONF_DEVICE_ID]}" - # Check if unique_id already exists as sub entry - config_entries = self.hass.config_entries.async_entries(domain=DOMAIN) - if not config_entries: + # Check if unique_id already exists as sub entry) + config_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False), + + config_entry: ConfigEntry | None = None + for entry in config_entries[0]: + if entry.title == INTEGRATION_NAME: + # We found the main config entry, use it + config_entry = entry + break + + if not config_entry: _LOGGER.debug("No existing single config entry found, creating new one") # Init defaults @@ -206,10 +215,13 @@ async def async_step_integration_discovery( data={}, options=options ) + config_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False), + for entry in config_entries[0]: + if entry.title == INTEGRATION_NAME: + # We found the main config entry, use it + config_entry = entry + break - config_entries = self.hass.config_entries.async_entries(domain=DOMAIN) - - config_entry = config_entries[0] for existing_subentry in config_entry.subentries.values(): if existing_subentry.unique_id == unique_id: _LOGGER.debug("Subentry with unique_id %s already exists", unique_id) From 3f412f590023e9cadac57f96721cf1d47d0a4ccc Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 20 Aug 2025 15:28:48 +0000 Subject: [PATCH 123/235] Add assertion to ensure config entry is not None in BatteryNotesFlowHandler --- custom_components/battery_notes/config_flow.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 569393c91..b46a92de1 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -222,6 +222,8 @@ async def async_step_integration_discovery( config_entry = entry break + assert(config_entry is not None) + for existing_subentry in config_entry.subentries.values(): if existing_subentry.unique_id == unique_id: _LOGGER.debug("Subentry with unique_id %s already exists", unique_id) From 902f1f9195b12f63db5c6d9df7dedee6fe72fc6b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 21 Aug 2025 11:14:12 +0000 Subject: [PATCH 124/235] Fix config entry retrieval and enhance device matching logic in BatteryNotes --- custom_components/battery_notes/config_flow.py | 4 ++-- custom_components/battery_notes/discovery.py | 17 ++++++++--------- custom_components/battery_notes/library.py | 14 ++++++++++++-- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index b46a92de1..d92f4d25f 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -184,10 +184,10 @@ async def async_step_integration_discovery( unique_id = f"bn_{discovery_info[CONF_DEVICE_ID]}" # Check if unique_id already exists as sub entry) - config_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False), + config_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False) config_entry: ConfigEntry | None = None - for entry in config_entries[0]: + for entry in config_entries: if entry.title == INTEGRATION_NAME: # We found the main config entry, use it config_entry = entry diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index ea687c7b3..57b63d00c 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -133,15 +133,14 @@ def _init_entity_discovery( device_battery_details: DeviceBatteryDetails, ) -> None: """Dispatch the discovery flow for a given entity.""" - for config_entry in self.hass.config_entries.async_entries(DOMAIN): - if config_entry.source != SOURCE_IGNORE: - for subentry in config_entry.subentries.values(): - if subentry.data.get(CONF_DEVICE_ID, "") == device_entry.id: - _LOGGER.debug( - "%s: Already setup, skipping new discovery", - f"bn_{device_entry.id}", - ) - return + for config_entry in self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False): + for subentry in config_entry.subentries.values(): + if subentry.data.get(CONF_DEVICE_ID, "") == device_entry.id: + _LOGGER.debug( + "%s: Already setup, skipping new discovery", + f"bn_{device_entry.id}", + ) + return discovery_data: dict[str, Any] = { CONF_DEVICE_ID: device_entry.id, diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 731beee0d..a70016a81 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -194,11 +194,21 @@ def device_partial_match( self, device: dict[str, Any], model_info: ModelInfo ) -> bool: """Check if device match on hw_version or model_id.""" + if model_info.hw_version is None and model_info.model_id is None: + if ( + device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING) + == LIBRARY_MISSING + and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING) + == LIBRARY_MISSING + ): + return True + return False + if model_info.hw_version is None or model_info.model_id is None: if ( device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() == str(model_info.hw_version).casefold() - or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() == str(model_info.model_id).casefold() ): return True @@ -206,7 +216,7 @@ def device_partial_match( if ( device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() == str(model_info.hw_version).casefold() - and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() == str(model_info.model_id).casefold() ): return True From b5ef188313306f52d9b99bcae884bbd580d8e645 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 21 Aug 2025 11:15:56 +0000 Subject: [PATCH 125/235] Remove unused SOURCE_IGNORE import from config flow and discovery modules --- custom_components/battery_notes/config_flow.py | 1 - custom_components/battery_notes/discovery.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index d92f4d25f..d0638a529 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -12,7 +12,6 @@ from homeassistant import config_entries from homeassistant.components.sensor.const import SensorDeviceClass from homeassistant.config_entries import ( - SOURCE_IGNORE, ConfigEntry, ConfigFlowResult, ConfigSubentry, diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index 57b63d00c..dc12953e1 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -6,7 +6,7 @@ from typing import Any import homeassistant.helpers.device_registry as dr -from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_INTEGRATION_DISCOVERY +from homeassistant.config_entries import SOURCE_INTEGRATION_DISCOVERY from homeassistant.const import CONF_DEVICE_ID from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import discovery_flow From 6ba545f5fe0bdc6b16e4fe9edfa1af3610257d9f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 22 Aug 2025 13:28:44 +0000 Subject: [PATCH 126/235] Fix discovery --- custom_components/battery_notes/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index a70016a81..8efe00a02 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -137,7 +137,7 @@ async def get_device_battery_details( if fully_matching_devices and len(fully_matching_devices) > 0: matching_devices = fully_matching_devices - if not matching_devices or len(matching_devices) != 1: + if not matching_devices: return None matched_device = matching_devices[0] From 784612e5d42b95b987e340977c76fb0d4fb9a6ea Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 11:13:49 +0000 Subject: [PATCH 127/235] Add better instructions --- custom_components/battery_notes/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 440c79085..b1a196a67 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", "title": "Setup Battery Notes" }, "battery": { From 933faff2c7c30a755923bb33a7db44d8312e3311 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 12:03:00 +0000 Subject: [PATCH 128/235] Device name attribute is now always the subentry title --- custom_components/battery_notes/coordinator.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 02df4e2b5..daf1c0c46 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -250,18 +250,7 @@ def _link_to_source(self) -> bool: entity.unit_of_measurement, ) - if entity.device_id: - device_entry = device_registry.async_get(entity.device_id) - if device_entry: - self.device_name = ( - device_entry.name_by_user - or device_entry.name - or self.subentry.title - ) - else: - self.device_name = self.subentry.title - else: - self.device_name = self.subentry.title + self.device_name = self.subentry.title else: for entity in entity_registry.entities.values(): From 8d2d48cc25decacb7dbbd68daf7eb9829e16390f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 12:10:32 +0000 Subject: [PATCH 129/235] Reorder device name assignment logic to prioritize subentry title --- custom_components/battery_notes/coordinator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index daf1c0c46..cf94110dc 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -291,7 +291,7 @@ def _link_to_source(self) -> bool: device_entry = device_registry.async_get(self.device_id) if device_entry: self.device_name = ( - device_entry.name_by_user or device_entry.name or self.subentry.title + self.subentry.title or device_entry.name_by_user or device_entry.name ) else: self.device_name = self.subentry.title From afb99516e286bb56846f4af000c347f3bcf807fb Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 12:24:59 +0000 Subject: [PATCH 130/235] Enhance device name assignment logic to include user-defined names and improve clarity in subentry titles --- .../battery_notes/config_flow.py | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index d0638a529..fa43d97c0 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -19,11 +19,7 @@ OptionsFlow, SubentryFlowResult, ) -from homeassistant.const import ( - CONF_DEVICE_ID, - CONF_NAME, - Platform, -) +from homeassistant.const import CONF_DEVICE_ID, CONF_NAME, Platform from homeassistant.core import callback, split_entity_id from homeassistant.data_entry_flow import section from homeassistant.helpers import selector @@ -394,9 +390,17 @@ async def async_step_battery( self._abort_if_unique_id_configured() if CONF_NAME in self.data: - title = self.data.get(CONF_NAME) + title = self.data.pop(CONF_NAME) elif source_entity_id and entity_entry: - title = entity_entry.name or entity_entry.original_name + if entity_entry.device_id: + device_registry = dr.async_get(self.hass) + device_entry = device_registry.async_get(entity_entry.device_id) + if device_entry: + title = f"{device_entry.name_by_user or device_entry.name} - {entity_entry.name or entity_entry.original_name}" + else: + title = entity_entry.name or entity_entry.original_name + else: + title = entity_entry.name or entity_entry.original_name else: assert device_entry title = device_entry.name_by_user or device_entry.name @@ -732,7 +736,15 @@ async def async_step_battery( if CONF_NAME in self.data: title = self.data.pop(CONF_NAME) elif source_entity_id and entity_entry: - title = entity_entry.name or entity_entry.original_name + if entity_entry.device_id: + device_registry = dr.async_get(self.hass) + device_entry = device_registry.async_get(entity_entry.device_id) + if device_entry: + title = f"{device_entry.name_by_user or device_entry.name} - {entity_entry.name or entity_entry.original_name}" + else: + title = entity_entry.name or entity_entry.original_name + else: + title = entity_entry.name or entity_entry.original_name else: assert device_entry title = device_entry.name_by_user or device_entry.name From 029ac71a6d29eea158a8053e45e662f25b091d0c Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 12:30:40 +0000 Subject: [PATCH 131/235] Refactor assertion syntax for improved readability --- custom_components/battery_notes/config_flow.py | 2 +- custom_components/battery_notes/coordinator.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index fa43d97c0..02df380ab 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -217,7 +217,7 @@ async def async_step_integration_discovery( config_entry = entry break - assert(config_entry is not None) + assert config_entry for existing_subentry in config_entry.subentries.values(): if existing_subentry.unique_id == unique_id: diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index cf94110dc..0a83c65aa 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -133,7 +133,7 @@ def __init__( self.is_orphaned = True return - assert(self.device_name) + assert self.device_name self.battery_type = cast(str, self.subentry.data.get(CONF_BATTERY_TYPE, "")) try: @@ -643,7 +643,7 @@ def last_reported(self, value): if self.source_entity_id: self.async_update_entity_config(entity_id=self.source_entity_id, data=entry) else: - assert(self.device_id) + assert self.device_id self.async_update_device_config(device_id=self.device_id, data=entry) @property @@ -672,7 +672,7 @@ def last_reported_level(self, value: float): if self.source_entity_id: self.async_update_entity_config(entity_id=self.source_entity_id, data=entry) else: - assert(self.device_id) + assert self.device_id self.async_update_device_config(device_id=self.device_id, data=entry) @property From ed50d07cd90e793a9cbaa3eaa482714e9883b462 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 13:07:26 +0000 Subject: [PATCH 132/235] Add hardware version support and clean up imports in battery_notes integration --- custom_components/battery_notes/__init__.py | 17 +++++++---------- custom_components/battery_notes/config_flow.py | 4 ++++ custom_components/battery_notes/const.py | 1 + custom_components/battery_notes/discovery.py | 4 +++- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 1aca31119..3c049f41f 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -13,10 +13,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry -from homeassistant.const import ( - CONF_DEVICE_ID, - EVENT_HOMEASSISTANT_STARTED, -) +from homeassistant.const import CONF_DEVICE_ID, EVENT_HOMEASSISTANT_STARTED from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import Event, HomeAssistant, callback from homeassistant.helpers import config_validation as cv @@ -24,9 +21,7 @@ from homeassistant.helpers import entity_registry as er from homeassistant.helpers import helper_integration from homeassistant.helpers import issue_registry as ir -from homeassistant.helpers.device import ( - async_entity_id_to_device_id, -) +from homeassistant.helpers.device import async_entity_id_to_device_id from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.typing import ConfigType @@ -36,9 +31,11 @@ CONF_BATTERY_QUANTITY, CONF_BATTERY_TYPE, CONF_DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_DEVICE_NAME, CONF_ENABLE_AUTODISCOVERY, CONF_ENABLE_REPLACED, CONF_HIDE_BATTERY, + CONF_HW_VERSION, CONF_MANUFACTURER, CONF_MODEL, CONF_MODEL_ID, @@ -64,9 +61,7 @@ from .discovery import DiscoveryManager from .library_updater import LibraryUpdater from .services import async_setup_services -from .store import ( - async_get_registry, -) +from .store import async_get_registry _LOGGER = logging.getLogger(__name__) @@ -260,9 +255,11 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> # Tidy up data we accidentally added from discovery entry_data_dict = dict(entry.data) + entry_data_dict.pop(CONF_DEVICE_NAME, None) entry_data_dict.pop(CONF_MANUFACTURER, None) entry_data_dict.pop(CONF_MODEL, None) entry_data_dict.pop(CONF_MODEL_ID, None) + entry_data_dict.pop(CONF_HW_VERSION, None) subentry = ConfigSubentry( data=MappingProxyType(entry_data_dict), diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 02df380ab..11626abfb 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -39,6 +39,7 @@ CONF_ENABLE_REPLACED, CONF_FILTER_OUTLIERS, CONF_HIDE_BATTERY, + CONF_HW_VERSION, CONF_MANUFACTURER, CONF_MODEL, CONF_MODEL_ID, @@ -229,6 +230,7 @@ async def async_step_integration_discovery( "manufacturer": discovery_info[CONF_MANUFACTURER], "model": discovery_info[CONF_MODEL], "model_id": discovery_info[CONF_MODEL_ID], + "hw_version": discovery_info[CONF_HW_VERSION], } await self.async_set_unique_id(unique_id) @@ -406,9 +408,11 @@ async def async_step_battery( title = device_entry.name_by_user or device_entry.name # Remove discovery data from data + self.data.pop(CONF_DEVICE_NAME, None) self.data.pop(CONF_MANUFACTURER, None) self.data.pop(CONF_MODEL, None) self.data.pop(CONF_MODEL_ID, None) + self.data.pop(CONF_HW_VERSION, None) config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] # Create a subentry diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 5e81e9f60..3f041166c 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -42,6 +42,7 @@ CONF_USER_LIBRARY = "user_library" CONF_MODEL = "model" CONF_MODEL_ID = "model_id" +CONF_HW_VERSION = "hw_version" CONF_MANUFACTURER = "manufacturer" CONF_DEVICE_NAME = "device_name" CONF_SHOW_ALL_DEVICES = "show_all_devices" diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index dc12953e1..4a23e2321 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -16,6 +16,7 @@ CONF_BATTERY_QUANTITY, CONF_BATTERY_TYPE, CONF_DEVICE_NAME, + CONF_HW_VERSION, CONF_MANUFACTURER, CONF_MODEL, CONF_MODEL_ID, @@ -153,7 +154,8 @@ def _init_entity_discovery( ) discovery_data[CONF_MANUFACTURER] = device_battery_details.manufacturer discovery_data[CONF_MODEL] = device_battery_details.model - discovery_data[CONF_MODEL_ID] = get_device_model_id(device_entry), + discovery_data[CONF_MODEL_ID] = get_device_model_id(device_entry) + discovery_data[CONF_HW_VERSION] = device_battery_details.hw_version discovery_data[CONF_DEVICE_NAME] = get_wrapped_device_name( device_entry.id, device_entry ) From 88818afc42779a880c1fb33361c7c39c8277ad9e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 13:40:38 +0000 Subject: [PATCH 133/235] Update extensions --- .devcontainer/integration/devcontainer.json | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.devcontainer/integration/devcontainer.json b/.devcontainer/integration/devcontainer.json index 746e6c9bc..49407f70f 100644 --- a/.devcontainer/integration/devcontainer.json +++ b/.devcontainer/integration/devcontainer.json @@ -13,14 +13,14 @@ "nodeGypDependencies": true, "version": "lts" }, - "ghcr.io/devcontainers/features/rust:1": {}, + "ghcr.io/devcontainers/features/rust:1": { }, "ghcr.io/devcontainers-extra/features/apt-packages:1": { - "packages": ["ffmpeg", "libturbojpeg0", "libpcap-dev"] + "packages": [ "ffmpeg", "libturbojpeg0", "libpcap-dev" ] } }, "postCreateCommand": "scripts/setup", - "runArgs": ["--network=host"], - "forwardPorts": [8123], + "runArgs": [ "--network=host" ], + "forwardPorts": [ 8123 ], "portsAttributes": { "8123": { "label": "Home Assistant", @@ -30,11 +30,17 @@ "customizations": { "vscode": { "extensions": [ + "charliermarsh.ruff", "ms-python.python", + "ms-python.pylint", + "ms-python.vscode-pylance", "github.vscode-pull-request-github", "ryanluker.vscode-coverage-gutters", - "ms-python.vscode-pylance", - "charliermarsh.ruff" + "visualstudioexptteam.vscodeintellicode", + "redhat.vscode-yaml", + "esbenp.prettier-vscode", + "GitHub.vscode-pull-request-github", + "GitHub.copilot" ], "settings": { "files.eol": "\n", From 3d5b282febec5e4e005d0fbb8966a6a164f98d6f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 14:30:59 +0000 Subject: [PATCH 134/235] Remove unnecessary newline in battery note entry type definition --- custom_components/battery_notes/translations/en.json | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index b1a196a67..1f7db0471 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -35,7 +35,6 @@ "user": "Add battery note" }, "entry_type": "Battery note", - "step": { "user": { "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", From 50938b886eaacba94337592bafd66a9bd809cf79 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 15:03:01 +0000 Subject: [PATCH 135/235] Translations ar, ca --- .../battery_notes/translations/ar.json | 172 +++++++++++++---- .../battery_notes/translations/ca.json | 178 ++++++++++++++---- 2 files changed, 277 insertions(+), 73 deletions(-) diff --git a/custom_components/battery_notes/translations/ar.json b/custom_components/battery_notes/translations/ar.json index 7c78e7886..3eb352098 100644 --- a/custom_components/battery_notes/translations/ar.json +++ b/custom_components/battery_notes/translations/ar.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "إذا كنت بحاجة إلى مساعدة في التكوين، يمكنك الاطلاع على هذا الرابط: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "نوع الارتباط" - }, - "menu_options": { - "device": "الجهاز (مستحسن)", - "entity": "كيان" - }, - "title": "اختر نوع ارتباطك" - }, - "device": { - "data": { - "device_id": "جهاز", - "name": "اسم" - }, - "data_description": { - "name": "اتركه فارغًا سيأخذ الاسم من الجهاز المصدر." - } - }, - "entity": { - "data": { - "source_entity_id": "كيان", - "name": "اسم" - }, - "data_description": { - "name": "اتركه فارغًا سيأخذ الاسم من الكيان المصدر." - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "الصانع: {manufacturer}\nالطراز: {model}\nمعرف الطراز: {model_id}\nإصدار الجهاز: {hw_version}", @@ -44,28 +19,146 @@ "battery_low_template": "القالب لتحديد إذا كانت البطارية منخفضة، يجب أن يُرجع \"صحيح\" إذا كانت منخفضة.\nمطلوب فقط للمستويات غير القياسية للبطارية.", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "تم تحديد هذا الجهاز في المكتبة كجهاز يدوي، حيث تستخدم الإصدارات المختلفة أنواع بطاريات مختلفة ولا يمكن تعيينها في المكتبة.\nالخطوة التالية ستتيح لك تحديد نوع البطارية الخاص بك، ولكن يُرجى عدم تقديم طلب جهاز.", - "title": "التكوين اليدوي للجهاز\n\n\n\n" } }, "abort": { - "already_configured": "تم تكوين الجهاز بالفعل." + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "حدث خطأ غير معروف.", - "unconfigurable_entity": "لا يمكن إضافة هذا الكيان إلى ملاحظات البطارية." + "unknown": "حدث خطأ غير معروف." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "إذا كنت بحاجة إلى مساعدة في التكوين، يمكنك الاطلاع على هذا الرابط: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "نوع الارتباط" + }, + "menu_options": { + "device": "الجهاز (مستحسن)", + "entity": "كيان" + }, + "title": "اختر نوع ارتباطك" + }, + "device": { + "data": { + "device_id": "جهاز", + "name": "اسم" + }, + "data_description": { + "name": "اتركه فارغًا سيأخذ الاسم من الجهاز المصدر." + } + }, + "entity": { + "data": { + "source_entity_id": "كيان", + "name": "اسم" + }, + "data_description": { + "name": "اتركه فارغًا سيأخذ الاسم من الكيان المصدر." + } + }, + "battery": { + "description": "الصانع: {manufacturer}\nالطراز: {model}\nمعرف الطراز: {model_id}\nإصدار الجهاز: {hw_version}", + "data": { + "battery_type": "نوع البطارية", + "battery_quantity": "كَمّيَّة البطارية", + "battery_low_threshold": "عتبة البطارية المنخفضة", + "battery_low_template": "قالب البطارية المنخفضة", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "الصفر سيستخدم العتبة الافتراضية العالمية.", + "battery_low_template": "القالب لتحديد إذا كانت البطارية منخفضة، يجب أن يُرجع \"صحيح\" إذا كانت منخفضة.\nمطلوب فقط للمستويات غير القياسية للبطارية.", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "تم تحديد هذا الجهاز في المكتبة كجهاز يدوي، حيث تستخدم الإصدارات المختلفة أنواع بطاريات مختلفة ولا يمكن تعيينها في المكتبة.\nالخطوة التالية ستتيح لك تحديد نوع البطارية الخاص بك، ولكن يُرجى عدم تقديم طلب جهاز.", + "title": "التكوين اليدوي للجهاز\n\n\n\n" + }, + "reconfigure": { + "description": "الصانع: {manufacturer}\nالطراز: {model}\nمعرف الطراز: {model_id}\nإصدار الجهاز: {hw_version}", + "data": { + "name": "اسم", + "battery_type": "نوع البطارية", + "battery_quantity": "كَمّيَّة البطارية", + "battery_low_threshold": "عتبة البطارية المنخفضة", + "battery_low_template": "قالب البطارية المنخفضة", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "تركه فارغًا سيأخذ الاسم من الجهاز المصدر.", + "battery_low_threshold": "الصفر سيستخدم العتبة الافتراضية العالمية.", + "battery_low_template": "القالب لتحديد إذا كانت البطارية منخفضة، يجب أن يُرجع \"صحيح\" إذا كانت منخفضة.\nمطلوب فقط للمستويات غير القياسية للبطارية.", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "تم تكوين الجهاز بالفعل." + }, + "error": { + "unknown": "حدث خطأ غير معروف.", + "unconfigurable_entity": "لا يمكن إضافة هذا الكيان إلى ملاحظات البطارية.", + "orphaned_battery_note": "الجهاز أو الكيان المرتبط لم يعد موجودًا لهذه الملاحظة الخاصة بالبطارية." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "حدث خطأ غير معروف." + } + }, + "battery_note_options": { "step": { "init": { "description": "الصانع: {manufacturer}\nالطراز: {model}\nمعرف الطراز: {model_id}\nإصدار الجهاز: {hw_version}", "data": { "name": "اسم", "battery_type": "نوع البطارية", - "battery_quantity": "كَمَيَّة البطارية", + "battery_quantity": "كَمّيَّة البطارية", "battery_low_threshold": "عتبة البطارية المنخفضة", "battery_low_template": "قالب البطارية المنخفضة", "filter_outliers": "Filter outliers" @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/ca.json b/custom_components/battery_notes/translations/ca.json index f1a60dfe3..e5c2e78b1 100644 --- a/custom_components/battery_notes/translations/ca.json +++ b/custom_components/battery_notes/translations/ca.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Si necessiteu ajuda amb la configuració, mireu aquí: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Tipus d'associació" - }, - "menu_options": { - "device": "Dispositiu (recomanat)", - "entity": "Entitat" - }, - "title": "Tria el tipus d'associació" - }, - "device": { - "data": { - "device_id": "Dispositiu", - "name": "Nom" - }, - "data_description": { - "name": "Si ho deixes en blanc, agafarà el nom del dispositiu d'origen" - } - }, - "entity": { - "data": { - "source_entity_id": "Entitat", - "name": "Nom" - }, - "data_description": { - "name": "Si ho deixes en blanc, agafarà el nom de l'entitat d'origen" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Fabricant: {manufacturer}\nModel: {model}\nIdentificador del model: {model_id}\nVersió de maquinari: {hw_version}", @@ -45,20 +20,138 @@ "filter_outliers": "Filtra les grans caigudes del nivell de bateria, reduint els esdeveniments que es disparen falsament en els dispositius que informen erròniament dels nivells de manera ocasional." } }, - "manual": { - "description": "Aquest dispositiu està marcat a la biblioteca com a manual, les variants utilitzen diferents tipus de bateries, de manera que no es pot configurar a la biblioteca.\nEl següent pas us permetrà configurar el tipus de bateria, però no envieu cap sol·licitud de dispositiu.", - "title": "Configuració manual del dispositiu" + "abort": { + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" + }, + "error": { + "unknown": "S'ha produït un error desconegut" + } + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Si necessiteu ajuda amb la configuració, mireu aquí: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Tipus d'associació" + }, + "menu_options": { + "device": "Dispositiu (recomanat)", + "entity": "Entitat" + }, + "title": "Tria el tipus d'associació" + }, + "device": { + "data": { + "device_id": "Dispositiu", + "name": "Nom" + }, + "data_description": { + "name": "Si ho deixes en blanc, agafarà el nom del dispositiu d'origen" + } + }, + "entity": { + "data": { + "source_entity_id": "Entitat", + "name": "Nom" + }, + "data_description": { + "name": "Si ho deixes en blanc, agafarà el nom de l'entitat d'origen" + } + }, + "battery": { + "description": "Fabricant: {manufacturer}\nModel: {model}\nIdentificador del model: {model_id}\nVersió de maquinari: {hw_version}", + "data": { + "battery_type": "Tipus de bateria", + "battery_quantity": "Quantitat de bateries", + "battery_low_threshold": "Llindar baix de la bateria", + "battery_low_template": "Plantilla de bateria baixa", + "filter_outliers": "iltrar valors atípics" + }, + "data_description": { + "battery_low_threshold": "0 utilitzarà el llindar predeterminat global", + "battery_low_template": "La plantilla per determinar que la bateria és baixa, hauria de tornar correcte si és baixa\nNomés és necessari per a nivells de bateria no estàndard", + "filter_outliers": "Filtra les grans caigudes del nivell de bateria, reduint els esdeveniments que es disparen falsament en els dispositius que informen erròniament dels nivells de manera ocasional." + } + }, + "manual": { + "description": "Aquest dispositiu està marcat a la biblioteca com a manual, les variants utilitzen diferents tipus de bateries, de manera que no es pot configurar a la biblioteca.\nEl següent pas us permetrà configurar el tipus de bateria, però no envieu cap sol·licitud de dispositiu.", + "title": "Configuració manual del dispositiu" + }, + "reconfigure": { + "description": "Fabricant: {manufacturer}\nModel: {model}\nIdentificador del model: {model_id}\nVersió de maquinari: {hw_version}", + "data": { + "name": "Nom", + "battery_type": "Tipus de bateria", + "battery_quantity": "Quantitat de bateries", + "battery_low_threshold": "Llindar baix de la bateria", + "battery_low_template": "Plantilla de bateria baixa", + "filter_outliers": "iltrar valors atípics" + }, + "data_description": { + "name": "Si ho deixes en blanc, agafarà el nom del dispositiu d'origen", + "battery_low_threshold": "0 utilitzarà el llindar predeterminat global", + "battery_low_template": "La plantilla per determinar que la bateria és baixa, hauria de tornar correcte si és baixa\nNomés és necessari per a nivells de bateria no estàndard", + "filter_outliers": "Filtra les grans caigudes del nivell de bateria, reduint els esdeveniments que es disparen falsament en els dispositius que informen erròniament dels nivells de manera ocasional." + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "El dispositiu ja està configurat" + }, + "error": { + "unknown": "S'ha produït un error desconegut", + "unconfigurable_entity": "No es pot afegir aquesta entitat al Battery Notes ", + "orphaned_battery_note": "El dispositiu o l'entitat associada ja no existeix per a aquesta Battery Note." + } + } + }, + "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } } - }, - "abort": { - "already_configured": "El dispositiu ja està configurat" }, "error": { - "unknown": "S'ha produït un error desconegut", - "unconfigurable_entity": "No es pot afegir aquesta entitat al Battery Notes " + "unknown": "S'ha produït un error desconegut" } }, - "options": { + "battery_note_options": { "step": { "init": { "description": "Fabricant: {manufacturer}\nModel: {model}\nIdentificador del model: {model_id}\nVersió de maquinari: {hw_version}", @@ -79,8 +172,8 @@ } }, "error": { - "orphaned_battery_note": "El dispositiu o l'entitat associada ja no existeix per a aquesta Battery Note.", - "unknown": "S'ha produït un error desconegut" + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", + "unknown": "Unknown error occurred." } }, "entity": { @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 88148a1a4d84f93e7f850044192756f1c9d55482 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 15:22:03 +0000 Subject: [PATCH 136/235] Translate cs --- .../battery_notes/translations/cs.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/cs.json b/custom_components/battery_notes/translations/cs.json index dae37bc46..8e7653ffe 100644 --- a/custom_components/battery_notes/translations/cs.json +++ b/custom_components/battery_notes/translations/cs.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Pokud potřebujete pomoc s konfigurací, podívejte se zde: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Typ přidružení" - }, - "menu_options": { - "device": "Zařízení (doporučeno)", - "entity": "Entita" - }, - "title": "Vyberte typ přidružení" - }, - "device": { - "data": { - "device_id": "Zařízení", - "name": "Název" - }, - "data_description": { - "name": "Ponecháte-li prázdné, převezme název ze zdrojového zařízení" - } - }, - "entity": { - "data": { - "source_entity_id": "Entita", - "name": "Název" - }, - "data_description": { - "name": "Ponecháte-li prázdné, převezme název ze zdrojové entity" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Výrobce: {manufacturer}\nModel: {model}\nID modelu: {model_id}\nHardware verze: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Šablona pro zjištění, zda je baterie vybitá, měla by vracet hodnotu PRAVDA (true), pokud je vybitá.\nPotřebné pouze pro nestandardní úrovně nabití baterie", "filter_outliers": "Filtrovat velké ztráty úrovně baterie, což snižuje falešné spouštění událostí na zařízení, která občas chybně hlásí úrovně" } - }, - "manual": { - "description": "Toto zařízení je v knihovně označeno jako manuální, varianty používají různé typy baterie, takže nemůže být nastaveno v knihovně.\nDalší krok vám umožní nastavit typ baterie, ale prosím nepotvrzujte žádost zařízení.", - "title": "Ruční nastavení zařízení" } }, "abort": { - "already_configured": "Zařízení je již nastaveno" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Vyskytla se neznámá chyba.", - "unconfigurable_entity": "Tuto entitu nelze přidat do Battery Notes." + "unknown": "Vyskytla se neznámá chyba." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Pokud potřebujete pomoc s konfigurací, podívejte se zde: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Typ přidružení" + }, + "menu_options": { + "device": "Zařízení (doporučeno)", + "entity": "Entita" + }, + "title": "Vyberte typ přidružení" + }, + "device": { + "data": { + "device_id": "Zařízení", + "name": "Název" + }, + "data_description": { + "name": "Ponecháte-li prázdné, převezme název ze zdrojového zařízení" + } + }, + "entity": { + "data": { + "source_entity_id": "Entita", + "name": "Název" + }, + "data_description": { + "name": "Ponecháte-li prázdné, převezme název ze zdrojové entity" + } + }, + "battery": { + "description": "Výrobce: {manufacturer}\nModel: {model}\nID modelu: {model_id}\nHardware verze: {hw_version}", + "data": { + "battery_type": "Typ baterie", + "battery_quantity": "Množství baterií", + "battery_low_threshold": "Práh nízkého stavu baterie", + "battery_low_template": "Šablona nízkého stavu baterie", + "filter_outliers": "Filtrovat odlehlé hodnoty" + }, + "data_description": { + "battery_low_threshold": "0 se použije jako globální výchozí práh", + "battery_low_template": "Šablona pro zjištění, zda je baterie vybitá, měla by vracet hodnotu PRAVDA (true), pokud je vybitá.\nPotřebné pouze pro nestandardní úrovně nabití baterie", + "filter_outliers": "Filtrovat velké ztráty úrovně baterie, což snižuje falešné spouštění událostí na zařízení, která občas chybně hlásí úrovně" + } + }, + "manual": { + "description": "Toto zařízení je v knihovně označeno jako manuální, varianty používají různé typy baterie, takže nemůže být nastaveno v knihovně.\nDalší krok vám umožní nastavit typ baterie, ale prosím nepotvrzujte žádost zařízení.", + "title": "Ruční nastavení zařízení" + }, + "reconfigure": { + "description": "Výrobce: {manufacturer}\nModel: {model}\nID modelu: {model_id}\nHardware verze: {hw_version}", + "data": { + "name": "Název", + "battery_type": "Typ baterie", + "battery_quantity": "Množství baterií", + "battery_low_threshold": "Práh nízkého stavu baterie", + "battery_low_template": "Šablona nízkého stavu baterie", + "filter_outliers": "Filtrovat odlehlé hodnoty" + }, + "data_description": { + "name": "Ponecháte-li prázdné, převezme název ze zdrojového zařízení", + "battery_low_threshold": "0 se použije jako globální výchozí práh", + "battery_low_template": "Šablona k určení zda je stav baterie nízký, měla by vrátit hodnotu pravda, pokud je nízký\nJe potřeba pouze pro nestandardní úroveně baterie", + "filter_outliers": "Filtrovat velké ztráty úrovně baterie, což snižuje falešné spouštění událostí na zařízení, která občas chybně hlásí úrovně" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Zařízení je již nastaveno" + }, + "error": { + "unknown": "Vyskytla se neznámá chyba.", + "unconfigurable_entity": "Tuto entitu nelze přidat do Battery Notes.", + "orphaned_battery_note": "Přidružené zařízení nebo entita pro tuto poznámku k baterii již neexistuje." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Vyskytla se neznámá chyba." + } + }, + "battery_note_options": { "step": { "init": { "description": "Výrobce: {manufacturer}\nModel: {model}\nID modelu: {model_id}\nHardware verze: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From adccd92f9798d4f3ff682c56b95382e743848d6b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 15:35:40 +0000 Subject: [PATCH 137/235] Translate da --- .../battery_notes/translations/da.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/da.json b/custom_components/battery_notes/translations/da.json index 0757d16b6..7d352b681 100644 --- a/custom_components/battery_notes/translations/da.json +++ b/custom_components/battery_notes/translations/da.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Hvis du har brug for hjælp til konfigurationen, så kig her: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Association type" - }, - "menu_options": { - "device": "Enhed (anbefales)", - "entity": "Enhed" - }, - "title": "Choose your association type" - }, - "device": { - "data": { - "device_id": "Enhed", - "name": "Navn" - }, - "data_description": { - "name": "Hvis du lader dette felt være tomt, hentes navnet fra kildeenheden" - } - }, - "entity": { - "data": { - "source_entity_id": "Enhed", - "name": "Navn" - }, - "data_description": { - "name": "Hvis du lader stå tomt, tages navnet fra kildeenheden" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Skabelon til at bestemme om et batteri er lavt, skal returnere sand, hvis lavt.\nKun nødvendigt for ikke-standard batteriniveauer", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Manuel konfiguration enheden" } }, "abort": { - "already_configured": "Enheden er allerede konfigureret" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Der opstod en ukendt fejl.", - "unconfigurable_entity": "Det er ikke muligt at tilføje denne enhed til Battery Notes." + "unknown": "Der opstod en ukendt fejl." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Hvis du har brug for hjælp til konfigurationen, så kig her: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Association type" + }, + "menu_options": { + "device": "Enhed (anbefales)", + "entity": "Enhed" + }, + "title": "Choose your association type" + }, + "device": { + "data": { + "device_id": "Enhed", + "name": "Navn" + }, + "data_description": { + "name": "Hvis du lader dette felt være tomt, hentes navnet fra kildeenheden" + } + }, + "entity": { + "data": { + "source_entity_id": "Enhed", + "name": "Navn" + }, + "data_description": { + "name": "Hvis du lader stå tomt, tages navnet fra kildeenheden" + } + }, + "battery": { + "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "Batteri type", + "battery_quantity": "Antal batterier", + "battery_low_threshold": "Lavt batteri niveau", + "battery_low_template": "Batteri lav skabelon", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 vil bruge den globale standardtærskel", + "battery_low_template": "Skabelon til at bestemme om et batteri er lavt, skal returnere sand, hvis lavt.\nKun nødvendigt for ikke-standard batteriniveauer", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Manuel konfiguration enheden" + }, + "reconfigure": { + "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "name": "Navn", + "battery_type": "Batteri type", + "battery_quantity": "Antal batterier", + "battery_low_threshold": "Lavt batteri niveau", + "battery_low_template": "Batteri lav skabelon", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Hvis du lader dette felt være tomt, hentes navnet fra kildeenheden", + "battery_low_threshold": "0 vil bruge den globale standardtærskel", + "battery_low_template": "Skabelon til at bestemme om et batteri er lavt, skal returnere sand, hvis lavt\nKun nødvendigt for ikke-standard batteriniveauer", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Enheden er allerede konfigureret" + }, + "error": { + "unknown": "Der opstod en ukendt fejl.", + "unconfigurable_entity": "Det er ikke muligt at tilføje denne enhed til Battery Notes.", + "orphaned_battery_note": "Den tilknyttede enhed eller enhed eksisterer ikke længere for dette Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Der opstod en ukendt fejl." + } + }, + "battery_note_options": { "step": { "init": { "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 9e3ff43368bb1de6168d5381df8642fd1d0db283 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 15:43:53 +0000 Subject: [PATCH 138/235] Translate de --- .../battery_notes/translations/de.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/de.json b/custom_components/battery_notes/translations/de.json index 7e59c180d..f436e0ff3 100644 --- a/custom_components/battery_notes/translations/de.json +++ b/custom_components/battery_notes/translations/de.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Hilfe zur Konfiguration findest du unter: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Verbindungstyp" - }, - "menu_options": { - "device": "Gerät (empfohlen)", - "entity": "Entität" - }, - "title": "Wählen Sie den Verbindungstyp" - }, - "device": { - "data": { - "device_id": "Gerät", - "name": "Name" - }, - "data_description": { - "name": "Wenn du nichts eingibst, wird der Name vom Quellgerät übernommen" - } - }, - "entity": { - "data": { - "source_entity_id": "Entität", - "name": "Name" - }, - "data_description": { - "name": "Leer lassen wird den Namen von der Quell-Entität übernehmen" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Hersteller: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHardware Version: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Vorlage um zu bestimmen, ob eine Batterie schwach ist; sollte \"wahr\" (true) rückmelden, wenn schwach.\nNur für nicht-Standard Batteriewerte benötigt.", "filter_outliers": "Filtere größere Sprünge des Ladestandes der Batterie bei Geräten, die ihren Ladestand nur sporadisch mitteilen, um fehlerhafte Auslösungen zu verhindern" } - }, - "manual": { - "description": "Dieses Gerät ist in der Bibliothek als \"manuell einzurichten\" gekennzeichnet, verschiedene Varianten verwenden unterschiedliche Batterietypen, so dass es in der Bibliothek nicht eingestellt werden kann.\nIm nächsten Schritt können Sie Ihren Batterietyp einstellen, aber bitte keine Geräteanforderung einreichen.", - "title": "Gerät manuell konfigurieren" } }, "abort": { - "already_configured": "Das Gerät ist bereits konfiguriert." + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Ein unbekannter Fehler ist aufgetreten.", - "unconfigurable_entity": "Es ist nicht möglich, diese Entität zu einem Batteriestatus hinzuzufügen." + "unknown": "Ein unbekannter Fehler ist aufgetreten." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Hilfe zur Konfiguration findest du unter: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Verbindungstyp" + }, + "menu_options": { + "device": "Gerät (empfohlen)", + "entity": "Entität" + }, + "title": "Wählen Sie den Verbindungstyp" + }, + "device": { + "data": { + "device_id": "Gerät", + "name": "Name" + }, + "data_description": { + "name": "Wenn du nichts eingibst, wird der Name vom Quellgerät übernommen" + } + }, + "entity": { + "data": { + "source_entity_id": "Entität", + "name": "Name" + }, + "data_description": { + "name": "Leer lassen wird den Namen von der Quell-Entität übernehmen" + } + }, + "battery": { + "description": "Hersteller: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHardware Version: {hw_version}", + "data": { + "battery_type": "Batterieart", + "battery_quantity": "Batteriemenge", + "battery_low_threshold": "Schwelle für niedrigen Batteriestand", + "battery_low_template": "Vorlage für niedrigen Batteriestand", + "filter_outliers": "Ausreißer filtern" + }, + "data_description": { + "battery_low_threshold": "0 verwendet den globalen Standardschwellenwert", + "battery_low_template": "Vorlage um zu bestimmen, ob eine Batterie schwach ist; sollte \"wahr\" (true) rückmelden, wenn schwach.\nNur für nicht-Standard Batteriewerte benötigt.", + "filter_outliers": "Filtere größere Sprünge des Ladestandes der Batterie bei Geräten, die ihren Ladestand nur sporadisch mitteilen, um fehlerhafte Auslösungen zu verhindern" + } + }, + "manual": { + "description": "Dieses Gerät ist in der Bibliothek als \"manuell einzurichten\" gekennzeichnet, verschiedene Varianten verwenden unterschiedliche Batterietypen, so dass es in der Bibliothek nicht eingestellt werden kann.\nIm nächsten Schritt können Sie Ihren Batterietyp einstellen, aber bitte keine Geräteanforderung einreichen.", + "title": "Gerät manuell konfigurieren" + }, + "reconfigure": { + "description": "Hersteller: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHardware Version: {hw_version}", + "data": { + "name": "Name", + "battery_type": "Batterieart", + "battery_quantity": "Batteriemenge", + "battery_low_threshold": "Schwelle für niedrigen Batteriestand", + "battery_low_template": "Vorlage für niedrigen Batteriestand", + "filter_outliers": "Ausreißer filtern" + }, + "data_description": { + "name": "Wenn du nichts eingibst, wird der Name vom Quellgerät übernommen", + "battery_low_threshold": "0 verwendet den globalen Standardschwellenwert", + "battery_low_template": "Vorlage um zu bestimmen, ob eine Batterie schwach ist; sollte \"wahr\" (true) rückmelden, wenn schwach.\nNur für nicht-Standard Batteriewerte benötigt.", + "filter_outliers": "Filtere größere Sprünge des Ladestandes der Batterie bei Geräten, die ihren Ladestand nur sporadisch mitteilen, um fehlerhafte Auslösungen zu verhindern" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Das Gerät ist bereits konfiguriert." + }, + "error": { + "unknown": "Ein unbekannter Fehler ist aufgetreten.", + "unconfigurable_entity": "Es ist nicht möglich, diese Entität zu einem Batteriestatus hinzuzufügen.", + "orphaned_battery_note": "Das zugeordnete Gerät für diesen Eintrag in \"Battery Notes\" ist nicht mehr verfügbar" + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Ein unbekannter Fehler ist aufgetreten." + } + }, + "battery_note_options": { "step": { "init": { "description": "Hersteller: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHardware Version: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From b4902c9d2060c3c3a59a2743fb489a6010a2bea7 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 16:01:59 +0000 Subject: [PATCH 139/235] Translate el --- .../battery_notes/translations/el.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/el.json b/custom_components/battery_notes/translations/el.json index 6c6248988..3e7e4ad5d 100644 --- a/custom_components/battery_notes/translations/el.json +++ b/custom_components/battery_notes/translations/el.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Αν χρειάζεστε βοήθεια με τις ρυθμίσεις παραμέτρων ρίξτε μια ματιά εδώ: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Τύπος συσχετισμού" - }, - "menu_options": { - "device": "Συσκευή (συνιστάται)", - "entity": "Οντότητα" - }, - "title": "Επιλέξτε τον τύπο συσχέτισης" - }, - "device": { - "data": { - "device_id": "Συσκευή", - "name": "Ονομα" - }, - "data_description": { - "name": "Αφήνοντάς το κενό θα πάρει το όνομα από τη συσκευή προέλευσης" - } - }, - "entity": { - "data": { - "source_entity_id": "Οντότητα", - "name": "Ονομα" - }, - "data_description": { - "name": "Αφήνοντάς το κενό θα πάρει το όνομα από την οντότητα προέλευσης" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Κατασκευαστής: {manufacturer}\nΜοντέλο: {model}\nID Μοντέλου: {model_id}\nΕκδοση υλικού: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Template για τον προσδιορισμό μιας μπαταρίας είναι χαμηλή, θα πρέπει να επιστρέψει true εάν είναι χαμηλή\nΧρειάζεται μόνο για μη τυπικές στάθμες μπαταρίας", "filter_outliers": "Φιλτράρετε μεγάλες πτώσεις στάθμης μπαταρίας, περιορίζοντας την πυροδότηση ψευδών συμβάντων σε συσκευές που εσφαλμένα αναφέρουν επίπεδα περιστασιακά" } - }, - "manual": { - "description": "Αυτή η συσκευή επισημαίνεται στη βιβλιοθήκη ως χειροκίνητη, οι παραλλαγές χρησιμοποιούν διαφορετικούς τύπους μπαταρίας ώστε να μην μπορεί να οριστεί στη βιβλιοθήκη.\nΤο επόμενο βήμα θα σας επιτρέψει να ορίσετε τον τύπο μπαταρίας σας αλλά μην υποβάλετε αίτημα συσκευής.", - "title": "Χειροκίνητη διαμόρφωση συσκευής" } }, "abort": { - "already_configured": "Η συσκευή έχει ήδη ρυθμιστεί" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Προέκυψε άγνωστο σφάλμα.", - "unconfigurable_entity": "Δεν είναι δυνατή η προσθήκη αυτής της οντότητας στο Battery Notes." + "unknown": "Προέκυψε άγνωστο σφάλμα." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Αν χρειάζεστε βοήθεια με τις ρυθμίσεις παραμέτρων ρίξτε μια ματιά εδώ: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Τύπος συσχετισμού" + }, + "menu_options": { + "device": "Συσκευή (συνιστάται)", + "entity": "Οντότητα" + }, + "title": "Επιλέξτε τον τύπο συσχέτισης" + }, + "device": { + "data": { + "device_id": "Συσκευή", + "name": "Ονομα" + }, + "data_description": { + "name": "Αφήνοντάς το κενό θα πάρει το όνομα από τη συσκευή προέλευσης" + } + }, + "entity": { + "data": { + "source_entity_id": "Οντότητα", + "name": "Ονομα" + }, + "data_description": { + "name": "Αφήνοντάς το κενό θα πάρει το όνομα από την οντότητα προέλευσης" + } + }, + "battery": { + "description": "Κατασκευαστής: {manufacturer}\nΜοντέλο: {model}\nID Μοντέλου: {model_id}\nΕκδοση υλικού: {hw_version}", + "data": { + "battery_type": "Τύπος μπαταρίας", + "battery_quantity": "Αριθμός μπαταριών", + "battery_low_threshold": "Ελάχιστο όριο μπαταρίας", + "battery_low_template": "Template χαμηλής στάθμης μπαταρίας", + "filter_outliers": "Φιλτράρισμα ακραίων τιμών" + }, + "data_description": { + "battery_low_threshold": "0 θα χρησιμοποιηθεί το καθολικό προεπιλεγμένο ελάχιστο όριο", + "battery_low_template": "Template για τον προσδιορισμό μιας μπαταρίας είναι χαμηλή, θα πρέπει να επιστρέψει true εάν είναι χαμηλή\nΧρειάζεται μόνο για μη τυπικές στάθμες μπαταρίας", + "filter_outliers": "Φιλτράρετε μεγάλες πτώσεις στάθμης μπαταρίας, περιορίζοντας την πυροδότηση ψευδών συμβάντων σε συσκευές που εσφαλμένα αναφέρουν επίπεδα περιστασιακά" + } + }, + "manual": { + "description": "Αυτή η συσκευή επισημαίνεται στη βιβλιοθήκη ως χειροκίνητη, οι παραλλαγές χρησιμοποιούν διαφορετικούς τύπους μπαταρίας ώστε να μην μπορεί να οριστεί στη βιβλιοθήκη.\nΤο επόμενο βήμα θα σας επιτρέψει να ορίσετε τον τύπο μπαταρίας σας αλλά μην υποβάλετε αίτημα συσκευής.", + "title": "Χειροκίνητη διαμόρφωση συσκευής" + }, + "reconfigure": { + "description": "Κατασκευαστής: {manufacturer}\nΜοντέλο: {model}\nID Μοντέλου: {model_id}\nΕκδοση υλικού: {hw_version}", + "data": { + "name": "Ονομα", + "battery_type": "Τύπος μπαταρίας", + "battery_quantity": "Αριθμός μπαταριών", + "battery_low_threshold": "Ελάχιστο όριο μπαταρίας", + "battery_low_template": "Template χαμηλής στάθμης μπαταρίας", + "filter_outliers": "Φιλτράρισμα ακραίων τιμών" + }, + "data_description": { + "name": "Αφήνοντάς το κενό θα πάρει το όνομα από τη συσκευή προέλευσης", + "battery_low_threshold": "0 θα χρησιμοποιηθεί το καθολικό προεπιλεγμένο ελάχιστο όριο", + "battery_low_template": "Template για τον προσδιορισμό μιας μπαταρίας είναι χαμηλή, θα πρέπει να επιστρέψει true εάν είναι χαμηλή\nΧρειάζεται μόνο για μη τυπικές στάθμες μπαταρίας", + "filter_outliers": "Φιλτράρετε μεγάλες πτώσεις στάθμης μπαταρίας, περιορίζοντας την πυροδότηση ψευδών συμβάντων σε συσκευές που εσφαλμένα αναφέρουν επίπεδα περιστασιακά" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Η συσκευή έχει ήδη ρυθμιστεί" + }, + "error": { + "unknown": "Προέκυψε άγνωστο σφάλμα.", + "unconfigurable_entity": "Δεν είναι δυνατή η προσθήκη αυτής της οντότητας στο Battery Notes.", + "orphaned_battery_note": "Η συσχετιζόμενη συσκευή ή οντότητα δεν υπάρχει πλέον για αυτήν την Σημείωση μπαταρίας." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Προέκυψε άγνωστο σφάλμα." + } + }, + "battery_note_options": { "step": { "init": { "description": "Κατασκευαστής: {manufacturer}\nΜοντέλο: {model}\nID Μοντέλου: {model_id}\nΕκδοση υλικού: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From eeaae160df8071f18be0f759ea9f3abe916b11d4 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 16:15:38 +0000 Subject: [PATCH 140/235] Translate pr-br, es-es --- .../battery_notes/translations/es-ES.json | 170 +++++++++++++---- .../battery_notes/translations/pt-BR.json | 173 ++++++++++++++---- 2 files changed, 275 insertions(+), 68 deletions(-) diff --git a/custom_components/battery_notes/translations/es-ES.json b/custom_components/battery_notes/translations/es-ES.json index 4db4d05a3..0b3b3819f 100644 --- a/custom_components/battery_notes/translations/es-ES.json +++ b/custom_components/battery_notes/translations/es-ES.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Si necesitas ayuda con la configuración, echa un vistazo aquí: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Tipo de asociación" - }, - "menu_options": { - "device": "Dispositivo (recomendado)", - "entity": "Entidad" - }, - "title": "Elija su tipo de asociación" - }, - "device": { - "data": { - "device_id": "Dispositivo", - "name": "Nombre" - }, - "data_description": { - "name": "Dejar en blanco utilizará el nombre del dispositivo de serie" - } - }, - "entity": { - "data": { - "source_entity_id": "Entidad", - "name": "Nombre" - }, - "data_description": { - "name": "Dejar en blanco utilizará el nombre del dispositivo de serie" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Fabricante: {manufacturer}\nModelo: {model}\nID de Modelo: {model_id}\nVersión de Hardware: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Plantilla para determinar que una batería es baja, debe devolver verdadero si es baja\nSolo necesario para niveles de batería no estándar", "filter_outliers": "Filtra las grandes caídas del nivel de batería, reduciendo los eventos que se disparan falsamente en los dispositivos que informan erróneamente de los niveles de forma ocasional." } - }, - "manual": { - "description": "Este dispositivo está marcado en la librería como manual; las variantes usan diferentes tipos de baterías, por lo que no se puede configurar en la librería.\nEl siguiente paso te permitirá configurar tu tipo de batería, pero por favor, no envíes una solicitud de dispositivo.", - "title": "Configuración manual del dispositivo" } }, "abort": { - "already_configured": "Dispositivo ya configurado" + "already_configured": "Dispositivo ya configurado", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Se ha producido un error desconocido.", - "unconfigurable_entity": "No es posible añadir esta entidad a las Notas de la batería." + "unknown": "Se ha producido un error desconocido." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Si necesitas ayuda con la configuración, echa un vistazo aquí: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Tipo de asociación" + }, + "menu_options": { + "device": "Dispositivo (recomendado)", + "entity": "Entidad" + }, + "title": "Elija su tipo de asociación" + }, + "device": { + "data": { + "device_id": "Dispositivo", + "name": "Nombre" + }, + "data_description": { + "name": "Dejar en blanco utilizará el nombre del dispositivo de serie" + } + }, + "entity": { + "data": { + "source_entity_id": "Entidad", + "name": "Nombre" + }, + "data_description": { + "name": "Dejar en blanco utilizará el nombre del dispositivo de serie" + } + }, + "battery": { + "description": "Fabricante: {manufacturer}\nModelo: {model}\nID de Modelo: {model_id}\nVersión de Hardware: {hw_version}", + "data": { + "battery_type": "Tipo de batería", + "battery_quantity": "Cantidad de batería", + "battery_low_threshold": "Umbral bajo de batería", + "battery_low_template": "Plantilla de batería baja", + "filter_outliers": "Filtrar valores atípicos" + }, + "data_description": { + "battery_low_threshold": "0 usará el umbral global por defecto", + "battery_low_template": "Plantilla para determinar que una batería es baja, debe devolver verdadero si es baja\nSolo necesario para niveles de batería no estándar", + "filter_outliers": "Filtra las grandes caídas del nivel de batería, reduciendo los eventos que se disparan falsamente en los dispositivos que informan erróneamente de los niveles de forma ocasional." + } + }, + "manual": { + "description": "Este dispositivo está marcado en la librería como manual; las variantes usan diferentes tipos de baterías, por lo que no se puede configurar en la librería.\nEl siguiente paso te permitirá configurar tu tipo de batería, pero por favor, no envíes una solicitud de dispositivo.", + "title": "Configuración manual del dispositivo" + }, + "reconfigure": { + "description": "Fabricante: {manufacturer}\nModelo: {model}\nID de Modelo: {model_id}\nVersión de Hardware: {hw_version}", + "data": { + "name": "Nombre", + "battery_type": "Tipo de batería", + "battery_quantity": "Cantidad de batería", + "battery_low_threshold": "Umbral bajo de batería", + "battery_low_template": "Plantilla de batería baja", + "filter_outliers": "Filtrar valores atípicos" + }, + "data_description": { + "name": "Dejar en blanco utilizará el nombre del dispositivo de serie", + "battery_low_threshold": "0 usará el umbral global por defecto", + "battery_low_template": "Plantilla para determinar que una batería es baja, debe devolver verdadero si es baja\nSolo necesario para niveles de batería no estándar", + "filter_outliers": "Filtra las grandes caídas del nivel de batería, reduciendo los eventos que se disparan falsamente en los dispositivos que informan erróneamente de los niveles de forma ocasional." + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Dispositivo ya configurado" + }, + "error": { + "unknown": "Se ha producido un error desconocido.", + "unconfigurable_entity": "No es posible añadir esta entidad a las Notas de la batería.", + "orphaned_battery_note": "El dispositivo o entidad asociada ya no existe para esta Nota de batería" + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Se ha producido un error desconocido." + } + }, + "battery_note_options": { "step": { "init": { "description": "Fabricante: {manufacturer}\nModelo: {model}\nID de Modelo: {model_id}\nVersión de Hardware: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/pt-BR.json b/custom_components/battery_notes/translations/pt-BR.json index 3ab0abd97..1f7db0471 100644 --- a/custom_components/battery_notes/translations/pt-BR.json +++ b/custom_components/battery_notes/translations/pt-BR.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Association type" - }, - "menu_options": { - "device": "Device (recommended)", - "entity": "Entity" - }, - "title": "Choose your association type" - }, - "device": { - "data": { - "device_id": "Device", - "name": "Name" - }, - "data_description": { - "name": "Leaving blank will take the name from the source device" - } - }, - "entity": { - "data": { - "source_entity_id": "Entity", - "name": "Name" - }, - "data_description": { - "name": "Leaving blank will take the name from the source entity" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" } }, "abort": { - "already_configured": "Device is already configured" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Unknown error occurred.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." + "unknown": "Unknown error occurred." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Association type" + }, + "menu_options": { + "device": "Device (recommended)", + "entity": "Entity" + }, + "title": "Choose your association type" + }, + "device": { + "data": { + "device_id": "Device", + "name": "Name" + }, + "data_description": { + "name": "Leaving blank will take the name from the source device" + } + }, + "entity": { + "data": { + "source_entity_id": "Entity", + "name": "Name" + }, + "data_description": { + "name": "Leaving blank will take the name from the source entity" + } + }, + "battery": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "Battery type", + "battery_quantity": "Battery quantity", + "battery_low_threshold": "Battery low threshold", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 will use the global default threshold", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Device manual configuration" + }, + "reconfigure": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "name": "Name", + "battery_type": "Battery type", + "battery_quantity": "Battery quantity", + "battery_low_threshold": "Battery low threshold", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Leaving blank will take the name from the source device", + "battery_low_threshold": "0 will use the global default threshold", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Device is already configured" + }, + "error": { + "unknown": "Unknown error occurred.", + "unconfigurable_entity": "It is not possible to add this entity to Battery Notes.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Unknown error occurred." + } + }, + "battery_note_options": { "step": { "init": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -92,6 +185,9 @@ "name": "Battery low threshold" } } + }, + "battery_outliers_filtered": { + "name": "Battery outliers filtered" } }, "button": { @@ -199,6 +295,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From e1a4cf6195ff0b5b1f5c630867946c9196ae94d6 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 16:20:59 +0000 Subject: [PATCH 141/235] Transalte fi --- .../battery_notes/translations/fi.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/fi.json b/custom_components/battery_notes/translations/fi.json index d823695d2..ba06e0f57 100644 --- a/custom_components/battery_notes/translations/fi.json +++ b/custom_components/battery_notes/translations/fi.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Jos tarvitset apua asetuksissa, katso täältä: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Association type" - }, - "menu_options": { - "device": "Laite (suositeltu)", - "entity": "Entiteetti" - }, - "title": "Choose your association type" - }, - "device": { - "data": { - "device_id": "Laite", - "name": "Nimi" - }, - "data_description": { - "name": "Tyhjäksi jättäminen ottaa nimen lähdelaitteesta" - } - }, - "entity": { - "data": { - "source_entity_id": "Entiteetti", - "name": "Nimi" - }, - "data_description": { - "name": "Tyhjäksi jättäminen ottaa nimen lähde entiteetistä" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" } }, "abort": { - "already_configured": "Laite on jo määritelty" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Tuntematon virhe.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." + "unknown": "Tuntematon virhe." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Jos tarvitset apua asetuksissa, katso täältä: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Association type" + }, + "menu_options": { + "device": "Laite (suositeltu)", + "entity": "Entiteetti" + }, + "title": "Choose your association type" + }, + "device": { + "data": { + "device_id": "Laite", + "name": "Nimi" + }, + "data_description": { + "name": "Tyhjäksi jättäminen ottaa nimen lähdelaitteesta" + } + }, + "entity": { + "data": { + "source_entity_id": "Entiteetti", + "name": "Nimi" + }, + "data_description": { + "name": "Tyhjäksi jättäminen ottaa nimen lähde entiteetistä" + } + }, + "battery": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "Akun tyyppi", + "battery_quantity": "Akkujen määrä", + "battery_low_threshold": "Akun alhainen raja", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 käyttää yleistä oletusarvoa", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Device manual configuration" + }, + "reconfigure": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "name": "Nimi", + "battery_type": "Akun tyyppi", + "battery_quantity": "Akkujen määrä", + "battery_low_threshold": "Akun alhainen raja", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Tyhjäksi jättäminen ottaa nimen lähdelaitteesta", + "battery_low_threshold": "0 käyttää yleistä oletusarvoa", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Laite on jo määritelty" + }, + "error": { + "unknown": "Tuntematon virhe.", + "unconfigurable_entity": "It is not possible to add this entity to Battery Notes.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Tuntematon virhe." + } + }, + "battery_note_options": { "step": { "init": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 423b668250d518b503fc8eae0562142aad46b354 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 16:31:52 +0000 Subject: [PATCH 142/235] Translate fr --- .../battery_notes/translations/fr.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/fr.json b/custom_components/battery_notes/translations/fr.json index be8401481..5bc273dde 100644 --- a/custom_components/battery_notes/translations/fr.json +++ b/custom_components/battery_notes/translations/fr.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Si vous avez besoin d'aide pour la configuration, regardez ici : https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Type d'association:" - }, - "menu_options": { - "device": "Appareil (recommandé)", - "entity": "Entité" - }, - "title": "Choisissez votre type d'association" - }, - "device": { - "data": { - "device_id": "Appareil", - "name": "Nom" - }, - "data_description": { - "name": "Le nom par défaut sera utilisé si laissé vide" - } - }, - "entity": { - "data": { - "source_entity_id": "Entité", - "name": "Nom" - }, - "data_description": { - "name": "Le nom de l'entité sera utilisé si laissé vide" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Fabricant : {manufacturer}\nModèle : {model}\nID modèle : {model_id}\nVersion du matériel : {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Modèle pour déterminer si une batterie est faible, devrait retourner vrai si faible\nNécessaire uniquement pour les niveaux de batterie non standard", "filter_outliers": "Filtrer les baisses importantes du niveau de batterie, pour réduire les événements faussement déclenchés par les appareils qui signalent occasionnellement des niveaux erronés" } - }, - "manual": { - "description": "Cet appareil est marqué dans la bibliothèque comme manuel, les variantes utilisent des types de batterie différents, il ne peut donc pas être défini dans la bibliothèque.\nL'étape suivante vous permettra de définir votre type de batterie, mais veuillez ne pas soumettre de demande d'appareil.", - "title": "Configuration manuelle de l'appareil" } }, "abort": { - "already_configured": "L'entité est deja configurée" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Erreur inconnue.", - "unconfigurable_entity": "Il n'est pas possible d'ajouter cette entité à Battery Notes." + "unknown": "Erreur inconnue." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Si vous avez besoin d'aide pour la configuration, regardez ici : https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Type d'association:" + }, + "menu_options": { + "device": "Appareil (recommandé)", + "entity": "Entité" + }, + "title": "Choisissez votre type d'association" + }, + "device": { + "data": { + "device_id": "Appareil", + "name": "Nom" + }, + "data_description": { + "name": "Le nom par défaut sera utilisé si laissé vide" + } + }, + "entity": { + "data": { + "source_entity_id": "Entité", + "name": "Nom" + }, + "data_description": { + "name": "Le nom de l'entité sera utilisé si laissé vide" + } + }, + "battery": { + "description": "Fabricant : {manufacturer}\nModèle : {model}\nID modèle : {model_id}\nVersion du matériel : {hw_version}", + "data": { + "battery_type": "Type de batterie", + "battery_quantity": "Nombre de batteries", + "battery_low_threshold": "Seuil de batterie faible", + "battery_low_template": "Modèle de batterie faible", + "filter_outliers": "Filtrer les valeurs aberrantes" + }, + "data_description": { + "battery_low_threshold": "0 gardera le seuil par defaut", + "battery_low_template": "Modèle pour déterminer si une batterie est faible, devrait retourner vrai si faible\nNécessaire uniquement pour les niveaux de batterie non standard", + "filter_outliers": "Filtrer les baisses importantes du niveau de batterie, pour réduire les événements faussement déclenchés par les appareils qui signalent occasionnellement des niveaux erronés" + } + }, + "manual": { + "description": "Cet appareil est marqué dans la bibliothèque comme manuel, les variantes utilisent des types de batterie différents, il ne peut donc pas être défini dans la bibliothèque.\nL'étape suivante vous permettra de définir votre type de batterie, mais veuillez ne pas soumettre de demande d'appareil.", + "title": "Configuration manuelle de l'appareil" + }, + "reconfigure": { + "description": "Fabricant : {manufacturer}\nModèle : {model}\nID modèle : {model_id}\nVersion du matériel : {hw_version}", + "data": { + "name": "Nom", + "battery_type": "Type de batterie", + "battery_quantity": "Nombre de batteries", + "battery_low_threshold": "Seuil de batterie faible", + "battery_low_template": "Modèle de batterie faible", + "filter_outliers": "Filtrer les valeurs aberrantes" + }, + "data_description": { + "name": "Laisser vide gardera le seuil par defaut", + "battery_low_threshold": "0 gardera le seuil par defaut", + "battery_low_template": "Modèle pour déterminer si une batterie est faible, devrait retourner vrai si faible\nNécessaire uniquement pour les niveaux de batterie non standard", + "filter_outliers": "Filtrer les baisses importantes du niveau de batterie, pour réduire les événements faussement déclenchés par les appareils qui signalent occasionnellement des niveaux erronés" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "L'entité est deja configurée" + }, + "error": { + "unknown": "Erreur inconnue.", + "unconfigurable_entity": "Il n'est pas possible d'ajouter cette entité à Battery Notes.", + "orphaned_battery_note": "Le périphérique ou l'entité associée n'existe plus pour cette Note de Batterie." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Erreur inconnue." + } + }, + "battery_note_options": { "step": { "init": { "description": "Fabricant : {manufacturer}\nModèle : {model}\nID modèle : {model_id}\nVersion du matériel : {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 8ed522a3e8a8868b70e250badfee2aeaaa7b8654 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 16:38:28 +0000 Subject: [PATCH 143/235] Translate hu --- .../battery_notes/translations/hu.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/hu.json b/custom_components/battery_notes/translations/hu.json index 28af9d3bf..a7d868fed 100644 --- a/custom_components/battery_notes/translations/hu.json +++ b/custom_components/battery_notes/translations/hu.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Segítség a konfigurációhoz: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Társítás típusa" - }, - "menu_options": { - "device": "Eszköz (javasolt)", - "entity": "Entitás" - }, - "title": "Válaszd ki a társítás típusát" - }, - "device": { - "data": { - "device_id": "Eszköz", - "name": "Név" - }, - "data_description": { - "name": "Üresen hagyva a forráseszköz nevét kapja" - } - }, - "entity": { - "data": { - "source_entity_id": "Entitás", - "name": "Név" - }, - "data_description": { - "name": "Üresen hagyva a forrás entitás nevét kapja" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Gyártó: {manufacturer}\nModell: {model}\nModell azonosító: {model_id}\nHardver verzió: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "A sablon igaz értéket kell adjon, ha az elem nemsokára lemerül\nCsak nem szokványos töltöttségi szint esetén kell megadni", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "Az eszköz különböző típusú elemekkel is használható, így manuálisan kell beállítani az elem típusát.\nA következő lépésben elvégezhető a beállítás, de kérlek, ne küldd be ezt az eszközt nekünk!", - "title": "Eszköz manuális beállítása" } }, "abort": { - "already_configured": "Az eszköz már konfigurálva van" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Ismeretlen hiba lépett fel.", - "unconfigurable_entity": "Ez az entitás nem adható a Battery Noteshoz." + "unknown": "Ismeretlen hiba lépett fel." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Segítség a konfigurációhoz: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Társítás típusa" + }, + "menu_options": { + "device": "Eszköz (javasolt)", + "entity": "Entitás" + }, + "title": "Válaszd ki a társítás típusát" + }, + "device": { + "data": { + "device_id": "Eszköz", + "name": "Név" + }, + "data_description": { + "name": "Üresen hagyva a forráseszköz nevét kapja" + } + }, + "entity": { + "data": { + "source_entity_id": "Entitás", + "name": "Név" + }, + "data_description": { + "name": "Üresen hagyva a forrás entitás nevét kapja" + } + }, + "battery": { + "description": "Gyártó: {manufacturer}\nModell: {model}\nModell azonosító: {model_id}\nHardver verzió: {hw_version}", + "data": { + "battery_type": "Elemtípus", + "battery_quantity": "Elem darabszám", + "battery_low_threshold": "Alacsony elemszint küszöbérték", + "battery_low_template": "Alacsony elemszint sablon", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 érték esetén a központi beállítást fogja használni", + "battery_low_template": "A sablon igaz értéket kell adjon, ha az elem nemsokára lemerül\nCsak nem szokványos töltöttségi szint esetén kell megadni", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "Az eszköz különböző típusú elemekkel is használható, így manuálisan kell beállítani az elem típusát.\nA következő lépésben elvégezhető a beállítás, de kérlek, ne küldd be ezt az eszközt nekünk!", + "title": "Eszköz manuális beállítása" + }, + "reconfigure": { + "description": "Gyártó: {manufacturer}\nModell: {model}\nModell azonosító: {model_id}\nHardver verzió: {hw_version}", + "data": { + "name": "Név", + "battery_type": "Elemtípus", + "battery_quantity": "Elem darabszám", + "battery_low_threshold": "Alacsony elemszint küszöbérték", + "battery_low_template": "Alacsony elemszint sablon", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Üresen hagyva a forráseszköz nevét kapja", + "battery_low_threshold": "0 érték esetén a központi beállítást fogja használni", + "battery_low_template": "A sablon igaz értéket kell adjon, ha az elem nemsokára lemerül\nCsak nem szokványos töltöttségi szint esetén kell megadni", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Az eszköz már konfigurálva van" + }, + "error": { + "unknown": "Ismeretlen hiba lépett fel.", + "unconfigurable_entity": "Ez az entitás nem adható a Battery Noteshoz.", + "orphaned_battery_note": "Az ehhez a Battery Note-hoz társított eszköz vagy entitás már nem létezik." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Ismeretlen hiba lépett fel." + } + }, + "battery_note_options": { "step": { "init": { "description": "Gyártó: {manufacturer}\nModell: {model}\nModell azonosító: {model_id}\nHardver verzió: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 3f2ec445c8e99e4a32e541a21206e4573654b9d1 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 16:45:35 +0000 Subject: [PATCH 144/235] Translate it --- .../battery_notes/translations/it.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/it.json b/custom_components/battery_notes/translations/it.json index 91fabea66..d5b6817da 100644 --- a/custom_components/battery_notes/translations/it.json +++ b/custom_components/battery_notes/translations/it.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Se hai bisogno di aiuto per la configurazione, dai un'occhiata qui: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Tipo di associazione" - }, - "menu_options": { - "device": "Dispositivo (consigliato)", - "entity": "Entità" - }, - "title": "Scegli il tipo di associazione" - }, - "device": { - "data": { - "device_id": "Dispositivo", - "name": "Nome" - }, - "data_description": { - "name": "Lasciando vuoto prenderà il nome dal dispositivo di origine" - } - }, - "entity": { - "data": { - "source_entity_id": "Entità", - "name": "Nome" - }, - "data_description": { - "name": "Lasciando vuoto prenderà il nome dall'entità di origine" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Produttore: {manufacturer}\nModello: {model}\nID Modello: {model_id}\nVersione hardware: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Modello per determinare se una batteria è scarica, dovrebbe restituire vero se scarica. \nNecessario solo per livelli di batteria non standard", "filter_outliers": "Filtra grossi cali batteria, riducendo falsi eventi su dispositivi che restituiscono occasionalmente livelli erronei" } - }, - "manual": { - "description": "Questo dispositivo è contrassegnato nella libreria come manuale, le varianti usano diversi tipi di batteria per cui non può essere impostato nella libreria.\nIl passo successivo ti permetterà di scegliere il tipo di batteria, non inviare una richiesta di dispositivo per favore.", - "title": "Configurazione manuale del dispositivo" } }, "abort": { - "already_configured": "Il dispositivo è già configurato" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Errore sconosciuto.", - "unconfigurable_entity": "Non è possibile aggiungere questa entità a Battery Notes." + "unknown": "Unknown error occurred." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Se hai bisogno di aiuto per la configurazione, dai un'occhiata qui: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Tipo di associazione" + }, + "menu_options": { + "device": "Dispositivo (consigliato)", + "entity": "Entità" + }, + "title": "Scegli il tipo di associazione" + }, + "device": { + "data": { + "device_id": "Dispositivo", + "name": "Nome" + }, + "data_description": { + "name": "Lasciando vuoto prenderà il nome dal dispositivo di origine" + } + }, + "entity": { + "data": { + "source_entity_id": "Entità", + "name": "Nome" + }, + "data_description": { + "name": "Lasciando vuoto prenderà il nome dall'entità di origine" + } + }, + "battery": { + "description": "Produttore: {manufacturer}\nModello: {model}\nID Modello: {model_id}\nVersione hardware: {hw_version}", + "data": { + "battery_type": "Tipo di batteria", + "battery_quantity": "Quantità batteria", + "battery_low_threshold": "Livello batteria bassa", + "battery_low_template": "Modello batteria bassa", + "filter_outliers": "Filtra anomali" + }, + "data_description": { + "battery_low_threshold": "0 utilizzerà la soglia globale predefinita", + "battery_low_template": "Modello per determinare se una batteria è scarica, dovrebbe restituire vero se scarica. \nNecessario solo per livelli di batteria non standard", + "filter_outliers": "Filtra grossi cali batteria, riducendo falsi eventi su dispositivi che restituiscono occasionalmente livelli erronei" + } + }, + "manual": { + "description": "Questo dispositivo è contrassegnato nella libreria come manuale, le varianti usano diversi tipi di batteria per cui non può essere impostato nella libreria.\nIl passo successivo ti permetterà di scegliere il tipo di batteria, non inviare una richiesta di dispositivo per favore.", + "title": "Configurazione manuale del dispositivo" + }, + "reconfigure": { + "description": "Produttore: {manufacturer}\nModello: {model}\nID Modello: {model_id}\nVersione hardware: {hw_version}", + "data": { + "name": "Nome", + "battery_type": "Tipo di batteria", + "battery_quantity": "Quantità batteria", + "battery_low_threshold": "Livello batteria bassa", + "battery_low_template": "Modello batteria bassa", + "filter_outliers": "Filtra anomali" + }, + "data_description": { + "name": "Lasciando vuoto prenderà il nome dal dispositivo di origine", + "battery_low_threshold": "0 utilizzerà la soglia globale predefinita", + "battery_low_template": "Modello per determinare se una batteria è scarica, dovrebbe restituire vero se scarica. \nNecessario solo per livelli di batteria non standard", + "filter_outliers": "Filtra grossi cali batteria, riducendo falsi eventi su dispositivi che restituiscono occasionalmente livelli erronei" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Il dispositivo è già configurato" + }, + "error": { + "unknown": "Errore sconosciuto.", + "unconfigurable_entity": "Non è possibile aggiungere questa entità a Battery Notes.", + "orphaned_battery_note": "L'entità o dispositivo associato non esiste più per questo Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Errore sconosciuto." + } + }, + "battery_note_options": { "step": { "init": { "description": "Produttore: {manufacturer}\nModello: {model}\nID Modello: {model_id}\nVersione hardware: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From d4c6a20ed179464f4c6bb47b4925ade61044db35 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 16:50:06 +0000 Subject: [PATCH 145/235] Translate lt --- .../battery_notes/translations/lt.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/lt.json b/custom_components/battery_notes/translations/lt.json index 1466fd31d..d529469f1 100644 --- a/custom_components/battery_notes/translations/lt.json +++ b/custom_components/battery_notes/translations/lt.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Daugiau pagalbos apie konfigūraciją rasite čia: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Association type" - }, - "menu_options": { - "device": "Device (recommended)", - "entity": "Entity" - }, - "title": "Choose your association type" - }, - "device": { - "data": { - "device_id": "Prietaisas", - "name": "Pavadinimas" - }, - "data_description": { - "name": "Leaving blank will take the name from the source device" - } - }, - "entity": { - "data": { - "source_entity_id": "Entity", - "name": "Pavadinimas" - }, - "data_description": { - "name": "Leaving blank will take the name from the source entity" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" } }, "abort": { - "already_configured": "Prietaisas jau sukonfigūruotas" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Įvyko nežinoma klaida.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." + "unknown": "Įvyko nežinoma klaida." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Daugiau pagalbos apie konfigūraciją rasite čia: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Association type" + }, + "menu_options": { + "device": "Device (recommended)", + "entity": "Entity" + }, + "title": "Choose your association type" + }, + "device": { + "data": { + "device_id": "Prietaisas", + "name": "Pavadinimas" + }, + "data_description": { + "name": "Leaving blank will take the name from the source device" + } + }, + "entity": { + "data": { + "source_entity_id": "Entity", + "name": "Pavadinimas" + }, + "data_description": { + "name": "Leaving blank will take the name from the source entity" + } + }, + "battery": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "Baterijos tipas", + "battery_quantity": "Baterijų kiekis", + "battery_low_threshold": "Battery low threshold", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "Įrašius 0 bus naudojama numatytoji vertė", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Device manual configuration" + }, + "reconfigure": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "name": "Pavadinimas", + "battery_type": "Baterijos tipas", + "battery_quantity": "Baterijų kiekis", + "battery_low_threshold": "Battery low threshold", + "battery_low_template": "Battery low template", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Leaving blank will take the name from the source device", + "battery_low_threshold": "Įrašius 0 bus naudojama numatytoji vertė", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Prietaisas jau sukonfigūruotas" + }, + "error": { + "unknown": "Įvyko nežinoma klaida.", + "unconfigurable_entity": "It is not possible to add this entity to Battery Notes.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Įvyko nežinoma klaida." + } + }, + "battery_note_options": { "step": { "init": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 4b30d9158119adefa1f4d849cf72d150117248e4 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 16:55:28 +0000 Subject: [PATCH 146/235] Translate lv --- .../battery_notes/translations/lv.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/lv.json b/custom_components/battery_notes/translations/lv.json index 2804fda1e..0cc38ae11 100644 --- a/custom_components/battery_notes/translations/lv.json +++ b/custom_components/battery_notes/translations/lv.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Ja nepieciešama konfigurēšanas palīdzība, papildus informāciju var iegūt šeit: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Asociācijas veids" - }, - "menu_options": { - "device": "Ierīce (ieteicams)", - "entity": "Vienība" - }, - "title": "Norādiet asociācijas veidu" - }, - "device": { - "data": { - "device_id": "Ierīce", - "name": "Nosaukums" - }, - "data_description": { - "name": "Atstājot tukšu tiks ņemts nosaukums no pamata ierīces" - } - }, - "entity": { - "data": { - "source_entity_id": "Vienība", - "name": "Nosaukums" - }, - "data_description": { - "name": "Atstājot tukšu tiks ņemts nosaukums no pamata vienības" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Ražotājs: {manufacturer}\nModelis: {model}\nModeļa ID: {model_id}\nAparatūras versija: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Šablons lai noteiktu zemu baterijas līmeni, kam jāatgriež patiesa vērtība, līmenis ir zems\nNepieciešams tikai nestandarta bateriju līmeņiem", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "Iekārta bibliotekā ir atzīmēta kā manuāla, kas nozīmē, ka šīs ierīces paveidi izmanto dažādus bateriju tipus.\nNākošājā solī norādiet kādu bateriju tipu ierīce izmanto. ", - "title": "Ierīces manuāla konfigurācija" } }, "abort": { - "already_configured": "Ierīce jau ir konfigurēta" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Notika nezināma kļūda.", - "unconfigurable_entity": "Nav iespējams pievienot šo vienību baterijas piezīmēm." + "unknown": "Notika nezināma kļūda." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Ja nepieciešama konfigurēšanas palīdzība, papildus informāciju var iegūt šeit: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Asociācijas veids" + }, + "menu_options": { + "device": "Ierīce (ieteicams)", + "entity": "Vienība" + }, + "title": "Norādiet asociācijas veidu" + }, + "device": { + "data": { + "device_id": "Ierīce", + "name": "Nosaukums" + }, + "data_description": { + "name": "Atstājot tukšu tiks ņemts nosaukums no pamata ierīces" + } + }, + "entity": { + "data": { + "source_entity_id": "Vienība", + "name": "Nosaukums" + }, + "data_description": { + "name": "Atstājot tukšu tiks ņemts nosaukums no pamata vienības" + } + }, + "battery": { + "description": "Ražotājs: {manufacturer}\nModelis: {model}\nModeļa ID: {model_id}\nAparatūras versija: {hw_version}", + "data": { + "battery_type": "Baterijas tips", + "battery_quantity": "Bateriju daudzums", + "battery_low_threshold": "Zema baterijas līmeņa slieksnis", + "battery_low_template": "Zema baterijas līmeņa šablons", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "Norādiet 0, lai izmantotu noklusēto slieksni", + "battery_low_template": "Šablons lai noteiktu zemu baterijas līmeni, kam jāatgriež patiesa vērtība, līmenis ir zems\nNepieciešams tikai nestandarta bateriju līmeņiem", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "Iekārta bibliotekā ir atzīmēta kā manuāla, kas nozīmē, ka šīs ierīces paveidi izmanto dažādus bateriju tipus.\nNākošājā solī norādiet kādu bateriju tipu ierīce izmanto. ", + "title": "Ierīces manuāla konfigurācija" + }, + "reconfigure": { + "description": "Ražotājs: {manufacturer}\nModelis: {model}\nModeļa ID: {model_id}\nAparatūras versija: {hw_version}", + "data": { + "name": "Nosaukums", + "battery_type": "Baterijas tips", + "battery_quantity": "Bateriju daudzums", + "battery_low_threshold": "Zema baterijas līmeņa slieksnis", + "battery_low_template": "Zema baterijas līmeņa šablons", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Atstājot tukšu tiks ņemts nosaukums no pamata ierīces", + "battery_low_threshold": "Norādiet 0, lai izmantotu noklusēto slieksni", + "battery_low_template": "Šablons lai noteiktu zemu baterijas līmeni, kam jāatgriež patiesa vērtība, līmenis ir zems\nNepieciešams tikai nestandarta bateriju līmeņiem", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Ierīce jau ir konfigurēta" + }, + "error": { + "unknown": "Notika nezināma kļūda.", + "unconfigurable_entity": "Nav iespējams pievienot šo vienību baterijas piezīmēm.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Notika nezināma kļūda." + } + }, + "battery_note_options": { "step": { "init": { "description": "Ražotājs: {manufacturer}\nModelis: {model}\nModeļa ID: {model_id}\nAparatūras versija: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 793842c43d08d76daaf2ff4cac1de3493241b2d0 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 17:00:09 +0000 Subject: [PATCH 147/235] Translate zh-Hant --- .../battery_notes/translations/zh-Hant.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/zh-Hant.json b/custom_components/battery_notes/translations/zh-Hant.json index b0930d902..b7616b64b 100644 --- a/custom_components/battery_notes/translations/zh-Hant.json +++ b/custom_components/battery_notes/translations/zh-Hant.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "若在設定過程中有任何疑問,請參考: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "關聯類型" - }, - "menu_options": { - "device": "裝置(建議)", - "entity": "實體" - }, - "title": "選擇關聯類型" - }, - "device": { - "data": { - "device_id": "裝置", - "name": "名稱" - }, - "data_description": { - "name": "若留空,將使用來源裝置的名稱" - } - }, - "entity": { - "data": { - "source_entity_id": "實體", - "name": "名稱" - }, - "data_description": { - "name": "若留空,將使用來源實體的名稱" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "製造商:{manufacturer}\n型號:{model}\n型號 ID:{model_id}\n硬體版本:{hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "判斷電池是否低電量的模板,若為低電量應回傳 true\n僅在電池電量非標準時需要", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "此裝置在資料庫中被標記為手動設定,不同變體使用不同電池類型,因此無法在資料庫中設定。\n下一步將讓你設定電池類型,但請勿提交裝置請求。", - "title": "裝置手動設定" } }, "abort": { - "already_configured": "裝置已設定過" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "發生未知錯誤。", - "unconfigurable_entity": "無法將此實體新增至 Battery Notes。" + "unknown": "發生未知錯誤。" + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "若在設定過程中有任何疑問,請參考: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "關聯類型" + }, + "menu_options": { + "device": "裝置(建議)", + "entity": "實體" + }, + "title": "選擇關聯類型" + }, + "device": { + "data": { + "device_id": "裝置", + "name": "名稱" + }, + "data_description": { + "name": "若留空,將使用來源裝置的名稱" + } + }, + "entity": { + "data": { + "source_entity_id": "實體", + "name": "名稱" + }, + "data_description": { + "name": "若留空,將使用來源實體的名稱" + } + }, + "battery": { + "description": "製造商:{manufacturer}\n型號:{model}\n型號 ID:{model_id}\n硬體版本:{hw_version}", + "data": { + "battery_type": "電池類型", + "battery_quantity": "電池數量", + "battery_low_threshold": "低電量閾值", + "battery_low_template": "低電量模板", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "若為零,將使用全域預設閾值", + "battery_low_template": "判斷電池是否低電量的模板,若為低電量應回傳 true\n僅在電池電量非標準時需要", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "此裝置在資料庫中被標記為手動設定,不同變體使用不同電池類型,因此無法在資料庫中設定。\n下一步將讓你設定電池類型,但請勿提交裝置請求。", + "title": "裝置手動設定" + }, + "reconfigure": { + "description": "製造商:{manufacturer}\n型號:{model}\n型號 ID:{model_id}\n硬體版本:{hw_version}", + "data": { + "name": "名稱", + "battery_type": "電池類型", + "battery_quantity": "電池數量", + "battery_low_threshold": "低電量閾值", + "battery_low_template": "低電量模板", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "若留空,將使用來源裝置的名稱", + "battery_low_threshold": "若為零,將使用全域預設閾值", + "battery_low_template": "判斷電池是否低電量的模板,若為低電量應回傳 true\n僅在電池電量非標準時需要", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "裝置已設定過" + }, + "error": { + "unknown": "發生未知錯誤。", + "unconfigurable_entity": "無法將此實體新增至 Battery Notes。", + "orphaned_battery_note": "此 Battery Note 的關聯裝置或實體已不存在。" + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "發生未知錯誤。" + } + }, + "battery_note_options": { "step": { "init": { "description": "製造商:{manufacturer}\n型號:{model}\n型號 ID:{model_id}\n硬體版本:{hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From d5f9a022a7eaee109b0b3ff30bb76ba2bce5beb6 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 17:02:05 +0000 Subject: [PATCH 148/235] Update en translation --- custom_components/battery_notes/translations/en.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 1f7db0471..7340fe430 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -185,9 +185,6 @@ "name": "Battery low threshold" } } - }, - "battery_outliers_filtered": { - "name": "Battery outliers filtered" } }, "button": { From 7cc1ff6771eba603c1ffd91237e6d455ba485757 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 17:06:00 +0000 Subject: [PATCH 149/235] Translate zh-Hans --- .../battery_notes/translations/zh-Hans.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/zh-Hans.json b/custom_components/battery_notes/translations/zh-Hans.json index da17b3441..da427ae48 100644 --- a/custom_components/battery_notes/translations/zh-Hans.json +++ b/custom_components/battery_notes/translations/zh-Hans.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "若在设定过程中有任何疑问,请参考: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "关联类型" - }, - "menu_options": { - "device": "装置(推荐)", - "entity": "实体" - }, - "title": "选择关联类型" - }, - "device": { - "data": { - "device_id": "装置", - "name": "名称" - }, - "data_description": { - "name": "若留空,将使用来源装置的名称" - } - }, - "entity": { - "data": { - "source_entity_id": "实体", - "name": "名称" - }, - "data_description": { - "name": "若留空,将使用来源实体的名称" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "制造商:{manufacturer}\n型号:{model}\n型号 ID:{model_id}\n硬件版本:{hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "判断电池是否低电量的模板,若为低电量应回传 true\n仅在电池电量非标准时需要", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "此装置在数据库中被标记为手动设定,不同变体使用不同电池类型,因此无法在数据库中设定。\n下一步将让你设定电池类型,但请勿提交装置请求。", - "title": "装置手动设定" } }, "abort": { - "already_configured": "装置已设定过" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "发生未知错误。", - "unconfigurable_entity": "无法将此实体新增至 Battery Notes。" + "unknown": "发生未知错误。" + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "若在设定过程中有任何疑问,请参考: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "关联类型" + }, + "menu_options": { + "device": "装置(推荐)", + "entity": "实体" + }, + "title": "选择关联类型" + }, + "device": { + "data": { + "device_id": "装置", + "name": "名称" + }, + "data_description": { + "name": "若留空,将使用来源装置的名称" + } + }, + "entity": { + "data": { + "source_entity_id": "实体", + "name": "名称" + }, + "data_description": { + "name": "若留空,将使用来源实体的名称" + } + }, + "battery": { + "description": "制造商:{manufacturer}\n型号:{model}\n型号 ID:{model_id}\n硬件版本:{hw_version}", + "data": { + "battery_type": "电池类型", + "battery_quantity": "电池数量", + "battery_low_threshold": "低电量阈值", + "battery_low_template": "低电量模板", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "若为零,将使用全域默认阈值", + "battery_low_template": "判断电池是否低电量的模板,若为低电量应回传 true\n仅在电池电量非标准时需要", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "此装置在数据库中被标记为手动设定,不同变体使用不同电池类型,因此无法在数据库中设定。\n下一步将让你设定电池类型,但请勿提交装置请求。", + "title": "装置手动设定" + }, + "reconfigure": { + "description": "制造商:{manufacturer}\n型号:{model}\n型号 ID:{model_id}\n硬件版本:{hw_version}", + "data": { + "name": "名称", + "battery_type": "电池类型", + "battery_quantity": "电池数量", + "battery_low_threshold": "低电量阈值", + "battery_low_template": "低电量模板", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "若留空,将使用来源装置的名称", + "battery_low_threshold": "若为零,将使用全域默认阈值", + "battery_low_template": "判断电池是否低电量的模板,若为低电量应回传 true\n仅在电池电量非标准时需要", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "装置已设定过" + }, + "error": { + "unknown": "发生未知错误。", + "unconfigurable_entity": "无法将此实体新增至 Battery Notes。", + "orphaned_battery_note": "此 Battery Note 的关联装置或实体已不存在。" + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "发生未知错误。" + } + }, + "battery_note_options": { "step": { "init": { "description": "制造商:{manufacturer}\n型号:{model}\n型号 ID:{model_id}\n硬件版本:{hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 7d921bd3d7a5a806255ec7135db8c7eab7137bea Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 17:10:01 +0000 Subject: [PATCH 150/235] Translate ur-IN --- .../battery_notes/translations/ur-IN.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/ur-IN.json b/custom_components/battery_notes/translations/ur-IN.json index 3e9aa588e..2364d4da3 100644 --- a/custom_components/battery_notes/translations/ur-IN.json +++ b/custom_components/battery_notes/translations/ur-IN.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "اگر آپ کو ترتیب میں مدد کی ضرورت ہو تو یہاں ایک نظر ڈالیں: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Association type" - }, - "menu_options": { - "device": "Device (recommended)", - "entity": "Entity" - }, - "title": "Choose your association type" - }, - "device": { - "data": { - "device_id": "آلہ", - "name": "نام" - }, - "data_description": { - "name": "خالی چھوڑنے سے نام ماخذ آلہ سے لیا جائے گا۔" - } - }, - "entity": { - "data": { - "source_entity_id": "Entity", - "name": "نام" - }, - "data_description": { - "name": "Leaving blank will take the name from the source entity" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "بیٹری کم ہونے کا تعین کرنے کے لیے ٹیمپلیٹ، کم ہونے کی صورت میں درست ہونا چاہیے\nصرف غیر معیاری بیٹری کی سطح کے لیے ضروری ہے", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" } }, "abort": { - "already_configured": "ڈیوائس پہلے سے ہی ترتیب شدہ ہے۔" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "نامعلوم خرابی پیش آگئی.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." + "unknown": "نامعلوم خرابی پیش آگئی." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "اگر آپ کو ترتیب میں مدد کی ضرورت ہو تو یہاں ایک نظر ڈالیں: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Association type" + }, + "menu_options": { + "device": "Device (recommended)", + "entity": "Entity" + }, + "title": "Choose your association type" + }, + "device": { + "data": { + "device_id": "آلہ", + "name": "نام" + }, + "data_description": { + "name": "خالی چھوڑنے سے نام ماخذ آلہ سے لیا جائے گا۔" + } + }, + "entity": { + "data": { + "source_entity_id": "Entity", + "name": "نام" + }, + "data_description": { + "name": "Leaving blank will take the name from the source entity" + } + }, + "battery": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "بیٹری کی قسم", + "battery_quantity": "بیٹری کی مقدار", + "battery_low_threshold": "بیٹری کی کم حد", + "battery_low_template": "کم بیٹری ٹیمپلیٹ", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 عالمی ڈیفالٹ حد استعمال کرے گا۔", + "battery_low_template": "بیٹری کم ہونے کا تعین کرنے کے لیے ٹیمپلیٹ، کم ہونے کی صورت میں درست ہونا چاہیے\nصرف غیر معیاری بیٹری کی سطح کے لیے ضروری ہے", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Device manual configuration" + }, + "reconfigure": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "name": "نام", + "battery_type": "بیٹری کی قسم", + "battery_quantity": "بیٹری کی مقدار", + "battery_low_threshold": "بیٹری کی کم حد", + "battery_low_template": " کم بیٹری ٹیمپلیٹ ", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "خالی چھوڑنے سے نام ماخذ آلہ سے لیا جائے گا۔", + "battery_low_threshold": "0 عالمی ڈیفالٹ حد استعمال کرے گا۔", + "battery_low_template": "بیٹری کم ہونے کا تعین کرنے کے لیے ٹیمپلیٹ، کم ہونے کی صورت میں درست ہونا چاہیے\nصرف غیر معیاری بیٹری کی سطح کے لیے ضروری ہے", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "ڈیوائس پہلے سے ہی ترتیب شدہ ہے۔" + }, + "error": { + "unknown": "نامعلوم خرابی پیش آگئی.", + "unconfigurable_entity": "It is not possible to add this entity to Battery Notes.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "نامعلوم خرابی پیش آگئی." + } + }, + "battery_note_options": { "step": { "init": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From 57cb94f63be18f31019fb3b6580b8f429349389c Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 17:13:28 +0000 Subject: [PATCH 151/235] Translate uk --- .../battery_notes/translations/uk.json | 170 ++++++++++++++---- 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/custom_components/battery_notes/translations/uk.json b/custom_components/battery_notes/translations/uk.json index e46fe6973..bfe287acc 100644 --- a/custom_components/battery_notes/translations/uk.json +++ b/custom_components/battery_notes/translations/uk.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Якщо вам потрібна допомога з конфігурацією, подивіться тут: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Тип асоціацій" - }, - "menu_options": { - "device": "Пристрій (рекомендовано)", - "entity": "Об'єкт" - }, - "title": "Виберіть тип асоціації" - }, - "device": { - "data": { - "device_id": "Пристрій", - "name": "Назва" - }, - "data_description": { - "name": "Залишаючи незаповненим, буде взяте ім'я з основного пристрою" - } - }, - "entity": { - "data": { - "source_entity_id": "Об'єкт", - "name": "Назва" - }, - "data_description": { - "name": "Залишаючи незаповненим, буде взяте ім'я з основного об'єкта" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Виробник: {manufacturer}\nМодель: {model}\nID моделі: {model_id}\nРевізія: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Шаблон для визначення, коли заряд батареї низький - в такому випадку має повернути \"true\"\nПотрібен тільки для нестандартних рівнів батареї", "filter_outliers": "Відфільтровуйте великі падіння рівня заряду акумулятора, зменшуючи кількість помилкових спрацьовувань на пристроях, які час від часу помилково повідомляють про рівень заряду" } - }, - "manual": { - "description": "Цей пристрій позначено у бібліотеці як налаштований вручну, різні варіанти пристрою використовують різні типи батарей, тому її не можна додати до бібліотеки.\nНаступний крок дозволить встановити тип батареї, але, будь ласка, не надсилайте запит на додання пристрою.", - "title": "Ручне налаштування пристрою" } }, "abort": { - "already_configured": "Пристрій вже налаштовано" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Сталася невідома помилка.", - "unconfigurable_entity": "Неможливо додати цей об'єкт до Battery Notes." + "unknown": "Сталася невідома помилка." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Якщо вам потрібна допомога з конфігурацією, подивіться тут: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Тип асоціацій" + }, + "menu_options": { + "device": "Пристрій (рекомендовано)", + "entity": "Об'єкт" + }, + "title": "Виберіть тип асоціації" + }, + "device": { + "data": { + "device_id": "Пристрій", + "name": "Назва" + }, + "data_description": { + "name": "Залишаючи незаповненим, буде взяте ім'я з основного пристрою" + } + }, + "entity": { + "data": { + "source_entity_id": "Об'єкт", + "name": "Назва" + }, + "data_description": { + "name": "Залишаючи незаповненим, буде взяте ім'я з основного об'єкта" + } + }, + "battery": { + "description": "Виробник: {manufacturer}\nМодель: {model}\nID моделі: {model_id}\nРевізія: {hw_version}", + "data": { + "battery_type": "Тип батареї", + "battery_quantity": "Кількість батарей", + "battery_low_threshold": "Нижній поріг батареї", + "battery_low_template": "Шаблон низького заряду батареї", + "filter_outliers": "Відсіяти сторонні елементи" + }, + "data_description": { + "battery_low_threshold": "0 буде використовувати глобальний поріг за замовчуванням", + "battery_low_template": "Шаблон для визначення, коли заряд батареї низький - в такому випадку має повернути \"true\"\nПотрібен тільки для нестандартних рівнів батареї", + "filter_outliers": "Відфільтровуйте великі падіння рівня заряду акумулятора, зменшуючи кількість помилкових спрацьовувань на пристроях, які час від часу помилково повідомляють про рівень заряду" + } + }, + "manual": { + "description": "Цей пристрій позначено у бібліотеці як налаштований вручну, різні варіанти пристрою використовують різні типи батарей, тому її не можна додати до бібліотеки.\nНаступний крок дозволить встановити тип батареї, але, будь ласка, не надсилайте запит на додання пристрою.", + "title": "Ручне налаштування пристрою" + }, + "reconfigure": { + "description": "Виробник: {manufacturer}\nМодель: {model}\nID моделі: {model_id}\nРевізія: {hw_version}", + "data": { + "name": "Назва", + "battery_type": "Тип батареї", + "battery_quantity": "Кількість батарей", + "battery_low_threshold": "Нижній поріг батареї", + "battery_low_template": "Шаблон низького заряду батареї", + "filter_outliers": "Відсіяти сторонні елементи" + }, + "data_description": { + "name": "Залишаючи незаповненим, буде взяте ім'я з основного пристрою", + "battery_low_threshold": "0 буде використовувати глобальний поріг за замовчуванням", + "battery_low_template": "Шаблон для визначення, коли заряд батареї низький - в такому випадку має повернути \"true\"\nПотрібен тільки для нестандартних рівнів батареї", + "filter_outliers": "Відфільтровуйте великі падіння рівня заряду акумулятора, зменшуючи кількість помилкових спрацьовувань на пристроях, які час від часу помилково повідомляють про рівень заряду" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Пристрій вже налаштовано" + }, + "error": { + "unknown": "Сталася невідома помилка.", + "unconfigurable_entity": "Неможливо додати цей об'єкт до Battery Notes.", + "orphaned_battery_note": "Пов'язаний пристрій або об'єкт більше не існує для Battery Note" + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Сталася невідома помилка." + } + }, + "battery_note_options": { "step": { "init": { "description": "Виробник: {manufacturer}\nМодель: {model}\nID моделі: {model_id}\nРевізія: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From e4077ee85178bb14a9a7918d68cdaf1868832b99 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 18:10:08 +0000 Subject: [PATCH 152/235] Translate remaining --- .../battery_notes/translations/nl.json | 170 +++++++++++++---- .../battery_notes/translations/no.json | 172 ++++++++++++++---- .../battery_notes/translations/pl.json | 168 +++++++++++++---- .../battery_notes/translations/pt.json | 170 +++++++++++++---- .../battery_notes/translations/ru.json | 170 +++++++++++++---- .../battery_notes/translations/sk.json | 170 +++++++++++++---- .../battery_notes/translations/sr-Latn.json | 170 +++++++++++++---- .../battery_notes/translations/sv-SE.json | 170 +++++++++++++---- .../battery_notes/translations/tr.json | 169 +++++++++++++---- 9 files changed, 1222 insertions(+), 307 deletions(-) diff --git a/custom_components/battery_notes/translations/nl.json b/custom_components/battery_notes/translations/nl.json index 5cdd02b40..7314c5102 100644 --- a/custom_components/battery_notes/translations/nl.json +++ b/custom_components/battery_notes/translations/nl.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Als u hulp nodig heeft bij de configuratie kunt u hier een kijkje nemen: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Associatietype" - }, - "menu_options": { - "device": "Apparaat (aanbevolen)", - "entity": "Entiteit" - }, - "title": "Kies uw associatietype" - }, - "device": { - "data": { - "device_id": "Apparaat", - "name": "Naam" - }, - "data_description": { - "name": "Indien dit leeg gelaten wordt dan wordt de naam van het bronapparaat overgenomen" - } - }, - "entity": { - "data": { - "source_entity_id": "Entiteit", - "name": "Naam" - }, - "data_description": { - "name": "Indien dit leeg gelaten wordt dan wordt de naam van de bron entiteit overgenomen" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware versie: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Sjabloon om te bepalen dat een batterij bijna leeg is, zal 'waar' teruggeven als bijna leeg\nAlleen nodig voor niet-standaard batterijniveaus", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "Dit apparaat is in de bibliotheek gemarkeerd als handmatig, varianten gebruiken verschillende batterijtypen zodat het niet kan worden ingesteld in de bibliotheek.\nDe volgende stap staat je toe om je batterijtype in te stellen, maar gelieve geen apparaat verzoek in te dienen.", - "title": "Handmatige configuratie van het toestel" } }, "abort": { - "already_configured": "Apparaat is al geconfigureerd" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Onbekende fout opgetreden.", - "unconfigurable_entity": "Het is niet mogelijk om deze entiteit toe te voegen aan Battery Notes" + "unknown": "Onbekende fout opgetreden." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Als u hulp nodig heeft bij de configuratie kunt u hier een kijkje nemen: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Associatietype" + }, + "menu_options": { + "device": "Apparaat (aanbevolen)", + "entity": "Entiteit" + }, + "title": "Kies uw associatietype" + }, + "device": { + "data": { + "device_id": "Apparaat", + "name": "Naam" + }, + "data_description": { + "name": "Indien dit leeg gelaten wordt dan wordt de naam van het bronapparaat overgenomen" + } + }, + "entity": { + "data": { + "source_entity_id": "Entiteit", + "name": "Naam" + }, + "data_description": { + "name": "Indien dit leeg gelaten wordt dan wordt de naam van de bron entiteit overgenomen" + } + }, + "battery": { + "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware versie: {hw_version}", + "data": { + "battery_type": "Batterij type", + "battery_quantity": "Aantal batterijen", + "battery_low_threshold": "Drempelwaarde batterij bijna leeg", + "battery_low_template": "Sjabloon batterij bijna leeg", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 zal de globale standaard drempelwaarde gebruiken", + "battery_low_template": "Sjabloon om te bepalen dat een batterij bijna leeg is, zal 'waar' teruggeven als bijna leeg\nAlleen nodig voor niet-standaard batterijniveaus", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "Dit apparaat is in de bibliotheek gemarkeerd als handmatig, varianten gebruiken verschillende batterijtypen zodat het niet kan worden ingesteld in de bibliotheek.\nDe volgende stap staat je toe om je batterijtype in te stellen, maar gelieve geen apparaat verzoek in te dienen.", + "title": "Handmatige configuratie van het toestel" + }, + "reconfigure": { + "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware versie: {hw_version}", + "data": { + "name": "Naam", + "battery_type": "Batterij type", + "battery_quantity": "Aantal batterijen", + "battery_low_threshold": "Drempelwaarde batterij bijna leeg", + "battery_low_template": "Sjabloon batterij bijna leeg", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Indien dit leeg gelaten wordt dan wordt de naam van het bronapparaat overgenomen", + "battery_low_threshold": "0 zal de globale standaard drempelwaarde gebruiken", + "battery_low_template": "Sjabloon om te bepalen dat een batterij bijna leeg is, zal 'waar' teruggeven als bijna leeg\nAlleen nodig voor niet-standaard batterijniveaus", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Apparaat is al geconfigureerd" + }, + "error": { + "unknown": "Onbekende fout opgetreden.", + "unconfigurable_entity": "Het is niet mogelijk om deze entiteit toe te voegen aan Battery Notes", + "orphaned_battery_note": "Het gekoppelde apparaat of entiteit bestaat niet meer voor deze Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Onbekende fout opgetreden." + } + }, + "battery_note_options": { "step": { "init": { "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware versie: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/no.json b/custom_components/battery_notes/translations/no.json index 43ddb80a1..7719f23a2 100644 --- a/custom_components/battery_notes/translations/no.json +++ b/custom_components/battery_notes/translations/no.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Hvis du trenger hjelp med konfigurasjonen, kan du se her: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Association type" - }, - "menu_options": { - "device": "Device (recommended)", - "entity": "Entity" - }, - "title": "Choose your association type" - }, - "device": { - "data": { - "device_id": "Device", - "name": "Navn" - }, - "data_description": { - "name": "Lar du det stå tomt, vil ta navnet fra kildeenheten bli brukt" - } - }, - "entity": { - "data": { - "source_entity_id": "Entity", - "name": "Navn" - }, - "data_description": { - "name": "Leaving blank will take the name from the source entity" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Produsent: {manufacturer}\nModel: {model}\nModell-ID: {model_id}\nMaskinvareversjon: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Manuell konfigurasjon for enhet" } }, "abort": { - "already_configured": "Enheten er allerede konfigurert" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "En ukjent feil har oppstått.", - "unconfigurable_entity": "Det er ikke mulig å legge denne enheten til batterinotater." + "unknown": "En ukjent feil har oppstått." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Hvis du trenger hjelp med konfigurasjonen, kan du se her: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Association type" + }, + "menu_options": { + "device": "Device (recommended)", + "entity": "Entity" + }, + "title": "Choose your association type" + }, + "device": { + "data": { + "device_id": "Device", + "name": "Navn" + }, + "data_description": { + "name": "Lar du det stå tomt, vil ta navnet fra kildeenheten bli brukt" + } + }, + "entity": { + "data": { + "source_entity_id": "Entity", + "name": "Navn" + }, + "data_description": { + "name": "Leaving blank will take the name from the source entity" + } + }, + "battery": { + "description": "Produsent: {manufacturer}\nModel: {model}\nModell-ID: {model_id}\nMaskinvareversjon: {hw_version}", + "data": { + "battery_type": "Batteritype", + "battery_quantity": "Antall batterier", + "battery_low_threshold": "Lavt batterinivå-terskel", + "battery_low_template": "Mal for lavt batterinivå", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 will use the global default threshold", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Manuell konfigurasjon for enhet" + }, + "reconfigure": { + "description": "Produsent: {manufacturer}\nModel: {model}\nModell-ID: {model_id}\nMaskinvareversjon: {hw_version}", + "data": { + "name": "Navn", + "battery_type": "Batteritype", + "battery_quantity": "Antall batterier", + "battery_low_threshold": "Lavt batterinivå-terskel", + "battery_low_template": "Mal for lavt batterinivå", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Leaving blank will take the name from the source device", + "battery_low_threshold": "0 will use the global default threshold", + "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Enheten er allerede konfigurert" + }, + "error": { + "unknown": "En ukjent feil har oppstått.", + "unconfigurable_entity": "Det er ikke mulig å legge denne enheten til batterinotater.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "En ukjent feil har oppstått." + } + }, + "battery_note_options": { "step": { "init": { "description": "Produsent: {manufacturer}\nModel: {model}\nModell-ID: {model_id}\nMaskinvareversjon: {hw_version}", @@ -80,7 +173,7 @@ }, "error": { "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Unknown error occurred." + "unknown": "En ukjent feil har oppstått." } }, "entity": { @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/pl.json b/custom_components/battery_notes/translations/pl.json index 38f5e770a..5a3f5cf68 100644 --- a/custom_components/battery_notes/translations/pl.json +++ b/custom_components/battery_notes/translations/pl.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Jeśli potrzebujesz pomocy w konfiguracji, zajrzyj tutaj: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Rodzaj powiązania" - }, - "menu_options": { - "device": "Urządzenie (zalecane)", - "entity": "Encja" - }, - "title": "Wybierz rodzaj powiązania" - }, - "device": { - "data": { - "device_id": "Urządzenie", - "name": "Nazwa" - }, - "data_description": { - "name": "Pozostawienie pustego pola spowoduje pobranie nazwy z urządzenia źródłowego" - } - }, - "entity": { - "data": { - "source_entity_id": "Encja", - "name": "Nazwa" - }, - "data_description": { - "name": "Pozostawienie pustego pola spowoduje pobranie nazwy z encji źródłowej" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Producent: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nWersja sprzętowa: {hw_version}", @@ -44,21 +19,137 @@ "battery_low_template": "Szablon do określenia czy poziom naładowania baterii jest niski, powinien zwrócić wartość true, jeśli poziom jest niski.\nJest wymagany tylko dla niestandardowych raportów poziomu baterii", "filter_outliers": "Filtruj duże spadki poziomu baterii, zmniejszając fałszywe wyzwalanie zdarzeń na urządzeniach, które sporadycznie zgłaszają poziomy baterii" } - }, - "manual": { - "description": "To urządzenie jest oznaczone w bibliotece jako manualne, różne warianty używają różnych typów baterii, więc nie mogą być ustawione z biblioteki.\nNastępny krok pozwoli Ci ustawić typ baterii, ale nie wysyłaj żądania dodania urządzenia do biblioteki.", - "title": "Ręczna konfiguracja urządzenia" } }, "abort": { - "already_configured": "Urządzenie jest już skonfigurowane" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Wystąpił nieznany błąd.", - "unconfigurable_entity": "Nie można dodać tej encji do Battery Notes." + "unknown": "Wystąpił nieznany błąd." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Jeśli potrzebujesz pomocy w konfiguracji, zajrzyj tutaj: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Rodzaj powiązania" + }, + "menu_options": { + "device": "Urządzenie (zalecane)", + "entity": "Encja" + }, + "title": "Wybierz rodzaj powiązania" + }, + "device": { + "data": { + "device_id": "Urządzenie", + "name": "Nazwa" + }, + "data_description": { + "name": "Pozostawienie pustego pola spowoduje pobranie nazwy z urządzenia źródłowego" + } + }, + "entity": { + "data": { + "source_entity_id": "Encja", + "name": "Nazwa" + }, + "data_description": { + "name": "Pozostawienie pustego pola spowoduje pobranie nazwy z encji źródłowej" + } + }, + "battery": { + "description": "Producent: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nWersja sprzętowa: {hw_version}", + "data": { + "battery_type": "Typ baterii", + "battery_quantity": "Liczba baterii", + "battery_low_threshold": "Próg niskiego poziomu baterii", + "battery_low_template": "Szablon niskiego poziomu baterii", + "filter_outliers": "Filtr wartości odstających" + }, + "data_description": { + "battery_low_threshold": "0 użyje globalnego progu domyślnego", + "battery_low_template": "Szablon do określenia czy poziom naładowania baterii jest niski, powinien zwrócić wartość true, jeśli poziom jest niski.\nJest wymagany tylko dla niestandardowych raportów poziomu baterii", + "filter_outliers": "Filtruj duże spadki poziomu baterii, zmniejszając fałszywe wyzwalanie zdarzeń na urządzeniach, które sporadycznie zgłaszają poziomy baterii" + } + }, + "manual": { + "description": "To urządzenie jest oznaczone w bibliotece jako manualne, różne warianty używają różnych typów baterii, więc nie mogą być ustawione z biblioteki.\nNastępny krok pozwoli Ci ustawić typ baterii, ale nie wysyłaj żądania dodania urządzenia do biblioteki.", + "title": "Ręczna konfiguracja urządzenia" + }, + "reconfigure": { + "description": "Producent: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nWersja sprzętowa: {hw_version}", + "data": { + "name": "Nazwa", + "battery_type": "Typ baterii", + "battery_quantity": "Liczba baterii", + "battery_low_threshold": "Próg niskiego poziomu baterii", + "battery_low_template": "Szablon niskiego poziomu baterii", + "filter_outliers": "Filtr wartości odstających" + }, + "data_description": { + "name": "Pozostawienie pustego pola spowoduje pobranie nazwy z urządzenia źródłowego", + "battery_low_threshold": "0 użyje globalnego progu domyślnego", + "battery_low_template": "Szablon do określenia czy poziom naładowania baterii jest niski, powinien zwrócić wartość true, jeśli poziom jest niski.\nJest wymagany tylko dla niestandardowych raportów poziomu baterii", + "filter_outliers": "Filtruj duże spadki poziomu baterii, zmniejszając fałszywe wyzwalanie zdarzeń na urządzeniach, które sporadycznie zgłaszają poziomy baterii" + } + } + }, + "abort": { + "already_configured": "Urządzenie jest już skonfigurowane" + }, + "error": { + "unknown": "Wystąpił nieznany błąd.", + "unconfigurable_entity": "Nie można dodać tej encji do Battery Notes." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Wystąpił nieznany błąd." + } + }, + "battery_note_options": { "step": { "init": { "description": "Producent: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nWersja sprzętowa: {hw_version}", @@ -199,6 +290,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/pt.json b/custom_components/battery_notes/translations/pt.json index 2e5e40256..b89ae14eb 100644 --- a/custom_components/battery_notes/translations/pt.json +++ b/custom_components/battery_notes/translations/pt.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Caso precise se ajude na configuração pode verificar em : https://github.com/andrew-codechimp/ha-battery-notes", - "data": { - "association_type": "Tipo de associação" - }, - "menu_options": { - "device": "Dispositivo (recomendado)", - "entity": "Entidade" - }, - "title": "Escolha o tipo de associação" - }, - "device": { - "data": { - "device_id": "Dispositivo", - "name": "Nome" - }, - "data_description": { - "name": "Deixar em branco fará com que tenha o mesmo nome que o dispositivo de origem" - } - }, - "entity": { - "data": { - "source_entity_id": "Entidade", - "name": "Nome" - }, - "data_description": { - "name": "Deixar em branco fará com que tenha mesmo nome que a entidade de origem" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Fabricante: {manufacturer}\nModelo: {model}\nID do Modelo: {model_id}\nVersão de Hardware: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Template para determinar que a bateria está baixa, deve devolver true se estiver baixa\nÉ somente necessário para níveis de bateria non-standard", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "Este dispositivo está definido como criado manualmente, variantes usam tipos de bateria diferentes, portanto, não pode ser configurado na biblioteca. \n O próximo passo permitirá que defina o tipo de bateria, mas, por favor, não envie um pedido para o dispositivo.", - "title": "Configuração manual do dispositivo" } }, "abort": { - "already_configured": "Dispositivo já configurado" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Erro desconhecido.", - "unconfigurable_entity": "Não é possível adicionar esta entidade ao Battery Notes." + "unknown": "Erro desconhecido." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Caso precise se ajude na configuração pode verificar em : https://github.com/andrew-codechimp/ha-battery-notes", + "data": { + "association_type": "Tipo de associação" + }, + "menu_options": { + "device": "Dispositivo (recomendado)", + "entity": "Entidade" + }, + "title": "Escolha o tipo de associação" + }, + "device": { + "data": { + "device_id": "Dispositivo", + "name": "Nome" + }, + "data_description": { + "name": "Deixar em branco fará com que tenha o mesmo nome que o dispositivo de origem" + } + }, + "entity": { + "data": { + "source_entity_id": "Entidade", + "name": "Nome" + }, + "data_description": { + "name": "Deixar em branco fará com que tenha mesmo nome que a entidade de origem" + } + }, + "battery": { + "description": "Fabricante: {manufacturer}\nModelo: {model}\nID do Modelo: {model_id}\nVersão de Hardware: {hw_version}", + "data": { + "battery_type": "Tipo de bateria", + "battery_quantity": "Quantidade de baterias", + "battery_low_threshold": "Nivel de bateria baixa", + "battery_low_template": "Template de bateria baixa", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 irá ser usado como valor por defeito para definir o descarregada", + "battery_low_template": "Template para determinar que a bateria está baixa, deve devolver true se estiver baixa\nÉ somente necessário para níveis de bateria non-standard", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "Este dispositivo está definido como criado manualmente, variantes usam tipos de bateria diferentes, portanto, não pode ser configurado na biblioteca. \n O próximo passo permitirá que defina o tipo de bateria, mas, por favor, não envie um pedido para o dispositivo.", + "title": "Configuração manual do dispositivo" + }, + "reconfigure": { + "description": "Fabricante: {manufacturer}\nModelo: {model}\nID do Modelo: {model_id}\nVersão de Hardware: {hw_version}", + "data": { + "name": "Nome", + "battery_type": "Tipo de bateria", + "battery_quantity": "Quantidade de baterias", + "battery_low_threshold": "Nivel de bateria baixa", + "battery_low_template": "Template de bateria baixa", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Deixar em branco fará com que tenha mesmo o nome que o dispositivo de origem", + "battery_low_threshold": "0 irá ser usado como valor por defeito para definir o descarregada", + "battery_low_template": "Template para determinar que a bateria está baixa, deve devolver true se estiver baixa\nÉ somente necessário para níveis de bateria non-standard", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Dispositivo já configurado" + }, + "error": { + "unknown": "Erro desconhecido.", + "unconfigurable_entity": "Não é possível adicionar esta entidade ao Battery Notes.", + "orphaned_battery_note": "O dispositivo ou entidade associado não existe mais para esta Nota de Bateria." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Error desconhecido." + } + }, + "battery_note_options": { "step": { "init": { "description": "Fabricante: {manufacturer}\nModelo: {model}\nID do Modelo: {model_id}\nVersão de Hardware: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/ru.json b/custom_components/battery_notes/translations/ru.json index cbbbc3c18..9d782e6dd 100644 --- a/custom_components/battery_notes/translations/ru.json +++ b/custom_components/battery_notes/translations/ru.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Если вам нужна помощь с настройкой, посмотрите здесь: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Тип связи" - }, - "menu_options": { - "device": "Устройство (рекомендуется)", - "entity": "Объект" - }, - "title": "Выберите тип связи" - }, - "device": { - "data": { - "device_id": "Устройство", - "name": "Название" - }, - "data_description": { - "name": "Если оставить пустым, то название будет взято с исходного устройства" - } - }, - "entity": { - "data": { - "source_entity_id": "Объект", - "name": "Название" - }, - "data_description": { - "name": "Если оставить пустым, то название будет взято с исходного устройства" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Производитель: {manufacturer}\nМодель: {model}\nID модели: {model_id}\nРевизия: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Шаблон низкого заряда батареи. В случае низкого заряда должен возвращать true.\nТребуется только для нестандартных уровней заряда батареи.", "filter_outliers": "Отфильтровать скачки заряда, уменьшая ложные срабатывания событий для устройств, которые иногда сообщают заряд батареи с ошибками" } - }, - "manual": { - "description": "Это устройство помечено в библиотеке для настройки вручную, в разных версиях используются различные типы батарей, поэтому оно не может быть настроено автоматически.\nСледующий шаг позволит вам настроить тип батареи. Пожалуйста, не отправляйте запросы на добавление настроек устройства в библиотеку.", - "title": "Ручная настройка устройства" } }, "abort": { - "already_configured": "Устройство уже настроено" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Произошла неизвестная ошибка.", - "unconfigurable_entity": "Невозможно добавить этот элемент в Battery Notes." + "unknown": "Произошла неизвестная ошибка." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Если вам нужна помощь с настройкой, посмотрите здесь: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Тип связи" + }, + "menu_options": { + "device": "Устройство (рекомендуется)", + "entity": "Объект" + }, + "title": "Выберите тип связи" + }, + "device": { + "data": { + "device_id": "Устройство", + "name": "Название" + }, + "data_description": { + "name": "Если оставить пустым, то название будет взято с исходного устройства" + } + }, + "entity": { + "data": { + "source_entity_id": "Объект", + "name": "Название" + }, + "data_description": { + "name": "Если оставить пустым, то название будет взято с исходного устройства" + } + }, + "battery": { + "description": "Производитель: {manufacturer}\nМодель: {model}\nID модели: {model_id}\nРевизия: {hw_version}", + "data": { + "battery_type": "Тип батареи", + "battery_quantity": "Количество батарей", + "battery_low_threshold": "Порог низкого заряда батареи", + "battery_low_template": "Шаблон низкого заряда батареи", + "filter_outliers": "Фильтр скачков заряда" + }, + "data_description": { + "battery_low_threshold": "0 будет использовать общий порог по умолчанию", + "battery_low_template": "Шаблон низкого заряда батареи. В случае низкого заряда должен возвращать true.\nТребуется только для нестандартных уровней заряда батареи.", + "filter_outliers": "Отфильтровать скачки заряда, уменьшая ложные срабатывания событий для устройств, которые иногда сообщают заряд батареи с ошибками" + } + }, + "manual": { + "description": "Это устройство помечено в библиотеке для настройки вручную, в разных версиях используются различные типы батарей, поэтому оно не может быть настроено автоматически.\nСледующий шаг позволит вам настроить тип батареи. Пожалуйста, не отправляйте запросы на добавление настроек устройства в библиотеку.", + "title": "Ручная настройка устройства" + }, + "reconfigure": { + "description": "Производитель: {manufacturer}\nМодель: {model}\nID модели: {model_id}\nРевизия: {hw_version}", + "data": { + "name": "Название", + "battery_type": "Тип батареи", + "battery_quantity": "Количество батарей", + "battery_low_threshold": "Порог низкого заряда батареи", + "battery_low_template": "Шаблон низкого заряда батареи", + "filter_outliers": "Фильтр скачков заряда" + }, + "data_description": { + "name": "Если оставить пустым, то название будет взято с исходного устройства", + "battery_low_threshold": "0 будет использовать общий порог по умолчанию", + "battery_low_template": "Шаблон низкого заряда батареи. В случае низкого заряда должен возвращать true.\nТребуется только для нестандартных уровней заряда батареи.", + "filter_outliers": "Отфильтровать скачки заряда, уменьшая ложные срабатывания событий для устройств, которые иногда сообщают заряд батареи с ошибками" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Устройство уже настроено" + }, + "error": { + "unknown": "Произошла неизвестная ошибка.", + "unconfigurable_entity": "Невозможно добавить этот элемент в Battery Notes.", + "orphaned_battery_note": "Привязанное к этой заметке устройство или объект больше не существует." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Unknown error occurred." + } + }, + "battery_note_options": { "step": { "init": { "description": "Производитель: {manufacturer}\nМодель: {model}\nID модели: {model_id}\nРевизия: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/sk.json b/custom_components/battery_notes/translations/sk.json index 6731e21b0..4728a6221 100644 --- a/custom_components/battery_notes/translations/sk.json +++ b/custom_components/battery_notes/translations/sk.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Ak potrebujete pomoc s konfiguráciou, pozrite sa sem: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Typ asociácie" - }, - "menu_options": { - "device": "Zariadenie (odporúčané)", - "entity": "Entita" - }, - "title": "Vyberte typ asociácie" - }, - "device": { - "data": { - "device_id": "Zariadenie", - "name": "Názov" - }, - "data_description": { - "name": "Ak ponecháte prázdne, názov sa prevezme zo zdrojového zariadenia" - } - }, - "entity": { - "data": { - "source_entity_id": "Entita", - "name": "Názov" - }, - "data_description": { - "name": "Ak ponecháte prázdne, názov sa prevezme zo zdrojovej entity" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Šablóna na určenie nízkej úrovne batérie by mala vrátiť hodnotu Pravda, ak je nízke\nPotrebné iba pri neštandardných úrovniach batérie", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" } }, "abort": { - "already_configured": "Zariadenie je už nakonfigurované" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Vyskytla sa neznáma chyba.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." + "unknown": "Vyskytla sa neznáma chyba." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Ak potrebujete pomoc s konfiguráciou, pozrite sa sem: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Typ asociácie" + }, + "menu_options": { + "device": "Zariadenie (odporúčané)", + "entity": "Entita" + }, + "title": "Vyberte typ asociácie" + }, + "device": { + "data": { + "device_id": "Zariadenie", + "name": "Názov" + }, + "data_description": { + "name": "Ak ponecháte prázdne, názov sa prevezme zo zdrojového zariadenia" + } + }, + "entity": { + "data": { + "source_entity_id": "Entita", + "name": "Názov" + }, + "data_description": { + "name": "Ak ponecháte prázdne, názov sa prevezme zo zdrojovej entity" + } + }, + "battery": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "Typ batérie", + "battery_quantity": "Množstvo batérie", + "battery_low_threshold": "Nízky prah batérie", + "battery_low_template": "Šablóna slabej batérie", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 použije globálny predvolený prah", + "battery_low_template": "Šablóna na určenie nízkej úrovne batérie by mala vrátiť hodnotu Pravda, ak je nízke\nPotrebné iba pri neštandardných úrovniach batérie", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Device manual configuration" + }, + "reconfigure": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "name": "Názov", + "battery_type": "Typ batérie", + "battery_quantity": "Množstvo batérie", + "battery_low_threshold": "Nízky prah batérie", + "battery_low_template": "Šablóna slabej batérie", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Ak ponecháte prázdne, názov sa prevezme zo zdrojového zariadenia", + "battery_low_threshold": "0 použije globálny predvolený prah", + "battery_low_template": "Šablóna na určenie nízkej úrovne batérie by mala vrátiť hodnotu true, ak je nízka\nPotrebné iba pri neštandardných úrovniach batérie", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Zariadenie je už nakonfigurované" + }, + "error": { + "unknown": "Vyskytla sa neznáma chyba.", + "unconfigurable_entity": "It is not possible to add this entity to Battery Notes.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Vyskytla sa neznáma chyba." + } + }, + "battery_note_options": { "step": { "init": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/sr-Latn.json b/custom_components/battery_notes/translations/sr-Latn.json index af0b1d3c6..753ae2ab8 100644 --- a/custom_components/battery_notes/translations/sr-Latn.json +++ b/custom_components/battery_notes/translations/sr-Latn.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Ako vam treba pomoć oko konfiguracije, pogledajte ovde: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Vrsta povezivanja" - }, - "menu_options": { - "device": "Uređaj (preporučeno)", - "entity": "Entitet" - }, - "title": "Odaberite vrstu povezivanja" - }, - "device": { - "data": { - "device_id": "Uređaj", - "name": "Naziv" - }, - "data_description": { - "name": "Ako ostavite prazno, naziv će preuzeti sa izvornog uređaja" - } - }, - "entity": { - "data": { - "source_entity_id": "Entitet", - "name": "Naziv" - }, - "data_description": { - "name": "Ako ostavite prazno, naziv će preuzeti sa izvornog entiteta" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Šablon za određivanje da je baterija prazna, treba da vrati true ako je nizak nivo\nPotrebno samo za nestandardne nivoe baterije", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" } }, "abort": { - "already_configured": "Uređaj je već konfigurisan" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Nepoznata greška se dogodila.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes." + "unknown": "Nepoznata greška se dogodila." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Ako vam treba pomoć oko konfiguracije, pogledajte ovde: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Vrsta povezivanja" + }, + "menu_options": { + "device": "Uređaj (preporučeno)", + "entity": "Entitet" + }, + "title": "Odaberite vrstu povezivanja" + }, + "device": { + "data": { + "device_id": "Uređaj", + "name": "Naziv" + }, + "data_description": { + "name": "Ako ostavite prazno, naziv će preuzeti sa izvornog uređaja" + } + }, + "entity": { + "data": { + "source_entity_id": "Entitet", + "name": "Naziv" + }, + "data_description": { + "name": "Ako ostavite prazno, naziv će preuzeti sa izvornog entiteta" + } + }, + "battery": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "battery_type": "Tip baterije", + "battery_quantity": "Broj baterija", + "battery_low_threshold": "Nizak prag napunjenosti baterije", + "battery_low_template": "Šablon ptazne baterije", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 će koristiti globalni podrazumevani prag", + "battery_low_template": "Šablon za određivanje da je baterija prazna, treba da vrati true ako je nizak nivo\nPotrebno samo za nestandardne nivoe baterije", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", + "title": "Device manual configuration" + }, + "reconfigure": { + "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "data": { + "name": "Naziv", + "battery_type": "Tip baterije", + "battery_quantity": "Broj baterija", + "battery_low_threshold": "Nizak prag napunjenosti baterije", + "battery_low_template": "Šablon prazne baterije", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Ako ostavite prazno, naziv će preuzeti sa izvornog uređaja", + "battery_low_threshold": "0 će koristiti globalni podrazumevani prag", + "battery_low_template": "Šablon za određivanje da je baterija prazna, treba da vrati true ako je nizak nivo\nPotrebno samo za nestandardne nivoe baterije", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Uređaj je već konfigurisan" + }, + "error": { + "unknown": "Nepoznata greška se dogodila.", + "unconfigurable_entity": "It is not possible to add this entity to Battery Notes.", + "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Nepoznata greška se dogodila!" + } + }, + "battery_note_options": { "step": { "init": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/sv-SE.json b/custom_components/battery_notes/translations/sv-SE.json index b6f59dd52..0bd46148d 100644 --- a/custom_components/battery_notes/translations/sv-SE.json +++ b/custom_components/battery_notes/translations/sv-SE.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Om du behöver hjälp med konfigurationen ta en titt här: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "Associationstyp" - }, - "menu_options": { - "device": "Enhet (rekommenderas)", - "entity": "Entitet" - }, - "title": "Välj din associationstyp" - }, - "device": { - "data": { - "device_id": "Enhet", - "name": "Namn" - }, - "data_description": { - "name": "Genom att lämna blankt tas namnet från källenheten. " - } - }, - "entity": { - "data": { - "source_entity_id": "Entitet", - "name": "Namn" - }, - "data_description": { - "name": "Lämnas tom kommer namn tas från källentiteten" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Tillverkare: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHårdvaruversion: {hw_version}", @@ -44,21 +19,139 @@ "battery_low_template": "Template för att bestämma om batteriet är lågt, borde returnera true om lågt.\nEndast nödvändigt för icke-standard batterinivåer.", "filter_outliers": "Filtrera bort stora batterinivåfall för att minska falska händelser på enheter som ibland rapporterar nivåer felaktigt" } - }, - "manual": { - "description": "Enheten är markerad som manuell i registret, varianter använder olika batterityper så den kan därför inte ställas in i registret.\nNästa steg gör att du kan ställa in din batterityp, men skicka inte in någon begäran om tillägg av denna batterienhet till utvecklarna.", - "title": "Manuell konfiguration av enhet" } }, "abort": { - "already_configured": "Enheten är redan konfigurerad. " + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Okänt fel inträffade. ", - "unconfigurable_entity": "Det är inte möjligt att lägga till denna enhet till Battery Notes." + "unknown": "Okänt fel inträffade." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Om du behöver hjälp med konfigurationen ta en titt här: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "Associationstyp" + }, + "menu_options": { + "device": "Enhet (rekommenderas)", + "entity": "Entitet" + }, + "title": "Välj din associationstyp" + }, + "device": { + "data": { + "device_id": "Enhet", + "name": "Namn" + }, + "data_description": { + "name": "Genom att lämna blankt tas namnet från källenheten. " + } + }, + "entity": { + "data": { + "source_entity_id": "Entitet", + "name": "Namn" + }, + "data_description": { + "name": "Lämnas tom kommer namn tas från källentiteten" + } + }, + "battery": { + "description": "Tillverkare: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHårdvaruversion: {hw_version}", + "data": { + "battery_type": "Batterityp", + "battery_quantity": "Antal batterier", + "battery_low_threshold": "Tröskelvärde lågt batteri", + "battery_low_template": "Batteri lågt template", + "filter_outliers": "Filtrera avvikande" + }, + "data_description": { + "battery_low_threshold": "0 kommer att använda det globala standardtröskelvärdet", + "battery_low_template": "Template för att bestämma om batteriet är lågt, borde returnera true om lågt.\nEndast nödvändigt för icke-standard batterinivåer.", + "filter_outliers": "Filtrera bort stora batterinivåfall för att minska falska händelser på enheter som ibland rapporterar nivåer felaktigt" + } + }, + "manual": { + "description": "Enheten är markerad som manuell i registret, varianter använder olika batterityper så den kan därför inte ställas in i registret.\nNästa steg gör att du kan ställa in din batterityp, men skicka inte in någon begäran om tillägg av denna batterienhet till utvecklarna.", + "title": "Manuell konfiguration av enhet" + }, + "reconfigure": { + "description": "Tillverkare: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHårdvaruversion: {hw_version}", + "data": { + "name": "Namn", + "battery_type": "Batterityp", + "battery_quantity": "Antal batterier", + "battery_low_threshold": "Batteri lågt tröskelvärde", + "battery_low_template": "Batteri lågt template", + "filter_outliers": "Filtrera avvikande värden" + }, + "data_description": { + "name": "Genom att lämna blankt tas namnet från källenheten. ", + "battery_low_threshold": "0 kommer att använda den globala standardtröskelvärdet. ", + "battery_low_template": "Template för att bestämma om batteriet är lågt. Ska returnera true om lågt. Behövs endast för icke-standard batterinivåer. ", + "filter_outliers": "Filtrera bort stora batterinivåfall för att minska falska händelser på enheter som ibland rapporterar nivåer felaktigt" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Enheten är redan konfigurerad. " + }, + "error": { + "unknown": "Okänt fel inträffade.", + "unconfigurable_entity": "Det är inte möjligt att lägga till denna enhet till Battery Notes.", + "orphaned_battery_note": "Den associerade enheten eller entiteten finns inte längre för denna Batteri \nNotering ." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Okänt fel inträffade. " + } + }, + "battery_note_options": { "step": { "init": { "description": "Tillverkare: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHårdvaruversion: {hw_version}", @@ -199,6 +292,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file diff --git a/custom_components/battery_notes/translations/tr.json b/custom_components/battery_notes/translations/tr.json index e3abfbe16..1eb769f4d 100644 --- a/custom_components/battery_notes/translations/tr.json +++ b/custom_components/battery_notes/translations/tr.json @@ -2,33 +2,8 @@ "config": { "step": { "user": { - "description": "Yapılandırma ile ilgili yardıma ihtiyacınız varsa buraya bir göz atın: https://andrew-codechimp.github.io/HA-Battery-Notes/", - "data": { - "association_type": "İlişkilendirme türü" - }, - "menu_options": { - "device": "Cihaz (önerilen)", - "entity": "Varlık" - }, - "title": "İlişkilendirme türünü seçin" - }, - "device": { - "data": { - "device_id": "Cihaz", - "name": "İsim" - }, - "data_description": { - "name": "Boş bırakıldığında kaynak cihazın ismi alınır" - } - }, - "entity": { - "data": { - "source_entity_id": "Varlık", - "name": "İsim" - }, - "data_description": { - "name": "Boş bırakıldığında isim kaynak varlıktan alınır" - } + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "title": "Setup Battery Notes" }, "battery": { "description": "Üretici firma: {manufacturer}\nModel: {model}\nModel Kodu: {model_id}\nDonanım sürümü: {hw_version}", @@ -44,21 +19,138 @@ "battery_low_template": "Bir pilin zayıf olduğunu belirleyen şablon, zayıfsa true döndürmelidir\nYalnızca standart olmayan pil seviyeleri için gereklidir", "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" } - }, - "manual": { - "description": "Bu cihaz kütüphanede manuel olarak işaretlenmiştir, varyantlar farklı pil türleri kullanır, bu nedenle kütüphanede ayarlanamaz.\nBir sonraki adım pil türünüzü ayarlamanıza izin verecektir ancak lütfen bir cihaz talebi göndermeyin.", - "title": "Cihaz manuel yapılandırması" } }, "abort": { - "already_configured": "Cihaz zaten yapılandırılmış" + "already_configured": "Integration is already configured", + "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Bilinmeyen bir hata oluştu.", - "unconfigurable_entity": "Bu varlığı Battery Notes'a eklemek mümkün değildir." + "unknown": "Bilinmeyen bir hata oluştu." + } + }, + "config_subentries": { + "battery_note": { + "initiate_flow": { + "user": "Add battery note" + }, + "entry_type": "Battery note", + "step": { + "user": { + "description": "Yapılandırma ile ilgili yardıma ihtiyacınız varsa buraya bir göz atın: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "data": { + "association_type": "İlişkilendirme türü" + }, + "menu_options": { + "device": "Cihaz (önerilen)", + "entity": "Varlık" + }, + "title": "İlişkilendirme türünü seçin" + }, + "device": { + "data": { + "device_id": "Cihaz", + "name": "İsim" + }, + "data_description": { + "name": "Boş bırakıldığında kaynak cihazın ismi alınır" + } + }, + "entity": { + "data": { + "source_entity_id": "Varlık", + "name": "İsim" + }, + "data_description": { + "name": "Boş bırakıldığında isim kaynak varlıktan alınır" + } + }, + "battery": { + "description": "Üretici firma: {manufacturer}\nModel: {model}\nModel Kodu: {model_id}\nDonanım sürümü: {hw_version}", + "data": { + "battery_type": "Pil Türü", + "battery_quantity": "Pil miktarı", + "battery_low_threshold": "Düşük pil eşiği", + "battery_low_template": "Düşük pil şablonu", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "battery_low_threshold": "0 genel varsayılan eşiği kullanacaktır", + "battery_low_template": "Bir pilin zayıf olduğunu belirleyen şablon, zayıfsa true döndürmelidir\nYalnızca standart olmayan pil seviyeleri için gereklidir", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + }, + "manual": { + "description": "Bu cihaz kütüphanede manuel olarak işaretlenmiştir, varyantlar farklı pil türleri kullanır, bu nedenle kütüphanede ayarlanamaz.\nBir sonraki adım pil türünüzü ayarlamanıza izin verecektir ancak lütfen bir cihaz talebi göndermeyin.", + "title": "Cihaz manuel yapılandırması" + }, + "reconfigure": { + "description": "Üretici firma: {manufacturer}\nModel: {model}\nModel kodu: {model_id}\nDonanım sürümü: {hw_version}", + "data": { + "name": "İsim", + "battery_type": "Pil türü", + "battery_quantity": "Pil miktarı", + "battery_low_threshold": "Düşük pil eşiği", + "battery_low_template": "Düşük pil şablonu", + "filter_outliers": "Filter outliers" + }, + "data_description": { + "name": "Boş bırakıldığında kaynak cihazın ismi alınır", + "battery_low_threshold": "0 genel varsayılan eşiği kullanacaktır", + "battery_low_template": "Bir pilin zayıf olduğunu belirleyen şablon, zayıfsa true döndürmelidir\nYalnızca standart olmayan pil seviyeleri için gereklidir", + "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + } + } + }, + "abort": { + "reconfigure_successful": "Re-configuration was successful", + "already_configured": "Cihaz zaten yapılandırılmış" + }, + "error": { + "unknown": "Bilinmeyen bir hata oluştu.", + "unconfigurable_entity": "Bu varlığı Battery Notes'a eklemek mümkün değildir." + } } }, "options": { + "step": { + "init": { + "data": { + "show_all_devices": "Show all devices", + "hide_battery": "Hide battery", + "round_battery": "Round battery", + "default_battery_low_threshold": "Default battery low threshold", + "battery_increase_threshold": "Battery increase threshold" + }, + "data_description": { + "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", + "hide_battery": "Hide the standard battery when adding Battery+.", + "round_battery": "Round battery+ to whole percentages.", + "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", + "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." + }, + "sections": { + "advanced_settings": { + "name": "Advanced settings", + "data": { + "enable_autodiscovery": "Auto discovery", + "enable_replaced": "Enable battery replaced", + "user_library": "User library" + }, + "data_description": { + "enable_autodiscovery": "Auto discovery of devices that are in the library.", + "enable_replaced": "Enable the battery replaced button on each battery note.", + "user_library": "If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in `config/.storage/battery_notes`." + } + } + } + } + }, + "error": { + "unknown": "Bilinmeyen bir hata oluştu." + } + }, + "battery_note_options": { "step": { "init": { "description": "Üretici firma: {manufacturer}\nModel: {model}\nModel kodu: {model_id}\nDonanım sürümü: {hw_version}", @@ -199,6 +291,15 @@ } } } + }, + "deprecated_yaml": { + "title": "The {integration_title} YAML configuration is being removed", + "description": "Configuring {integration_title} using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue." + } + }, + "exceptions": { + "not_configured_in_battery_notes": { + "message": "{source} is not configured in Battery Notes." } } } \ No newline at end of file From ddf9f5c84e165f5a3d6202d64919cd12b1333a36 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 18:15:46 +0000 Subject: [PATCH 153/235] Fix translations --- custom_components/battery_notes/translations/pl.json | 4 +++- custom_components/battery_notes/translations/pt-BR.json | 3 --- custom_components/battery_notes/translations/tr.json | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_components/battery_notes/translations/pl.json b/custom_components/battery_notes/translations/pl.json index 5a3f5cf68..eb9577b1a 100644 --- a/custom_components/battery_notes/translations/pl.json +++ b/custom_components/battery_notes/translations/pl.json @@ -103,11 +103,13 @@ } }, "abort": { + "reconfigure_successful": "Re-configuration was successful", "already_configured": "Urządzenie jest już skonfigurowane" }, "error": { "unknown": "Wystąpił nieznany błąd.", - "unconfigurable_entity": "Nie można dodać tej encji do Battery Notes." + "unconfigurable_entity": "Nie można dodać tej encji do Battery Notes.", + "orphaned_battery_note": "Powiązane urządzenie lub encja już nie istnieje dla tej Notatki Baterii." } } }, diff --git a/custom_components/battery_notes/translations/pt-BR.json b/custom_components/battery_notes/translations/pt-BR.json index 1f7db0471..7340fe430 100644 --- a/custom_components/battery_notes/translations/pt-BR.json +++ b/custom_components/battery_notes/translations/pt-BR.json @@ -185,9 +185,6 @@ "name": "Battery low threshold" } } - }, - "battery_outliers_filtered": { - "name": "Battery outliers filtered" } }, "button": { diff --git a/custom_components/battery_notes/translations/tr.json b/custom_components/battery_notes/translations/tr.json index 1eb769f4d..42f6acebe 100644 --- a/custom_components/battery_notes/translations/tr.json +++ b/custom_components/battery_notes/translations/tr.json @@ -108,7 +108,8 @@ }, "error": { "unknown": "Bilinmeyen bir hata oluştu.", - "unconfigurable_entity": "Bu varlığı Battery Notes'a eklemek mümkün değildir." + "unconfigurable_entity": "Bu varlığı Battery Notes'a eklemek mümkün değildir.", + "orphaned_battery_note": "İlişkili cihaz veya varlık bu Battery Notes için artık mevcut değildir." } } }, From cb2bc14feff8320de94b84a180dd328bf743bc09 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 18:16:48 +0000 Subject: [PATCH 154/235] Refactor entity ID handling to ignore domain in BatteryNotesEntity --- custom_components/battery_notes/entity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index 8b8e89f9c..2aa5af148 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -65,7 +65,7 @@ def _set_entity_id(self, entity_description: BatteryNotesEntityDescription) -> N f"{entity_description.entity_type}.{self.coordinator.device_name.lower()}_{entity_description.key}" ) elif self.coordinator.source_entity_id and self.coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( + _, source_object_id = split_entity_id( self.coordinator.source_entity_id ) self._attr_translation_placeholders = { From e0f118accabaa18625301fff924f30b2c3dc4d69 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 18:30:44 +0000 Subject: [PATCH 155/235] Suppress unused argument warnings in template event callbacks and sensor initialization --- custom_components/battery_notes/binary_sensor.py | 7 ++++--- custom_components/battery_notes/button.py | 2 +- custom_components/battery_notes/sensor.py | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index fd01a07fe..5ad13af79 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -235,6 +235,7 @@ def handle_result( last_result: str | None | TemplateError, result: str | TemplateError, ) -> None: + # pylint: disable=unused-argument """Handle a template result event callback.""" if isinstance(result, TemplateError): _LOGGER.error( @@ -374,7 +375,7 @@ def __init__( f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( + _, source_object_id = split_entity_id( coordinator.source_entity_id ) self._attr_translation_placeholders = { @@ -564,7 +565,7 @@ def __init__( f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( + _, source_object_id = split_entity_id( coordinator.source_entity_id ) self._attr_translation_placeholders = { @@ -644,7 +645,7 @@ def __init__( f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( + _, source_object_id = split_entity_id( coordinator.source_entity_id ) self._attr_translation_placeholders = { diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 95eedeec4..015ebc1ce 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -137,7 +137,7 @@ def __init__( f"button.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: - source_entity_domain, source_object_id = split_entity_id( + _, source_object_id = split_entity_id( coordinator.source_entity_id ) self._attr_translation_placeholders = { diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index f07ea8d44..2e7222d6a 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -344,6 +344,7 @@ def __init__( enable_replaced: bool, round_battery: bool, ) -> None: + # pylint: disable=unused-argument """Initialize the sensor.""" super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) From b39ea224dc9a0e1dd241977960c4dc6ef012fab3 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 18:41:35 +0000 Subject: [PATCH 156/235] Refactor template variable names for consistency in BatteryNotesBatteryLowTemplateSensor --- .../battery_notes/binary_sensor.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 5ad13af79..8f7aad934 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -48,6 +48,7 @@ EventStateChangedData, TrackTemplate, TrackTemplateResult, + TrackTemplateResultInfo, async_track_state_change_event, async_track_template_result, ) @@ -197,7 +198,7 @@ def __init__( self, entity: Entity, attribute: str, - template: Template, + tmpl: Template, validator: Callable[[Any], Any] | None = None, on_update: Callable[[Any], None] | None = None, none_on_template_error: bool | None = False, @@ -205,7 +206,7 @@ def __init__( """Template attribute.""" self._entity = entity self._attribute = attribute - self.template = template + self.template = tmpl self.validator = validator self.on_update = on_update self.async_update = None @@ -231,7 +232,7 @@ def _default_update(self, result: str | TemplateError) -> None: def handle_result( self, event: Event[EventStateChangedData] | None, - template: Template, + tmpl: Template, last_result: str | None | TemplateError, result: str | TemplateError, ) -> None: @@ -358,7 +359,7 @@ def __init__( coordinator: BatteryNotesSubentryCoordinator, entity_description: BatteryNotesBinarySensorEntityDescription, unique_id: str, - template: str, + tmpl: str, ) -> None: """Create a low battery binary sensor.""" @@ -366,6 +367,7 @@ def __init__( self._attr_unique_id = unique_id self._template_attrs: dict[Template, list[_TemplateAttribute]] = {} + self._template_result_info: TrackTemplateResultInfo | None = None if coordinator.source_entity_id and not coordinator.device_id: self._attr_translation_placeholders = { @@ -388,7 +390,7 @@ def __init__( f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" ) - self._template = template + self._template = tmpl self._state: bool | None = None async def async_added_to_hass(self) -> None: @@ -403,7 +405,7 @@ async def async_added_to_hass(self) -> None: def add_template_attribute( self, attribute: str, - template: Template, + tmpl: Template, validator: Callable[[Any], Any] | None = None, on_update: Callable[[Any], None] | None = None, none_on_template_error: bool = False, @@ -430,10 +432,10 @@ def add_template_attribute( assert self.hass is not None, "hass cannot be None" template.hass = self.hass template_attribute = _TemplateAttribute( - self, attribute, template, validator, on_update, none_on_template_error + self, attribute, tmpl, validator, on_update, none_on_template_error ) - self._template_attrs.setdefault(template, []) - self._template_attrs[template].append(template_attribute) + self._template_attrs.setdefault(tmpl, []) + self._template_attrs[tmpl].append(template_attribute) @callback def _async_setup_templates(self) -> None: From 6a8d60f0827809388d6484b79cc843dfb5298964 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 24 Aug 2025 18:42:20 +0000 Subject: [PATCH 157/235] Add wrapped_attributes to BatteryNotesBatteryBinaryLowSensor for state management --- custom_components/battery_notes/binary_sensor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 8f7aad934..c3a7a421b 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -663,6 +663,7 @@ def __init__( self._attr_unique_id = unique_id self._state: bool | None = None + self._wrapped_attributes: dict[str, Any] | None = None @callback async def async_state_changed_listener( From 4093f071d0594e630074bee38c09a6c50d3dc4c9 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 31 Aug 2025 14:29:24 +0000 Subject: [PATCH 158/235] Refactor integration entry retrieval in BatteryNotesFlowHandler --- .../battery_notes/config_flow.py | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 11626abfb..0cb478178 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -170,6 +170,14 @@ def async_get_supported_subentry_types( SUBENTRY_BATTERY_NOTE: BatteryNotesSubentryFlowHandler, } + def get_integration_entry(self) -> ConfigEntry | None: + """Return the main integration config entry, if it exists.""" + existing_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False) + for entry in existing_entries: + if entry.title == INTEGRATION_NAME: + return entry + return None + async def async_step_integration_discovery( self, discovery_info: DiscoveryInfoType, @@ -179,15 +187,7 @@ async def async_step_integration_discovery( unique_id = f"bn_{discovery_info[CONF_DEVICE_ID]}" - # Check if unique_id already exists as sub entry) - config_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False) - - config_entry: ConfigEntry | None = None - for entry in config_entries: - if entry.title == INTEGRATION_NAME: - # We found the main config entry, use it - config_entry = entry - break + config_entry = self.get_integration_entry() if not config_entry: _LOGGER.debug("No existing single config entry found, creating new one") @@ -211,12 +211,7 @@ async def async_step_integration_discovery( data={}, options=options ) - config_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False), - for entry in config_entries[0]: - if entry.title == INTEGRATION_NAME: - # We found the main config entry, use it - config_entry = entry - break + config_entry = self.get_integration_entry() assert config_entry @@ -414,8 +409,7 @@ async def async_step_battery( self.data.pop(CONF_MODEL_ID, None) self.data.pop(CONF_HW_VERSION, None) - config_entry = self.hass.config_entries.async_entries(domain=DOMAIN)[0] - # Create a subentry + config_entry = self.get_integration_entry() subentry = ConfigSubentry(subentry_type=SUBENTRY_BATTERY_NOTE, data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) self.hass.config_entries.async_add_subentry(config_entry, subentry) From 02cb2e75d29e9b7586708942bebb1418ad2d8552 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 31 Aug 2025 14:38:03 +0000 Subject: [PATCH 159/235] Refactor integration entry retrieval to use async method in BatteryNotesFlowHandler --- .../battery_notes/config_flow.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 0cb478178..dede34061 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -170,7 +170,7 @@ def async_get_supported_subentry_types( SUBENTRY_BATTERY_NOTE: BatteryNotesSubentryFlowHandler, } - def get_integration_entry(self) -> ConfigEntry | None: + async def async_get_integration_entry(self) -> ConfigEntry | None: """Return the main integration config entry, if it exists.""" existing_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False) for entry in existing_entries: @@ -187,7 +187,7 @@ async def async_step_integration_discovery( unique_id = f"bn_{discovery_info[CONF_DEVICE_ID]}" - config_entry = self.get_integration_entry() + config_entry = await self.async_get_integration_entry() if not config_entry: _LOGGER.debug("No existing single config entry found, creating new one") @@ -211,7 +211,7 @@ async def async_step_integration_discovery( data={}, options=options ) - config_entry = self.get_integration_entry() + config_entry = await self.async_get_integration_entry() assert config_entry @@ -369,7 +369,7 @@ async def async_step_battery( if source_entity_id: entity_registry = er.async_get(self.hass) entity_entry = entity_registry.async_get(source_entity_id) - source_entity_domain, source_object_id = split_entity_id( + _, source_object_id = split_entity_id( source_entity_id ) if entity_entry: @@ -409,7 +409,7 @@ async def async_step_battery( self.data.pop(CONF_MODEL_ID, None) self.data.pop(CONF_HW_VERSION, None) - config_entry = self.get_integration_entry() + config_entry = await self.async_get_integration_entry() subentry = ConfigSubentry(subentry_type=SUBENTRY_BATTERY_NOTE, data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) self.hass.config_entries.async_add_subentry(config_entry, subentry) @@ -495,7 +495,7 @@ def _is_new(self) -> bool: return self.source == "user" async def async_step_user( - self, user_input: dict[str, Any] | None = None + self, user_input: dict[str, Any] | None = None # pylint: disable=unused-argument ) -> SubentryFlowResult: """Add a subentry.""" @@ -673,6 +673,7 @@ async def async_step_entity( async def async_step_manual(self, user_input: dict[str, Any] | None = None) -> SubentryFlowResult: """Second step in config flow to add the battery type.""" + # pylint: disable=unused-argument errors: dict[str, str] = {} if user_input is not None: return await self.async_step_battery() @@ -710,7 +711,7 @@ async def async_step_battery( if source_entity_id: entity_registry = er.async_get(self.hass) entity_entry = entity_registry.async_get(source_entity_id) - source_entity_domain, source_object_id = split_entity_id( + _, source_object_id = split_entity_id( source_entity_id ) if entity_entry: @@ -830,11 +831,11 @@ async def async_step_reconfigure( self.data = config_subentry.data.copy() - self.source_device_id = self.data.get(CONF_DEVICE_ID) + source_device_id = self.data.get(CONF_DEVICE_ID) - if self.source_device_id: + if source_device_id: device_registry = dr.async_get(self.hass) - device_entry = device_registry.async_get(self.source_device_id) + device_entry = device_registry.async_get(source_device_id) if not device_entry: errors["base"] = "orphaned_battery_note" From 04ee6e58aad3f3c5cd3848e3fdaaf04fc57880f0 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 31 Aug 2025 15:21:49 +0000 Subject: [PATCH 160/235] Refactor timer_update method and improve logging format in LibraryUpdater; add pylint disables for unused arguments in repairs and store modules --- custom_components/battery_notes/library_updater.py | 4 ++-- custom_components/battery_notes/repairs.py | 4 ++-- custom_components/battery_notes/store.py | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index d7f921e6c..09cf110b8 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -54,7 +54,7 @@ def __init__(self, hass: HomeAssistant): ) @callback - async def timer_update(self, now: datetime): + async def timer_update(self): """Need to update the library.""" if await self.time_to_update_library(23) is False: return @@ -168,7 +168,7 @@ def __init__( async def async_get_data(self) -> Any: """Get data from the API.""" - _LOGGER.debug(f"Updating library from {DEFAULT_LIBRARY_URL}") + _LOGGER.debug("Updating library from %s", DEFAULT_LIBRARY_URL) return await self._api_wrapper(method="get", url=DEFAULT_LIBRARY_URL) async def _api_wrapper( diff --git a/custom_components/battery_notes/repairs.py b/custom_components/battery_notes/repairs.py index 7c72b7a35..8450ff5c2 100644 --- a/custom_components/battery_notes/repairs.py +++ b/custom_components/battery_notes/repairs.py @@ -25,7 +25,7 @@ def __init__(self, data: dict[str, str | int | float | None] | None) -> None: self.source_entity_id = cast(str, data["source_entity_id"]) async def async_step_init( - self, user_input: dict[str, str] | None = None + self, user_input: dict[str, str] | None = None #pylint: disable=unused-argument ) -> data_entry_flow.FlowResult: """Handle the first step of a fix flow.""" @@ -54,7 +54,7 @@ async def async_step_confirm( async def async_create_fix_flow( - hass: HomeAssistant, + hass: HomeAssistant, #pylint: disable=unused-argument issue_id: str, data: dict[str, str | int | float | None] | None, ) -> RepairsFlow: diff --git a/custom_components/battery_notes/store.py b/custom_components/battery_notes/store.py index 6320ec57b..bb30d7969 100644 --- a/custom_components/battery_notes/store.py +++ b/custom_components/battery_notes/store.py @@ -27,6 +27,7 @@ @attr.s(slots=True, frozen=True) class DeviceEntry: + #pylint: disable=too-few-public-methods """Battery Notes Device storage Entry.""" device_id = attr.ib(type=str, default=None) @@ -37,6 +38,7 @@ class DeviceEntry: @attr.s(slots=True, frozen=True) class EntityEntry: + #pylint: disable=too-few-public-methods """Battery Notes Entity storage Entry.""" entity_id = attr.ib(type=str, default=None) From 370b98f9680509eab8d003bf936fbd97b636d535 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 31 Aug 2025 15:40:58 +0000 Subject: [PATCH 161/235] Update translations to capitalize "Battery+" in data descriptions across multiple language files --- custom_components/battery_notes/translations/ar.json | 2 +- custom_components/battery_notes/translations/ca.json | 2 +- custom_components/battery_notes/translations/cs.json | 2 +- custom_components/battery_notes/translations/da.json | 2 +- custom_components/battery_notes/translations/de.json | 2 +- custom_components/battery_notes/translations/el.json | 2 +- custom_components/battery_notes/translations/en.json | 2 +- custom_components/battery_notes/translations/es-ES.json | 2 +- custom_components/battery_notes/translations/fi.json | 2 +- custom_components/battery_notes/translations/fr.json | 2 +- custom_components/battery_notes/translations/hu.json | 2 +- custom_components/battery_notes/translations/it.json | 2 +- custom_components/battery_notes/translations/lt.json | 2 +- custom_components/battery_notes/translations/lv.json | 2 +- custom_components/battery_notes/translations/nl.json | 2 +- custom_components/battery_notes/translations/no.json | 2 +- custom_components/battery_notes/translations/pl.json | 2 +- custom_components/battery_notes/translations/pt-BR.json | 2 +- custom_components/battery_notes/translations/pt.json | 2 +- custom_components/battery_notes/translations/ru.json | 2 +- custom_components/battery_notes/translations/sk.json | 2 +- custom_components/battery_notes/translations/sr-Latn.json | 2 +- custom_components/battery_notes/translations/sv-SE.json | 2 +- custom_components/battery_notes/translations/tr.json | 2 +- custom_components/battery_notes/translations/uk.json | 2 +- custom_components/battery_notes/translations/ur-IN.json | 2 +- custom_components/battery_notes/translations/zh-Hans.json | 2 +- custom_components/battery_notes/translations/zh-Hant.json | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/custom_components/battery_notes/translations/ar.json b/custom_components/battery_notes/translations/ar.json index 3eb352098..9b16928ca 100644 --- a/custom_components/battery_notes/translations/ar.json +++ b/custom_components/battery_notes/translations/ar.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/ca.json b/custom_components/battery_notes/translations/ca.json index e5c2e78b1..7baabe7a8 100644 --- a/custom_components/battery_notes/translations/ca.json +++ b/custom_components/battery_notes/translations/ca.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/cs.json b/custom_components/battery_notes/translations/cs.json index 8e7653ffe..129df6daf 100644 --- a/custom_components/battery_notes/translations/cs.json +++ b/custom_components/battery_notes/translations/cs.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/da.json b/custom_components/battery_notes/translations/da.json index 7d352b681..7639940af 100644 --- a/custom_components/battery_notes/translations/da.json +++ b/custom_components/battery_notes/translations/da.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/de.json b/custom_components/battery_notes/translations/de.json index f436e0ff3..485d5f14f 100644 --- a/custom_components/battery_notes/translations/de.json +++ b/custom_components/battery_notes/translations/de.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/el.json b/custom_components/battery_notes/translations/el.json index 3e7e4ad5d..67bb27851 100644 --- a/custom_components/battery_notes/translations/el.json +++ b/custom_components/battery_notes/translations/el.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 7340fe430..9fccf4695 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/es-ES.json b/custom_components/battery_notes/translations/es-ES.json index 0b3b3819f..af33d610a 100644 --- a/custom_components/battery_notes/translations/es-ES.json +++ b/custom_components/battery_notes/translations/es-ES.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/fi.json b/custom_components/battery_notes/translations/fi.json index ba06e0f57..ff6e0bd59 100644 --- a/custom_components/battery_notes/translations/fi.json +++ b/custom_components/battery_notes/translations/fi.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/fr.json b/custom_components/battery_notes/translations/fr.json index 5bc273dde..8c1f9bcf1 100644 --- a/custom_components/battery_notes/translations/fr.json +++ b/custom_components/battery_notes/translations/fr.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/hu.json b/custom_components/battery_notes/translations/hu.json index a7d868fed..4ee8c2010 100644 --- a/custom_components/battery_notes/translations/hu.json +++ b/custom_components/battery_notes/translations/hu.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/it.json b/custom_components/battery_notes/translations/it.json index d5b6817da..d4b4294ae 100644 --- a/custom_components/battery_notes/translations/it.json +++ b/custom_components/battery_notes/translations/it.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/lt.json b/custom_components/battery_notes/translations/lt.json index d529469f1..e72febdbb 100644 --- a/custom_components/battery_notes/translations/lt.json +++ b/custom_components/battery_notes/translations/lt.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/lv.json b/custom_components/battery_notes/translations/lv.json index 0cc38ae11..1c790014b 100644 --- a/custom_components/battery_notes/translations/lv.json +++ b/custom_components/battery_notes/translations/lv.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/nl.json b/custom_components/battery_notes/translations/nl.json index 7314c5102..ac3d14bab 100644 --- a/custom_components/battery_notes/translations/nl.json +++ b/custom_components/battery_notes/translations/nl.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/no.json b/custom_components/battery_notes/translations/no.json index 7719f23a2..f63ff0bd3 100644 --- a/custom_components/battery_notes/translations/no.json +++ b/custom_components/battery_notes/translations/no.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/pl.json b/custom_components/battery_notes/translations/pl.json index eb9577b1a..e090444b4 100644 --- a/custom_components/battery_notes/translations/pl.json +++ b/custom_components/battery_notes/translations/pl.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/pt-BR.json b/custom_components/battery_notes/translations/pt-BR.json index 7340fe430..9fccf4695 100644 --- a/custom_components/battery_notes/translations/pt-BR.json +++ b/custom_components/battery_notes/translations/pt-BR.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/pt.json b/custom_components/battery_notes/translations/pt.json index b89ae14eb..3972e3361 100644 --- a/custom_components/battery_notes/translations/pt.json +++ b/custom_components/battery_notes/translations/pt.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/ru.json b/custom_components/battery_notes/translations/ru.json index 9d782e6dd..704f09b3e 100644 --- a/custom_components/battery_notes/translations/ru.json +++ b/custom_components/battery_notes/translations/ru.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/sk.json b/custom_components/battery_notes/translations/sk.json index 4728a6221..da37fb58c 100644 --- a/custom_components/battery_notes/translations/sk.json +++ b/custom_components/battery_notes/translations/sk.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/sr-Latn.json b/custom_components/battery_notes/translations/sr-Latn.json index 753ae2ab8..dd0e40f75 100644 --- a/custom_components/battery_notes/translations/sr-Latn.json +++ b/custom_components/battery_notes/translations/sr-Latn.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/sv-SE.json b/custom_components/battery_notes/translations/sv-SE.json index 0bd46148d..e68190c43 100644 --- a/custom_components/battery_notes/translations/sv-SE.json +++ b/custom_components/battery_notes/translations/sv-SE.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/tr.json b/custom_components/battery_notes/translations/tr.json index 42f6acebe..1d4768713 100644 --- a/custom_components/battery_notes/translations/tr.json +++ b/custom_components/battery_notes/translations/tr.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/uk.json b/custom_components/battery_notes/translations/uk.json index bfe287acc..d2a5c84eb 100644 --- a/custom_components/battery_notes/translations/uk.json +++ b/custom_components/battery_notes/translations/uk.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/ur-IN.json b/custom_components/battery_notes/translations/ur-IN.json index 2364d4da3..d04796153 100644 --- a/custom_components/battery_notes/translations/ur-IN.json +++ b/custom_components/battery_notes/translations/ur-IN.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/zh-Hans.json b/custom_components/battery_notes/translations/zh-Hans.json index da427ae48..16e8e8f95 100644 --- a/custom_components/battery_notes/translations/zh-Hans.json +++ b/custom_components/battery_notes/translations/zh-Hans.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, diff --git a/custom_components/battery_notes/translations/zh-Hant.json b/custom_components/battery_notes/translations/zh-Hant.json index b7616b64b..18f48e4ae 100644 --- a/custom_components/battery_notes/translations/zh-Hant.json +++ b/custom_components/battery_notes/translations/zh-Hant.json @@ -126,7 +126,7 @@ "data_description": { "show_all_devices": "Show all devices in the device dropdown, otherwise only those with batteries will be shown.", "hide_battery": "Hide the standard battery when adding Battery+.", - "round_battery": "Round battery+ to whole percentages.", + "round_battery": "Round Battery+ to whole percentages.", "default_battery_low_threshold": "The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired if the battery is below this threshold, can be overriden per device in device configuration.", "battery_increase_threshold": "The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level." }, From 660548515a3a66ce7c665cce0c79909ca94fb620 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 31 Aug 2025 16:07:32 +0000 Subject: [PATCH 162/235] Fix variable name for battery type in async_migrate_entry function --- custom_components/battery_notes/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 3c049f41f..8201289ec 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -381,15 +381,15 @@ async def async_migrate_entry( ) if matches: qty = matches.group(1) if matches.group(1) is not None else "1" - type = ( + battery_type = ( matches.group(2) if matches.group(2) is not None else matches.group(3) ) else: qty = 1 - type = config_entry.data[CONF_BATTERY_TYPE] + battery_type = config_entry.data[CONF_BATTERY_TYPE] new_data = {**config_entry.data} - new_data[CONF_BATTERY_TYPE] = type + new_data[CONF_BATTERY_TYPE] = battery_type new_data[CONF_BATTERY_QUANTITY] = qty hass.config_entries.async_update_entry( From 0ec3bc7be7ed02d16c40ccd4b73f4f135448a473 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 31 Aug 2025 16:08:14 +0000 Subject: [PATCH 163/235] Refactor variable names for battery quantity in async_migrate_entry function --- custom_components/battery_notes/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 8201289ec..92d9769f7 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -380,17 +380,17 @@ async def async_migrate_entry( r"^(\d+)(?=x)(?:x\s)(\w+$)|([\s\S]+)", config_entry.data[CONF_BATTERY_TYPE] ) if matches: - qty = matches.group(1) if matches.group(1) is not None else "1" + battery_qty = matches.group(1) if matches.group(1) is not None else "1" battery_type = ( matches.group(2) if matches.group(2) is not None else matches.group(3) ) else: - qty = 1 + battery_qty = 1 battery_type = config_entry.data[CONF_BATTERY_TYPE] new_data = {**config_entry.data} new_data[CONF_BATTERY_TYPE] = battery_type - new_data[CONF_BATTERY_QUANTITY] = qty + new_data[CONF_BATTERY_QUANTITY] = battery_qty hass.config_entries.async_update_entry( config_entry, version=2, title=config_entry.title, data=new_data From 0905e0150c5393076739c37f44af222c9e47952b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 31 Aug 2025 17:03:29 +0000 Subject: [PATCH 164/235] Refactor async_setup_entry to simplify event listener management and remove unused unsubscribe function --- custom_components/battery_notes/__init__.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 92d9769f7..c39aa68c3 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -156,6 +156,7 @@ async def async_setup_entry( config_entry.async_on_unload(config_entry.add_update_listener(_async_update_listener)) + @callback async def _after_start(_: Event) -> None: """After Home Assistant has started, update library and do discovery.""" library_updater = LibraryUpdater(hass) @@ -168,23 +169,10 @@ async def _after_start(_: Event) -> None: else: _LOGGER.debug("Auto discovery disabled") - @callback - def _unsubscribe_ha_started() -> None: - """Unsubscribe the started listener.""" - if after_start_unsub is not None: - try: - after_start_unsub() - except ValueError: - _LOGGER.debug( - "Failed to unsubscribe started listener, " - "it might have already been removed or never registered.", - ) - # Wait until Home Assistant is started, before doing library and discovery - after_start_unsub = hass.bus.async_listen_once( + hass.bus.async_listen_once( EVENT_HOMEASSISTANT_STARTED, _after_start ) - config_entry.async_on_unload(_unsubscribe_ha_started) return True From f18b24f73cba802e5ab3eb3b078cab84bd24bc65 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 31 Aug 2025 17:35:21 +0000 Subject: [PATCH 165/235] Add debug log for existing battery_notes config entry during flow initialization --- custom_components/battery_notes/config_flow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index dede34061..712283d58 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -240,6 +240,7 @@ async def async_step_user( """Handle a flow initialized by the user.""" if self._async_current_entries(): + _LOGGER.debug("An existing battery_notes config entry already exists") return self.async_abort(reason="already_configured") if user_input is not None: From 424aa8305b1752192339f9c55ca53b404bd9099c Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 1 Sep 2025 12:23:34 +0000 Subject: [PATCH 166/235] Prevent second discovery --- custom_components/battery_notes/__init__.py | 3 +-- custom_components/battery_notes/discovery.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index c39aa68c3..576a77156 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -355,6 +355,7 @@ async def async_migrate_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry ) -> bool: """Migrate old config.""" + _LOGGER.debug("Migrating configuration from version %s.%s", config_entry.version, config_entry.minor_version) if config_entry.version > 3: # This means the user has downgraded from a future version @@ -362,8 +363,6 @@ async def async_migrate_entry( if config_entry.version == 1: # Version 1 had a single config for qty & type, split them - _LOGGER.debug("Migrating config entry from version %s", config_entry.version) - matches = re.search( r"^(\d+)(?=x)(?:x\s)(\w+$)|([\s\S]+)", config_entry.data[CONF_BATTERY_TYPE] ) diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index 4a23e2321..a98823c35 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -134,12 +134,23 @@ def _init_entity_discovery( device_battery_details: DeviceBatteryDetails, ) -> None: """Dispatch the discovery flow for a given entity.""" + unique_id = f"bn_{device_entry.id}" + + # Iterate all the ignored devices and check if we have it already + for config_entry in self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=True, include_disabled=False): + if config_entry.unique_id == unique_id: + _LOGGER.debug( + "%s: Ignored, skipping new discovery", + unique_id, + ) + return + for config_entry in self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False): for subentry in config_entry.subentries.values(): if subentry.data.get(CONF_DEVICE_ID, "") == device_entry.id: _LOGGER.debug( "%s: Already setup, skipping new discovery", - f"bn_{device_entry.id}", + unique_id, ) return From 2f0ae390512dc2622d1674c2881f223f5d0ce3d2 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 1 Sep 2025 14:10:08 +0000 Subject: [PATCH 167/235] Refactor async_setup_entry to improve discovery management and update library handling --- custom_components/battery_notes/__init__.py | 24 ++++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 576a77156..8314062ca 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -8,6 +8,7 @@ import logging import re +from datetime import datetime from types import MappingProxyType import voluptuous as vol @@ -15,15 +16,17 @@ from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry from homeassistant.const import CONF_DEVICE_ID, EVENT_HOMEASSISTANT_STARTED from homeassistant.const import __version__ as HA_VERSION # noqa: N812 -from homeassistant.core import Event, HomeAssistant, callback +from homeassistant.core import HassJob, HomeAssistant, callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers import device_registry as dr from homeassistant.helpers import entity_registry as er from homeassistant.helpers import helper_integration from homeassistant.helpers import issue_registry as ir from homeassistant.helpers.device import async_entity_id_to_device_id +from homeassistant.helpers.event import async_call_later from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.typing import ConfigType +from homeassistant.util import dt as dt_util from .const import ( CONF_ADVANCED_SETTINGS, @@ -65,6 +68,7 @@ _LOGGER = logging.getLogger(__name__) +DISCOVERY_DELAY = 10 CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.All( @@ -143,6 +147,8 @@ async def async_setup_entry( loaded_subentries=config_entry.subentries.copy(), ) + discovery_manager = DiscoveryManager(hass, domain_config) + config_entry.runtime_data.subentry_coordinators = {} for subentry in config_entry.subentries.values(): if subentry.subentry_type == SUBENTRY_BATTERY_NOTE: @@ -156,22 +162,24 @@ async def async_setup_entry( config_entry.async_on_unload(config_entry.add_update_listener(_async_update_listener)) + @callback - async def _after_start(_: Event) -> None: - """After Home Assistant has started, update library and do discovery.""" + async def _async_delayed_discovery(now: datetime) -> None: #pylint: disable=unused-argument + """Update the library and do discovery.""" library_updater = LibraryUpdater(hass) await library_updater.copy_schema() - await library_updater.get_library_updates(startup=True) + await library_updater.get_library_updates(startup=False) if domain_config.enable_autodiscovery: - discovery_manager = DiscoveryManager(hass, domain_config) await discovery_manager.start_discovery() else: _LOGGER.debug("Auto discovery disabled") - # Wait until Home Assistant is started, before doing library and discovery - hass.bus.async_listen_once( - EVENT_HOMEASSISTANT_STARTED, _after_start + # Let the system settle a bit before starting discovery + async_call_later( + hass, + DISCOVERY_DELAY, + HassJob(_async_delayed_discovery, "battery notes discovery", cancel_on_shutdown=True), ) return True From 46806ec744ee312be48981e40c232af0f3d3cb71 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 1 Sep 2025 14:10:24 +0000 Subject: [PATCH 168/235] Remove unused import of EVENT_HOMEASSISTANT_STARTED and dt_util from __init__.py --- custom_components/battery_notes/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 8314062ca..ee6a7a26d 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -14,7 +14,7 @@ import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry -from homeassistant.const import CONF_DEVICE_ID, EVENT_HOMEASSISTANT_STARTED +from homeassistant.const import CONF_DEVICE_ID from homeassistant.const import __version__ as HA_VERSION # noqa: N812 from homeassistant.core import HassJob, HomeAssistant, callback from homeassistant.helpers import config_validation as cv @@ -26,7 +26,6 @@ from homeassistant.helpers.event import async_call_later from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.typing import ConfigType -from homeassistant.util import dt as dt_util from .const import ( CONF_ADVANCED_SETTINGS, From f9e91a6a859e5b26d90ad592d6c7851c1eed52c9 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 1 Sep 2025 16:32:34 +0000 Subject: [PATCH 169/235] Update discovery.py to include SOURCE_IGNORE in config entry checks for ignored devices --- custom_components/battery_notes/discovery.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index a98823c35..f02acbce7 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -6,7 +6,7 @@ from typing import Any import homeassistant.helpers.device_registry as dr -from homeassistant.config_entries import SOURCE_INTEGRATION_DISCOVERY +from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_INTEGRATION_DISCOVERY from homeassistant.const import CONF_DEVICE_ID from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import discovery_flow @@ -138,7 +138,7 @@ def _init_entity_discovery( # Iterate all the ignored devices and check if we have it already for config_entry in self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=True, include_disabled=False): - if config_entry.unique_id == unique_id: + if config_entry.source == SOURCE_IGNORE and config_entry.unique_id == unique_id: _LOGGER.debug( "%s: Ignored, skipping new discovery", unique_id, From a07720fa8f73ca9c508e354283ee47ba0ef8bff6 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 2 Sep 2025 11:21:54 +0000 Subject: [PATCH 170/235] Set startup flag to True for library updates during entry setup --- custom_components/battery_notes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index ee6a7a26d..ec5e3af65 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -167,7 +167,7 @@ async def _async_delayed_discovery(now: datetime) -> None: #pylint: disable=unus """Update the library and do discovery.""" library_updater = LibraryUpdater(hass) await library_updater.copy_schema() - await library_updater.get_library_updates(startup=False) + await library_updater.get_library_updates(startup=True) if domain_config.enable_autodiscovery: await discovery_manager.start_discovery() From 4f33f6ae4843e7c7912a6f5a741906344cdf70af Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 2 Sep 2025 11:36:50 +0000 Subject: [PATCH 171/235] Refactor async_get_config_entry_diagnostics to include subentry device information --- .../battery_notes/diagnostics.py | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/custom_components/battery_notes/diagnostics.py b/custom_components/battery_notes/diagnostics.py index 280bb097f..45e5ab87b 100644 --- a/custom_components/battery_notes/diagnostics.py +++ b/custom_components/battery_notes/diagnostics.py @@ -26,25 +26,26 @@ async def async_get_config_entry_diagnostics( device_registry = dr.async_get(hass) entity_registry = er.async_get(hass) - device_id = config_entry.data.get(CONF_DEVICE_ID, None) - source_entity_id = config_entry.data.get(CONF_SOURCE_ENTITY_ID, None) - - if source_entity_id: - entity = entity_registry.async_get(source_entity_id) - if entity: - device_id = entity.device_id - diagnostics = {"entry": config_entry.as_dict()} - if device_id: - device_entry = device_registry.async_get(device_id) - if device_entry: - device_info = { - "manufacturer": device_entry.manufacturer, - "model": device_entry.model, - "model_id": get_device_model_id(device_entry), - "hw_version": device_entry.hw_version, - } - diagnostics.update({"device": device_info}) + for subentry in config_entry.subentries.values(): + device_id = subentry.data.get(CONF_DEVICE_ID, None) + source_entity_id = subentry.data.get(CONF_SOURCE_ENTITY_ID, None) + + if source_entity_id: + entity = entity_registry.async_get(source_entity_id) + if entity: + device_id = entity.device_id + + if device_id: + device_entry = device_registry.async_get(device_id) + if device_entry: + device_info = { + "manufacturer": device_entry.manufacturer, + "model": device_entry.model, + "model_id": get_device_model_id(device_entry), + "hw_version": device_entry.hw_version, + } + diagnostics.update({f"subentry {subentry.subentry_id}": device_info}) return diagnostics From 4ca8038b9cc41accd8443000c18057214b8f5a6b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 4 Sep 2025 13:37:39 +0000 Subject: [PATCH 172/235] Bump to HA 2025.9 --- custom_components/battery_notes/const.py | 4 +- hacs.json | 2 +- poetry.lock | 488 +++++++++++------------ pyproject.toml | 2 +- requirements.txt | 2 +- 5 files changed, 246 insertions(+), 252 deletions(-) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 3f041166c..19129e4e4 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -11,7 +11,7 @@ LOGGER: Logger = getLogger(__package__) -MIN_HA_VERSION = "2025.8.0" +MIN_HA_VERSION = "2025.9.0" manifestfile = Path(__file__).parent / "manifest.json" with open(file=manifestfile, encoding="UTF-8") as json_file: @@ -115,4 +115,4 @@ Platform.SENSOR, ] -SUBENTRY_BATTERY_NOTE = "battery_note" \ No newline at end of file +SUBENTRY_BATTERY_NOTE = "battery_note" diff --git a/hacs.json b/hacs.json index b1fff2ebd..642bf8970 100644 --- a/hacs.json +++ b/hacs.json @@ -2,6 +2,6 @@ "name": "Battery Notes", "filename": "battery_notes.zip", "hide_default_branch": true, - "homeassistant": "2025.8.0", + "homeassistant": "2025.9.0", "zip_release": true } diff --git a/poetry.lock b/poetry.lock index f87b9da25..3779ed48a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,14 +2,14 @@ [[package]] name = "acme" -version = "4.1.1" +version = "4.2.0" description = "ACME protocol implementation in Python" optional = false python-versions = ">=3.9.2" groups = ["main"] files = [ - {file = "acme-4.1.1-py3-none-any.whl", hash = "sha256:9c904453bf1374789b6cd78c6314dea6e7609b4f6c58e35339ee91701f39cd20"}, - {file = "acme-4.1.1.tar.gz", hash = "sha256:0ffaaf6d3f41ff05772fd2b6170cf0b2b139f5134d7a70ee49f6e63ca20e8f9a"}, + {file = "acme-4.2.0-py3-none-any.whl", hash = "sha256:6292011bbfa5f966521b2fb9469982c24ff4c58e240985f14564ccf35372e79a"}, + {file = "acme-4.2.0.tar.gz", hash = "sha256:0df68c0e1acb3824a2100013f8cd51bda2e1a56aa23447449d14c942959f0c41"}, ] [package.dependencies] @@ -17,7 +17,6 @@ cryptography = ">=43.0.0" josepy = ">=2.0.0" PyOpenSSL = ">=25.0.0" pyrfc3339 = "*" -pytz = ">=2019.3" requests = ">=2.20.0" [package.extras] @@ -53,14 +52,14 @@ files = [ [[package]] name = "aiohasupervisor" -version = "0.3.1" +version = "0.3.2" description = "Asynchronous python client for Home Assistant Supervisor." optional = false python-versions = ">=3.12.0" groups = ["main"] files = [ - {file = "aiohasupervisor-0.3.1-py3-none-any.whl", hash = "sha256:d5fa5df20562177703c701e95889a52595788c5790a856f285474d68553346a3"}, - {file = "aiohasupervisor-0.3.1.tar.gz", hash = "sha256:6d88c32e640932855cf5d7ade573208a003527a9687129923a71e3ab0f0cdf26"}, + {file = "aiohasupervisor-0.3.2-py3-none-any.whl", hash = "sha256:93599f698e7daf238e8040053d455104bac149f9e59fda757c6378708fbd1629"}, + {file = "aiohasupervisor-0.3.2.tar.gz", hash = "sha256:eb291b600cc5cf05072e4bd16df5655cfaea3b9f3b964844896b38230e529a7c"}, ] [package.dependencies] @@ -69,7 +68,7 @@ mashumaro = ">=3.11,<4.0" orjson = ">=3.6.1,<4.0.0" [package.extras] -dev = ["aiohttp (==3.11.18)", "aioresponses (==0.7.8)", "codespell (==2.4.1)", "coverage (==7.8.0)", "mashumaro (==3.15)", "mypy (==1.15.0)", "orjson (==3.10.16)", "pre-commit (==4.2.0)", "pytest (==8.3.5)", "pytest-aiohttp (==1.1.0)", "pytest-cov (==6.1.1)", "pytest-timeout (==2.3.1)", "ruff (==0.11.6)", "yamllint (==1.37.0)"] +dev = ["aiohttp (==3.12.15)", "aioresponses (==0.7.8)", "codespell (==2.4.1)", "coverage (==7.10.5)", "mashumaro (==3.16)", "mypy (==1.17.1)", "orjson (==3.11.2)", "pre-commit (==4.3.0)", "pytest (==8.4.1)", "pytest-aiohttp (==1.1.0)", "pytest-cov (==6.2.1)", "pytest-timeout (==2.4.0)", "ruff (==0.12.10)", "yamllint (==1.37.1)"] [[package]] name = "aiohttp" @@ -567,14 +566,14 @@ pythonista = ["bleak-pythonista (>=0.1.1)"] [[package]] name = "bleak-retry-connector" -version = "4.0.0" +version = "4.4.3" description = "A connector for Bleak Clients that handles transient connection failures" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "bleak_retry_connector-4.0.0-py3-none-any.whl", hash = "sha256:b7712a10f80735eaa981549fa4f867418268cd32ab15d8ca4e0f6697bbe13f02"}, - {file = "bleak_retry_connector-4.0.0.tar.gz", hash = "sha256:2a20dcaee5aed6aada886565fcda0b59244fabbdba7781c139adac68422a50ae"}, + {file = "bleak_retry_connector-4.4.3-py3-none-any.whl", hash = "sha256:17a478d525706488973b181fc789e960bc3fb4bcd94ccb0eee7b7b682442577b"}, + {file = "bleak_retry_connector-4.4.3.tar.gz", hash = "sha256:70aa305dbd26eaf0586dd24723daac93ee3dd6a465e9782bf02b711fcbc4a527"}, ] [package.dependencies] @@ -584,14 +583,14 @@ dbus-fast = {version = ">=1.14.0", markers = "platform_system == \"Linux\""} [[package]] name = "bluetooth-adapters" -version = "2.0.0" +version = "2.1.0" description = "Tools to enumerate and find Bluetooth Adapters" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "bluetooth_adapters-2.0.0-py3-none-any.whl", hash = "sha256:7eff2c48dd3170e8ccf91888ddc97d847faa24cdd2678cf4b78166c1999171a8"}, - {file = "bluetooth_adapters-2.0.0.tar.gz", hash = "sha256:ecdba203e806a90ea503cc32acfe11eafdc10813abac4591545d174da78d3c55"}, + {file = "bluetooth_adapters-2.1.0-py3-none-any.whl", hash = "sha256:d40204ef5277209987a4ac7eb385ef11af477133e2dcdafd60bb65172c106797"}, + {file = "bluetooth_adapters-2.1.0.tar.gz", hash = "sha256:ef7363c7557721fdad28df30fbdf0c7f2f793671ad259b99be4b38a78afe9038"}, ] [package.dependencies] @@ -693,18 +692,18 @@ docs = ["Sphinx (>=5,<9)", "myst-parser (>=0.18,<4.1)", "sphinx-rtd-theme (>=1,< [[package]] name = "boto3" -version = "1.40.7" +version = "1.40.23" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "boto3-1.40.7-py3-none-any.whl", hash = "sha256:8727cac601a679d2885dc78b8119a0548bbbe04e49b72f7d94021a629154c080"}, - {file = "boto3-1.40.7.tar.gz", hash = "sha256:61b15f70761f1eadd721c6ba41a92658f003eaaef09500ca7642f5ae68ec8945"}, + {file = "boto3-1.40.23-py3-none-any.whl", hash = "sha256:9826fb6abcdda2f016a939b81e94d1a9e1147ae897a523f366cf5a1558936356"}, + {file = "boto3-1.40.23.tar.gz", hash = "sha256:ca5e2f767a7b759b0bb5c7e5c665effa1512799e763823e68d04e7c10b1399d5"}, ] [package.dependencies] -botocore = ">=1.40.7,<1.41.0" +botocore = ">=1.40.23,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -713,14 +712,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.7" +version = "1.40.23" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "botocore-1.40.7-py3-none-any.whl", hash = "sha256:a06956f3d7222e80ef6ae193608f358c3b7898e1a2b88553479d8f9737fbb03e"}, - {file = "botocore-1.40.7.tar.gz", hash = "sha256:33793696680cf3a0c4b5ace4f9070c67c4d4fcb19c999fd85cfee55de3dcf913"}, + {file = "botocore-1.40.23-py3-none-any.whl", hash = "sha256:487cced8f9346f7d1038e9158c56b6ecf6d839dd43e345bc730053c8cf321ed3"}, + {file = "botocore-1.40.23.tar.gz", hash = "sha256:de07cceaf9b142c183e165d303a0eee289c34d63f63e6b7a640406d6bacfb646"}, ] [package.dependencies] @@ -729,7 +728,7 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.23.8)"] +crt = ["awscrt (==0.27.6)"] [[package]] name = "btsocket" @@ -1185,21 +1184,16 @@ cli = ["Jinja2[cli] (>=3.0.3,<4.0.0)", "click[cli] (>=8.0.3,<9.0.0)", "terminalt [[package]] name = "filelock" -version = "3.18.0" +version = "3.19.1" description = "A platform independent file lock." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"}, - {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"}, + {file = "filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d"}, + {file = "filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58"}, ] -[package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] -typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] - [[package]] name = "fnv-hash-fast" version = "1.5.0" @@ -1459,67 +1453,67 @@ files = [ [[package]] name = "habluetooth" -version = "5.0.1" +version = "5.3.0" description = "High availability Bluetooth" optional = false python-versions = ">=3.11" groups = ["main"] files = [ - {file = "habluetooth-5.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fbc44abedfd4d462d7b2cafa71c9b29b1f7293967cf6ae0f8379b94a0a1bf751"}, - {file = "habluetooth-5.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f20812a973c903b80e9864223dfb228dfdbfe446173b762181c463bd8be9e407"}, - {file = "habluetooth-5.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d7f25e33f4f230917a1a96d5c1e77f25b3ea3fca3f4284816b35dc03922a7595"}, - {file = "habluetooth-5.0.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6c4cb947003e92041503ff51a02ebe457177ea19b484435640c0dded98f60343"}, - {file = "habluetooth-5.0.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e97bfc5ac6cf2ca22fdad622a26984ff7ed01acc7c61b223dc69f0a82f9f128b"}, - {file = "habluetooth-5.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8f41adec778f522c51a27fa9ec8b539683a2d151d43f6957f00ba2a06656d526"}, - {file = "habluetooth-5.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d13dc369c3381d190c0cf21a7b3262a8f2c044474e54d665d904a20abe34bb63"}, - {file = "habluetooth-5.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96dc5ff1fdab8f20112a3db00a3822ace758688ac6b39ad1632d5943df20a50c"}, - {file = "habluetooth-5.0.1-cp311-cp311-win32.whl", hash = "sha256:15ec534969436e04f859a0fd60b9bb813f4d082fb77d1e1c57f3e607fd1641c9"}, - {file = "habluetooth-5.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bb375cadcfc4ffc90cec6f71af9ec9a665ebf9564c43d8b367e643802da2cac2"}, - {file = "habluetooth-5.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:43585141e2de4a9b0b866049acf116bf8b84651a6479f0d1cd3eabdf885e6d37"}, - {file = "habluetooth-5.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e55481e405489aafea5ac77744db920b29afdae770e8a6f8e4c0e94d48cd8f1b"}, - {file = "habluetooth-5.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:05a398922580abe6a7eb72860a9b4ccc623d77f78c0aed06e8a845bbf1edca6b"}, - {file = "habluetooth-5.0.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:30dd7705e7732bc439d3e053da46335a8addbee477352c75987cc622eeef65d0"}, - {file = "habluetooth-5.0.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:485f985e3dc7e325fff46ee58a62a5fca7d55579ab3d67bd27345ab2d5112539"}, - {file = "habluetooth-5.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6bc118d7535014e45d6a2763392118ef51ee23f6105fcf4a1569339d54d7000e"}, - {file = "habluetooth-5.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e4e981732c6483fedecd5773ddaa010e48e5abfe9e3d1a1b160c386b31fed4d8"}, - {file = "habluetooth-5.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad3a38ba90e1d94c0520c73244b00329f1db68f684990c13176507f144ca0dca"}, - {file = "habluetooth-5.0.1-cp312-cp312-win32.whl", hash = "sha256:c7ad7d9613d6d74d639cae05ae3686098d6a0c86e557fe1233dabf2fee19ce8a"}, - {file = "habluetooth-5.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:7e462e1bcbc0a7dbf2e526f44dc4b08344ed67e40f398cc932eeae828934741a"}, - {file = "habluetooth-5.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f6aac5b5d904ccf7a0cb8d2353ffbdcd9384e403c21a11d999e514f21d310bb"}, - {file = "habluetooth-5.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95fca9eb3a8bcdbb86990228129f7cf2159d100b2cccd862a961f3f22c1e042c"}, - {file = "habluetooth-5.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18ac447c09c0f2edcdd9152e15b707338ea3e6c903e35fee14a5f4820e6d64e1"}, - {file = "habluetooth-5.0.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c55c6b7de8c64a2a23522d40fea7f60ccc0040d91b377e635f4ad4f26925ce49"}, - {file = "habluetooth-5.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62263daf0bed0c227bab14924e624f9ca8af483939a9be847844ea388fab971d"}, - {file = "habluetooth-5.0.1-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:ee08ae031f594683a236c359ed6d5fe2fa53fe1dca57229df5bd4b238cba61f3"}, - {file = "habluetooth-5.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e8e45c746e31d86c93347054bd6a36d802ca873238b7f1da0a9a9830bc4caca7"}, - {file = "habluetooth-5.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7aa09c6252f5a1f2bcb94c22ec6c9ac5e3e25369a11674e43de60afe7b345568"}, - {file = "habluetooth-5.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0fa229e2f0f09407f1471afecd4d318cfaf4e50c8f5d9bdc73a65226ab4810c6"}, - {file = "habluetooth-5.0.1-cp313-cp313-win32.whl", hash = "sha256:173df6fb4cba6cef2605a1a6e178417143ecaf82ad7f3086693d13b0638743a0"}, - {file = "habluetooth-5.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:7690ea34c16ce37d9e7c9ad59c662d8f17d6069d235a72d323d6febe664ce764"}, - {file = "habluetooth-5.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d46c67de552d3db96e000ce4031e388735681882a2d95a437b6e0138db918e9"}, - {file = "habluetooth-5.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ddc5644c6c6b2a80ff9c826f901ca15748a020b8c7e162ab39fc35b49bbecf17"}, - {file = "habluetooth-5.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86825b3c10e0fa43a469af6b5aad6dbfb012d90dcc039936ec441b9e908b70c1"}, - {file = "habluetooth-5.0.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:beda16e0c9272a077771c12f4b50cf43a3aa5173d71dbc4794ae68dc98aa3cad"}, - {file = "habluetooth-5.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:30cbd5f37cc8aa2644db93c3a01c4f2843befc12962c2aa3f8b9aac8b6dfd3c2"}, - {file = "habluetooth-5.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1df1af9448deeead2b7ca9cfb89a5e44d6c5068a6a818211eaefb6a8a4ff808"}, - {file = "habluetooth-5.0.1-cp314-cp314-win32.whl", hash = "sha256:23740047240da1ebf5a1ba9f99d337310670ae5070c8f960c2bbc3aef061be95"}, - {file = "habluetooth-5.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:8327354cbb4a645b63595f8ae04767b97827376389a2c44bc0bfbc37c91f143e"}, - {file = "habluetooth-5.0.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:50ee71822ab1bd6b3bbbe449c32701a9cbe5b224560ec8aa2cbde318bdcc51da"}, - {file = "habluetooth-5.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:137484d72fd96829c5d16cf3f179ee218fc5155bda56d8c4563accda0094e816"}, - {file = "habluetooth-5.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f0de147f3a393adee328459ee66663783a4b92e994789d37f594e415a047e07"}, - {file = "habluetooth-5.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:458ad7112caee189ef5ec22766ab1d9f788a0a6c02ef9a8507b344385a5802f0"}, - {file = "habluetooth-5.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a838a76e71f7962c33865c6ed0990c6170def2a72de17d2f4986cc8064370a61"}, - {file = "habluetooth-5.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d7557cbbb53a3b40fa626eca475c3d95a7fee43d90357655cbad15e7fc3a759d"}, - {file = "habluetooth-5.0.1-cp314-cp314t-win32.whl", hash = "sha256:b7f96471c2ea4949300fa4abcda3a35a6d7132634fe93378c6a9b9d45cc32c90"}, - {file = "habluetooth-5.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f2d9a13a13b105ee3712bdfbec3ac17baffd311c24d5a29c8e9c129eb362252e"}, - {file = "habluetooth-5.0.1.tar.gz", hash = "sha256:dfa720b0c2b03d6380ae3d474061c4fe78e58523f4baa208d0f8f5f8f3a8663c"}, + {file = "habluetooth-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d6cd322239c30b1ce618ef34f64af4a47fd96b9d2aa45e808d7fd0e086789473"}, + {file = "habluetooth-5.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:772985736a4758273cb08f200c5679f47135c854c7a8c09e8048d61a08db4da1"}, + {file = "habluetooth-5.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:213224c97a1ce072f06ea2780367b0a49e75aef32f56edcb4647fd65d44114e0"}, + {file = "habluetooth-5.3.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dc13924a03772f1f95cb498d28d7f95ec07c31d61c3c35c6cc9245d1ded08cfe"}, + {file = "habluetooth-5.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:312427faced2bc90c1a645d4a8726e43366a638a5330bc03d842e14c4e74a99a"}, + {file = "habluetooth-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b39d0fbf816ddaae0c618fd9df7b05dc48e6f178f90325f53769e9af68afdf84"}, + {file = "habluetooth-5.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:44910a738d8a8877ccd408920d83eaac97e508dbe08f885f5cd07cedc1645d6e"}, + {file = "habluetooth-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3a380e69b288c59f131c320d50cdbc2061b76684f671e171fee973ce98e63549"}, + {file = "habluetooth-5.3.0-cp311-cp311-win32.whl", hash = "sha256:544a9428e7bca1033167c62279ca7e8a251684c801dc52cfc02d6f9f31dfee57"}, + {file = "habluetooth-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:09b0242de42b907089a8348c455c42c36fda11dff5feea122d25119c26b5842c"}, + {file = "habluetooth-5.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ac934bafb2e014de7290113524b118928e31dc8bcae8dceb8a3942415628ec73"}, + {file = "habluetooth-5.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f78622c7663cf569374876a37fb08f503c16922185a4b4d42d6749cf2c8562ff"}, + {file = "habluetooth-5.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b1accaf1af22c8bf5d28c272244e6c288d075428d1dc146d2efa5d4cb5877a4"}, + {file = "habluetooth-5.3.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a1b5b3355ef7963bd4ab9c79404a55098601c2ba4817722f3672e2b1ea3c6d11"}, + {file = "habluetooth-5.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e84f8bd8d1439a51618cdc7134a1229594aebeebee31736c151621adb8f0b5d"}, + {file = "habluetooth-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef0aba29d989ebc56195612fa13fb688ff6b34b6325d54312c4481e989b56730"}, + {file = "habluetooth-5.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5d1511778e2e680bd1f70c196671851567e0de0216783060e0015aab07a89813"}, + {file = "habluetooth-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7ebe77d69245c56a5683ace39dd0c05a6c23ef6e93589f03663a460e5157b804"}, + {file = "habluetooth-5.3.0-cp312-cp312-win32.whl", hash = "sha256:6343c3a3b9717012044b7211037b1270f387f7dc2220f2917ad1083f2d8042b1"}, + {file = "habluetooth-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:271608f4fa20889aacdfe9fd399590336ccd67a041d66140e8b970a49703849a"}, + {file = "habluetooth-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:51cdec48bc225033582eb0614e85682fe4fbf2220b6126537e01cd229e45ca88"}, + {file = "habluetooth-5.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b02428daef97758e495fc92d993b61011c3e938d82d69c485a5a370168c5375e"}, + {file = "habluetooth-5.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73bd63b3af3849f10104564f2fa432d59d1b0e08f393e87e21a85c8ac805217f"}, + {file = "habluetooth-5.3.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10989b4d1e61d1b21be8fac73609e78353a80288707f84c6eb06e818ea1402a8"}, + {file = "habluetooth-5.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:203147f7f8eecaa4b5dd9496ca2604a5c8000ec701681d57d20030077fc3d873"}, + {file = "habluetooth-5.3.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:578fac07b33890ef0541753c545b205c7a458e93bcd2b91892e438a0fb2273ee"}, + {file = "habluetooth-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:10484ee1ff125edcd0ac1d252beaab12468f42819c13812cb5c02960be7a98c7"}, + {file = "habluetooth-5.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ef04d191281f68ea294306e39514080844668188245b625517e7b91573f7ef9a"}, + {file = "habluetooth-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:736476437df2de27863e57f5f3d845f84f936c4345d3d4ba7d50820ef2defc45"}, + {file = "habluetooth-5.3.0-cp313-cp313-win32.whl", hash = "sha256:3d529d0a5b044e5fceb5361b732e0b0d7f9477771f45fe642c2aa12987479f84"}, + {file = "habluetooth-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:75b01ed9bc64fd7d1a4e744ac46ef6527cd47e50f3864896736a7e0cf09ca5f6"}, + {file = "habluetooth-5.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7a3783052ddf8691e3b13d645470e776fb2967764d5d0c9971556238ca2a4d7c"}, + {file = "habluetooth-5.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da5a57814d74292287efac1288c7456ab63d37f16f08592e38bd111fac60c1b7"}, + {file = "habluetooth-5.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5216ee433b53e2aff591fb1312aa432076d8673138dfb6023f7d357ac72b34c2"}, + {file = "habluetooth-5.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:503cb724a37a6c084fc29e87a4c6ce77c94e88cbcb7457ff0a30c592d266d398"}, + {file = "habluetooth-5.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e61d4fe06f26629ea78f2677ba39960e76d4c4b2ed2bebc847bbf58c1caed7ed"}, + {file = "habluetooth-5.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:df4210cdcadc3154caf25027c0aec052c0eb9b7a84ccc49c23341e230a1ae9c7"}, + {file = "habluetooth-5.3.0-cp314-cp314-win32.whl", hash = "sha256:df0cfe5c7e6621d4191f0abb31d0d954d277c3ee1c800f0918bcff8d8e9704cc"}, + {file = "habluetooth-5.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:e96835e09b01a11f7067fdd1e56b1f3fd58f3a1a2a0ddc27835b04e5b8b2f31e"}, + {file = "habluetooth-5.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:660908e7da797db7e1aefeef7989caf2a71e35503959f3e195e8160fbe783e60"}, + {file = "habluetooth-5.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f9ddea6b686ab0888091a67b8b0745ae5efb6d5fe1ddf676cb0ce2c435bc6629"}, + {file = "habluetooth-5.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1df64f2439b36e58b8393327b0f8ef5a64284a20729e8497c4028bcb73cafa30"}, + {file = "habluetooth-5.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3cb7720e0a406e71d0fb2344dc6e4d3947525b632b26542fc6c1db4a03336fd"}, + {file = "habluetooth-5.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22e47a11018868865d095220f743871bda6a2e976270840bd5424ee75cc2af41"}, + {file = "habluetooth-5.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:df4fa114647b413a6038490008e07fca0263f725d2190d632cff006ecf485d3c"}, + {file = "habluetooth-5.3.0-cp314-cp314t-win32.whl", hash = "sha256:ba728e8b37ad8c9a536f6d0daebf336287e3c5b46a7fd44f3b1f8163aa84efbe"}, + {file = "habluetooth-5.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:3f638985a9538ffa46ce7bf2d507a8c825ec5aae8e98692c820a0001aa9dc8e2"}, + {file = "habluetooth-5.3.0.tar.gz", hash = "sha256:2d60e828ea2ca8551dc475ed4a4e1e6b807119c131f84d6b4390050a1523101d"}, ] [package.dependencies] async-interrupt = ">=1.1.1" bleak = ">=1.0.1" -bleak-retry-connector = ">=4" -bluetooth-adapters = ">=2" +bleak-retry-connector = ">=4.2.0" +bluetooth-adapters = ">=2.1.0" bluetooth-auto-recovery = ">=1.5.1" bluetooth-data-tools = ">=1.28.0" btsocket = ">=0.3.0" @@ -1527,18 +1521,18 @@ dbus-fast = {version = ">=2.30.2", markers = "platform_system == \"Linux\""} [[package]] name = "hass-nabucasa" -version = "0.111.1" +version = "1.1.0" description = "Home Assistant cloud integration by Nabu Casa, Inc." optional = false python-versions = ">=3.13" groups = ["main"] files = [ - {file = "hass_nabucasa-0.111.1-py3-none-any.whl", hash = "sha256:446177dde8af6ef7c5af137ceb47f9b3054d8f477f6625f288eedda0856445d7"}, - {file = "hass_nabucasa-0.111.1.tar.gz", hash = "sha256:184541ca05d598ca01d9d52839b4b280032c701d8abb3e2809940a0ebf31e43b"}, + {file = "hass_nabucasa-1.1.0-py3-none-any.whl", hash = "sha256:d10498e0f61d19369e12eba121c391cc5a79f7b71d6d3295ca0e8ff7ecfb96f6"}, + {file = "hass_nabucasa-1.1.0.tar.gz", hash = "sha256:c9714b54ed94c8e32a8a2eec2b3e42e57739c8fa85eda164b08b292f1f311246"}, ] [package.dependencies] -acme = "4.1.1" +acme = "4.2.0" aiohttp = ">=3.6.1" async_timeout = ">=4" atomicwrites-homeassistant = "1.4.1" @@ -1549,12 +1543,12 @@ josepy = ">=2,<3" pycognito = "2024.5.1" PyJWT = ">=2.8.0" sentence-stream = "1.1.0" -snitun = "0.40.0" +snitun = "0.44.0" webrtc-models = "<1.0.0" yarl = ">=1.20,<2" [package.extras] -test = ["codespell (==2.4.1)", "freezegun (==1.5.4)", "mypy (==1.17.1)", "pre-commit (==4.2.0)", "pre-commit-hooks (==5.0.0)", "pylint (==3.3.7)", "pytest (==8.4.1)", "pytest-aiohttp (==1.1.0)", "pytest-socket (==0.7.0)", "pytest-timeout (==2.4.0)", "ruff (==0.12.7)", "syrupy (==4.9.1)", "tomli (==2.2.1)", "types_atomicwrites (==1.4.5.1)", "types_pyOpenSSL (==24.1.0.20240722)", "xmltodict (==0.14.2)"] +test = ["codespell (==2.4.1)", "freezegun (==1.5.5)", "mypy (==1.17.1)", "pre-commit (==4.3.0)", "pre-commit-hooks (==6.0.0)", "pylint (==3.3.8)", "pytest (==8.4.1)", "pytest-aiohttp (==1.1.0)", "pytest-socket (==0.7.0)", "pytest-timeout (==2.4.0)", "ruff (==0.12.11)", "syrupy (==4.9.1)", "tomli (==2.2.1)", "types_atomicwrites (==1.4.5.1)", "types_pyOpenSSL (==24.1.0.20240722)", "xmltodict (==0.14.2)"] [[package]] name = "home-assistant-bluetooth" @@ -1573,19 +1567,19 @@ habluetooth = ">=3.0" [[package]] name = "homeassistant" -version = "2025.8.0" +version = "2025.9.0" description = "Open-source home automation platform running on Python 3." optional = false python-versions = ">=3.13.2" groups = ["main"] files = [ - {file = "homeassistant-2025.8.0-py3-none-any.whl", hash = "sha256:b603e8f3fb9d1e107422c2f8816d6733587d32ad4807722f9eeea3cfa12be0a5"}, - {file = "homeassistant-2025.8.0.tar.gz", hash = "sha256:534eadb571167b8ea1f0edb0bab63268237bf047520af3acd7455b9f239076c3"}, + {file = "homeassistant-2025.9.0-py3-none-any.whl", hash = "sha256:51bda990b96c419f5e2a3410aa1a636e454ac5a65616ea8ec663f04956c5a725"}, + {file = "homeassistant-2025.9.0.tar.gz", hash = "sha256:f2afb8dc2ecedb3dc809b79a1c7099e2b0ad177631aec880904578f7716cedfc"}, ] [package.dependencies] aiodns = "3.5.0" -aiohasupervisor = "0.3.1" +aiohasupervisor = "0.3.2" aiohttp = "3.12.15" aiohttp-asyncmdnsresolver = "0.1.1" aiohttp_cors = "0.8.1" @@ -1604,13 +1598,13 @@ ciso8601 = "2.3.2" cronsim = "2.6" cryptography = "45.0.3" fnv-hash-fast = "1.5.0" -hass-nabucasa = "0.111.1" +hass-nabucasa = "1.1.0" home-assistant-bluetooth = "1.13.1" httpx = "0.28.1" ifaddr = "0.2.0" Jinja2 = "3.1.6" lru-dict = "1.3.0" -orjson = "3.11.1" +orjson = "3.11.3" packaging = ">=23.1" Pillow = "11.3.0" propcache = "0.3.2" @@ -1624,13 +1618,13 @@ securetar = "2025.2.1" SQLAlchemy = "2.0.41" standard-aifc = "3.13.0" standard-telnetlib = "3.13.0" -typing-extensions = ">=4.14.0,<5.0" +typing-extensions = ">=4.15.0,<5.0" ulid-transform = "1.4.0" urllib3 = ">=2.0" -uv = "0.7.1" +uv = "0.8.9" voluptuous = "0.15.2" voluptuous-openapi = "0.1.0" -voluptuous-serialize = "2.6.0" +voluptuous-serialize = "2.7.0" webrtc-models = "0.3.0" yarl = "1.20.1" zeroconf = "0.147.0" @@ -2120,95 +2114,95 @@ files = [ [[package]] name = "orjson" -version = "3.11.1" +version = "3.11.3" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "orjson-3.11.1-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:92d771c492b64119456afb50f2dff3e03a2db8b5af0eba32c5932d306f970532"}, - {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0085ef83a4141c2ed23bfec5fecbfdb1e95dd42fc8e8c76057bdeeec1608ea65"}, - {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5caf7f13f2e1b4e137060aed892d4541d07dabc3f29e6d891e2383c7ed483440"}, - {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f716bcc166524eddfcf9f13f8209ac19a7f27b05cf591e883419079d98c8c99d"}, - {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:507d6012fab05465d8bf21f5d7f4635ba4b6d60132874e349beff12fb51af7fe"}, - {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1545083b0931f754c80fd2422a73d83bea7a6d1b6de104a5f2c8dd3d64c291e"}, - {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e217ce3bad76351e1eb29ebe5ca630326f45cd2141f62620107a229909501a3"}, - {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06ef26e009304bda4df42e4afe518994cde6f89b4b04c0ff24021064f83f4fbb"}, - {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ba49683b87bea3ae1489a88e766e767d4f423a669a61270b6d6a7ead1c33bd65"}, - {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5072488fcc5cbcda2ece966d248e43ea1d222e19dd4c56d3f82747777f24d864"}, - {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f58ae2bcd119226fe4aa934b5880fe57b8e97b69e51d5d91c88a89477a307016"}, - {file = "orjson-3.11.1-cp310-cp310-win32.whl", hash = "sha256:6723be919c07906781b9c63cc52dc7d2fb101336c99dd7e85d3531d73fb493f7"}, - {file = "orjson-3.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:5fd44d69ddfdfb4e8d0d83f09d27a4db34930fba153fbf79f8d4ae8b47914e04"}, - {file = "orjson-3.11.1-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:15e2a57ce3b57c1a36acffcc02e823afefceee0a532180c2568c62213c98e3ef"}, - {file = "orjson-3.11.1-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:17040a83ecaa130474af05bbb59a13cfeb2157d76385556041f945da936b1afd"}, - {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a68f23f09e5626cc0867a96cf618f68b91acb4753d33a80bf16111fd7f9928c"}, - {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47e07528bb6ccbd6e32a55e330979048b59bfc5518b47c89bc7ab9e3de15174a"}, - {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3807cce72bf40a9d251d689cbec28d2efd27e0f6673709f948f971afd52cb09"}, - {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b2dc7e88da4ca201c940f5e6127998d9e89aa64264292334dad62854bc7fc27"}, - {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3091dad33ac9e67c0a550cfff8ad5be156e2614d6f5d2a9247df0627751a1495"}, - {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ed0fce2307843b79a0c83de49f65b86197f1e2310de07af9db2a1a77a61ce4c"}, - {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a31e84782a18c30abd56774c0cfa7b9884589f4d37d9acabfa0504dad59bb9d"}, - {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26b6c821abf1ae515fbb8e140a2406c9f9004f3e52acb780b3dee9bfffddbd84"}, - {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f857b3d134b36a8436f1e24dcb525b6b945108b30746c1b0b556200b5cb76d39"}, - {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df146f2a14116ce80f7da669785fcb411406d8e80136558b0ecda4c924b9ac55"}, - {file = "orjson-3.11.1-cp311-cp311-win32.whl", hash = "sha256:d777c57c1f86855fe5492b973f1012be776e0398571f7cc3970e9a58ecf4dc17"}, - {file = "orjson-3.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:e9a5fd589951f02ec2fcb8d69339258bbf74b41b104c556e6d4420ea5e059313"}, - {file = "orjson-3.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:4cddbe41ee04fddad35d75b9cf3e3736ad0b80588280766156b94783167777af"}, - {file = "orjson-3.11.1-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2b7c8be96db3a977367250c6367793a3c5851a6ca4263f92f0b48d00702f9910"}, - {file = "orjson-3.11.1-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:72e18088f567bd4a45db5e3196677d9ed1605e356e500c8e32dd6e303167a13d"}, - {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d346e2ae1ce17888f7040b65a5a4a0c9734cb20ffbd228728661e020b4c8b3a5"}, - {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4bda5426ebb02ceb806a7d7ec9ba9ee5e0c93fca62375151a7b1c00bc634d06b"}, - {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10506cebe908542c4f024861102673db534fd2e03eb9b95b30d94438fa220abf"}, - {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45202ee3f5494644e064c41abd1320497fb92fd31fc73af708708af664ac3b56"}, - {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5adaf01b92e0402a9ac5c3ebe04effe2bbb115f0914a0a53d34ea239a746289"}, - {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6162a1a757a1f1f4a94bc6ffac834a3602e04ad5db022dd8395a54ed9dd51c81"}, - {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:78404206977c9f946613d3f916727c189d43193e708d760ea5d4b2087d6b0968"}, - {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:db48f8e81072e26df6cdb0e9fff808c28597c6ac20a13d595756cf9ba1fed48a"}, - {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0c1e394e67ced6bb16fea7054d99fbdd99a539cf4d446d40378d4c06e0a8548d"}, - {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e7a840752c93d4eecd1378e9bb465c3703e127b58f675cd5c620f361b6cf57a4"}, - {file = "orjson-3.11.1-cp312-cp312-win32.whl", hash = "sha256:4537b0e09f45d2b74cb69c7f39ca1e62c24c0488d6bf01cd24673c74cd9596bf"}, - {file = "orjson-3.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:dbee6b050062540ae404530cacec1bf25e56e8d87d8d9b610b935afeb6725cae"}, - {file = "orjson-3.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:f55e557d4248322d87c4673e085c7634039ff04b47bfc823b87149ae12bef60d"}, - {file = "orjson-3.11.1-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53cfefe4af059e65aabe9683f76b9c88bf34b4341a77d329227c2424e0e59b0e"}, - {file = "orjson-3.11.1-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:93d5abed5a6f9e1b6f9b5bf6ed4423c11932b5447c2f7281d3b64e0f26c6d064"}, - {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbf06642f3db2966df504944cdd0eb68ca2717f0353bb20b20acd78109374a6"}, - {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dddf4e78747fa7f2188273f84562017a3c4f0824485b78372513c1681ea7a894"}, - {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa3fe8653c9f57f0e16f008e43626485b6723b84b2f741f54d1258095b655912"}, - {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6334d2382aff975a61f6f4d1c3daf39368b887c7de08f7c16c58f485dcf7adb2"}, - {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3d0855b643f259ee0cb76fe3df4c04483354409a520a902b067c674842eb6b8"}, - {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0eacdfeefd0a79987926476eb16e0245546bedeb8febbbbcf4b653e79257a8e4"}, - {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ed07faf9e4873518c60480325dcbc16d17c59a165532cccfb409b4cdbaeff24"}, - {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d308dd578ae3658f62bb9eba54801533225823cd3248c902be1ebc79b5e014"}, - {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c4aa13ca959ba6b15c0a98d3d204b850f9dc36c08c9ce422ffb024eb30d6e058"}, - {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:be3d0653322abc9b68e5bcdaee6cfd58fcbe9973740ab222b87f4d687232ab1f"}, - {file = "orjson-3.11.1-cp313-cp313-win32.whl", hash = "sha256:4dd34e7e2518de8d7834268846f8cab7204364f427c56fb2251e098da86f5092"}, - {file = "orjson-3.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:d6895d32032b6362540e6d0694b19130bb4f2ad04694002dce7d8af588ca5f77"}, - {file = "orjson-3.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:bb7c36d5d3570fcbb01d24fa447a21a7fe5a41141fd88e78f7994053cc4e28f4"}, - {file = "orjson-3.11.1-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7b71ef394327b3d0b39f6ea7ade2ecda2731a56c6a7cbf0d6a7301203b92a89b"}, - {file = "orjson-3.11.1-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:77c0fe28ed659b62273995244ae2aa430e432c71f86e4573ab16caa2f2e3ca5e"}, - {file = "orjson-3.11.1-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:1495692f1f1ba2467df429343388a0ed259382835922e124c0cfdd56b3d1f727"}, - {file = "orjson-3.11.1-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:08c6a762fca63ca4dc04f66c48ea5d2428db55839fec996890e1bfaf057b658c"}, - {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e26794fe3976810b2c01fda29bd9ac7c91a3c1284b29cc9a383989f7b614037"}, - {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4b4b4f8f0b1d3ef8dc73e55363a0ffe012a42f4e2f1a140bf559698dca39b3fa"}, - {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:848be553ea35aa89bfefbed2e27c8a41244c862956ab8ba00dc0b27e84fd58de"}, - {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c964c29711a4b1df52f8d9966f015402a6cf87753a406c1c4405c407dd66fd45"}, - {file = "orjson-3.11.1-cp314-cp314-win32.whl", hash = "sha256:33aada2e6b6bc9c540d396528b91e666cedb383740fee6e6a917f561b390ecb1"}, - {file = "orjson-3.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:68e10fd804e44e36188b9952543e3fa22f5aa8394da1b5283ca2b423735c06e8"}, - {file = "orjson-3.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:f3cf6c07f8b32127d836be8e1c55d4f34843f7df346536da768e9f73f22078a1"}, - {file = "orjson-3.11.1-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3d593a9e0bccf2c7401ae53625b519a7ad7aa555b1c82c0042b322762dc8af4e"}, - {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0baad413c498fc1eef568504f11ea46bc71f94b845c075e437da1e2b85b4fb86"}, - {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:22cf17ae1dae3f9b5f37bfcdba002ed22c98bbdb70306e42dc18d8cc9b50399a"}, - {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e855c1e97208133ce88b3ef6663c9a82ddf1d09390cd0856a1638deee0390c3c"}, - {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5861c5f7acff10599132854c70ab10abf72aebf7c627ae13575e5f20b1ab8fe"}, - {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1e6415c5b5ff3a616a6dafad7b6ec303a9fc625e9313c8e1268fb1370a63dcb"}, - {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:912579642f5d7a4a84d93c5eed8daf0aa34e1f2d3f4dc6571a8e418703f5701e"}, - {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2092e1d3b33f64e129ff8271642afddc43763c81f2c30823b4a4a4a5f2ea5b55"}, - {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:b8ac64caba1add2c04e9cd4782d4d0c4d6c554b7a3369bdec1eed7854c98db7b"}, - {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:23196b826ebc85c43f8e27bee0ab33c5fb13a29ea47fb4fcd6ebb1e660eb0252"}, - {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f2d3364cfad43003f1e3d564a069c8866237cca30f9c914b26ed2740b596ed00"}, - {file = "orjson-3.11.1-cp39-cp39-win32.whl", hash = "sha256:20b0dca94ea4ebe4628330de50975b35817a3f52954c1efb6d5d0498a3bbe581"}, - {file = "orjson-3.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:200c3ad7ed8b5d31d49143265dfebd33420c4b61934ead16833b5cd2c3d241be"}, - {file = "orjson-3.11.1.tar.gz", hash = "sha256:48d82770a5fd88778063604c566f9c7c71820270c9cc9338d25147cbf34afd96"}, + {file = "orjson-3.11.3-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:29cb1f1b008d936803e2da3d7cba726fc47232c45df531b29edf0b232dd737e7"}, + {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97dceed87ed9139884a55db8722428e27bd8452817fbf1869c58b49fecab1120"}, + {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58533f9e8266cb0ac298e259ed7b4d42ed3fa0b78ce76860626164de49e0d467"}, + {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c212cfdd90512fe722fa9bd620de4d46cda691415be86b2e02243242ae81873"}, + {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff835b5d3e67d9207343effb03760c00335f8b5285bfceefd4dc967b0e48f6a"}, + {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5aa4682912a450c2db89cbd92d356fef47e115dffba07992555542f344d301b"}, + {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d18dd34ea2e860553a579df02041845dee0af8985dff7f8661306f95504ddf"}, + {file = "orjson-3.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8b11701bc43be92ea42bd454910437b355dfb63696c06fe953ffb40b5f763b4"}, + {file = "orjson-3.11.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:90368277087d4af32d38bd55f9da2ff466d25325bf6167c8f382d8ee40cb2bbc"}, + {file = "orjson-3.11.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fd7ff459fb393358d3a155d25b275c60b07a2c83dcd7ea962b1923f5a1134569"}, + {file = "orjson-3.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f8d902867b699bcd09c176a280b1acdab57f924489033e53d0afe79817da37e6"}, + {file = "orjson-3.11.3-cp310-cp310-win32.whl", hash = "sha256:bb93562146120bb51e6b154962d3dadc678ed0fce96513fa6bc06599bb6f6edc"}, + {file = "orjson-3.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:976c6f1975032cc327161c65d4194c549f2589d88b105a5e3499429a54479770"}, + {file = "orjson-3.11.3-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d2ae0cc6aeb669633e0124531f342a17d8e97ea999e42f12a5ad4adaa304c5f"}, + {file = "orjson-3.11.3-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:ba21dbb2493e9c653eaffdc38819b004b7b1b246fb77bfc93dc016fe664eac91"}, + {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00f1a271e56d511d1569937c0447d7dce5a99a33ea0dec76673706360a051904"}, + {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b67e71e47caa6680d1b6f075a396d04fa6ca8ca09aafb428731da9b3ea32a5a6"}, + {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7d012ebddffcce8c85734a6d9e5f08180cd3857c5f5a3ac70185b43775d043d"}, + {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd759f75d6b8d1b62012b7f5ef9461d03c804f94d539a5515b454ba3a6588038"}, + {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6890ace0809627b0dff19cfad92d69d0fa3f089d3e359a2a532507bb6ba34efb"}, + {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9d4a5e041ae435b815e568537755773d05dac031fee6a57b4ba70897a44d9d2"}, + {file = "orjson-3.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d68bf97a771836687107abfca089743885fb664b90138d8761cce61d5625d55"}, + {file = "orjson-3.11.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bfc27516ec46f4520b18ef645864cee168d2a027dbf32c5537cb1f3e3c22dac1"}, + {file = "orjson-3.11.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f66b001332a017d7945e177e282a40b6997056394e3ed7ddb41fb1813b83e824"}, + {file = "orjson-3.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:212e67806525d2561efbfe9e799633b17eb668b8964abed6b5319b2f1cfbae1f"}, + {file = "orjson-3.11.3-cp311-cp311-win32.whl", hash = "sha256:6e8e0c3b85575a32f2ffa59de455f85ce002b8bdc0662d6b9c2ed6d80ab5d204"}, + {file = "orjson-3.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:6be2f1b5d3dc99a5ce5ce162fc741c22ba9f3443d3dd586e6a1211b7bc87bc7b"}, + {file = "orjson-3.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:fafb1a99d740523d964b15c8db4eabbfc86ff29f84898262bf6e3e4c9e97e43e"}, + {file = "orjson-3.11.3-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8c752089db84333e36d754c4baf19c0e1437012242048439c7e80eb0e6426e3b"}, + {file = "orjson-3.11.3-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:9b8761b6cf04a856eb544acdd82fc594b978f12ac3602d6374a7edb9d86fd2c2"}, + {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b13974dc8ac6ba22feaa867fc19135a3e01a134b4f7c9c28162fed4d615008a"}, + {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f83abab5bacb76d9c821fd5c07728ff224ed0e52d7a71b7b3de822f3df04e15c"}, + {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6fbaf48a744b94091a56c62897b27c31ee2da93d826aa5b207131a1e13d4064"}, + {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc779b4f4bba2847d0d2940081a7b6f7b5877e05408ffbb74fa1faf4a136c424"}, + {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd4b909ce4c50faa2192da6bb684d9848d4510b736b0611b6ab4020ea6fd2d23"}, + {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:524b765ad888dc5518bbce12c77c2e83dee1ed6b0992c1790cc5fb49bb4b6667"}, + {file = "orjson-3.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:84fd82870b97ae3cdcea9d8746e592b6d40e1e4d4527835fc520c588d2ded04f"}, + {file = "orjson-3.11.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbecb9709111be913ae6879b07bafd4b0785b44c1eb5cac8ac76da048b3885a1"}, + {file = "orjson-3.11.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9dba358d55aee552bd868de348f4736ca5a4086d9a62e2bfbbeeb5629fe8b0cc"}, + {file = "orjson-3.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eabcf2e84f1d7105f84580e03012270c7e97ecb1fb1618bda395061b2a84a049"}, + {file = "orjson-3.11.3-cp312-cp312-win32.whl", hash = "sha256:3782d2c60b8116772aea8d9b7905221437fdf53e7277282e8d8b07c220f96cca"}, + {file = "orjson-3.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:79b44319268af2eaa3e315b92298de9a0067ade6e6003ddaef72f8e0bedb94f1"}, + {file = "orjson-3.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:0e92a4e83341ef79d835ca21b8bd13e27c859e4e9e4d7b63defc6e58462a3710"}, + {file = "orjson-3.11.3-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:af40c6612fd2a4b00de648aa26d18186cd1322330bd3a3cc52f87c699e995810"}, + {file = "orjson-3.11.3-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:9f1587f26c235894c09e8b5b7636a38091a9e6e7fe4531937534749c04face43"}, + {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61dcdad16da5bb486d7227a37a2e789c429397793a6955227cedbd7252eb5a27"}, + {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11c6d71478e2cbea0a709e8a06365fa63da81da6498a53e4c4f065881d21ae8f"}, + {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff94112e0098470b665cb0ed06efb187154b63649403b8d5e9aedeb482b4548c"}, + {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b756575aaa2a855a75192f356bbda11a89169830e1439cfb1a3e1a6dde7be"}, + {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9416cc19a349c167ef76135b2fe40d03cea93680428efee8771f3e9fb66079d"}, + {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b822caf5b9752bc6f246eb08124c3d12bf2175b66ab74bac2ef3bbf9221ce1b2"}, + {file = "orjson-3.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:414f71e3bdd5573893bf5ecdf35c32b213ed20aa15536fe2f588f946c318824f"}, + {file = "orjson-3.11.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:828e3149ad8815dc14468f36ab2a4b819237c155ee1370341b91ea4c8672d2ee"}, + {file = "orjson-3.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac9e05f25627ffc714c21f8dfe3a579445a5c392a9c8ae7ba1d0e9fb5333f56e"}, + {file = "orjson-3.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e44fbe4000bd321d9f3b648ae46e0196d21577cf66ae684a96ff90b1f7c93633"}, + {file = "orjson-3.11.3-cp313-cp313-win32.whl", hash = "sha256:2039b7847ba3eec1f5886e75e6763a16e18c68a63efc4b029ddf994821e2e66b"}, + {file = "orjson-3.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:29be5ac4164aa8bdcba5fa0700a3c9c316b411d8ed9d39ef8a882541bd452fae"}, + {file = "orjson-3.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:18bd1435cb1f2857ceb59cfb7de6f92593ef7b831ccd1b9bfb28ca530e539dce"}, + {file = "orjson-3.11.3-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cf4b81227ec86935568c7edd78352a92e97af8da7bd70bdfdaa0d2e0011a1ab4"}, + {file = "orjson-3.11.3-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:bc8bc85b81b6ac9fc4dae393a8c159b817f4c2c9dee5d12b773bddb3b95fc07e"}, + {file = "orjson-3.11.3-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:88dcfc514cfd1b0de038443c7b3e6a9797ffb1b3674ef1fd14f701a13397f82d"}, + {file = "orjson-3.11.3-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d61cd543d69715d5fc0a690c7c6f8dcc307bc23abef9738957981885f5f38229"}, + {file = "orjson-3.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2b7b153ed90ababadbef5c3eb39549f9476890d339cf47af563aea7e07db2451"}, + {file = "orjson-3.11.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:7909ae2460f5f494fecbcd10613beafe40381fd0316e35d6acb5f3a05bfda167"}, + {file = "orjson-3.11.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2030c01cbf77bc67bee7eef1e7e31ecf28649353987775e3583062c752da0077"}, + {file = "orjson-3.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0169ebd1cbd94b26c7a7ad282cf5c2744fce054133f959e02eb5265deae1872"}, + {file = "orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d"}, + {file = "orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804"}, + {file = "orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc"}, + {file = "orjson-3.11.3-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:56afaf1e9b02302ba636151cfc49929c1bb66b98794291afd0e5f20fecaf757c"}, + {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:913f629adef31d2d350d41c051ce7e33cf0fd06a5d1cb28d49b1899b23b903aa"}, + {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0a23b41f8f98b4e61150a03f83e4f0d566880fe53519d445a962929a4d21045"}, + {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d721fee37380a44f9d9ce6c701b3960239f4fb3d5ceea7f31cbd43882edaa2f"}, + {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73b92a5b69f31b1a58c0c7e31080aeaec49c6e01b9522e71ff38d08f15aa56de"}, + {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2489b241c19582b3f1430cc5d732caefc1aaf378d97e7fb95b9e56bed11725f"}, + {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5189a5dab8b0312eadaf9d58d3049b6a52c454256493a557405e77a3d67ab7f"}, + {file = "orjson-3.11.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9d8787bdfbb65a85ea76d0e96a3b1bed7bf0fbcb16d40408dc1172ad784a49d2"}, + {file = "orjson-3.11.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8e531abd745f51f8035e207e75e049553a86823d189a51809c078412cefb399a"}, + {file = "orjson-3.11.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8ab962931015f170b97a3dd7bd933399c1bae8ed8ad0fb2a7151a5654b6941c7"}, + {file = "orjson-3.11.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:124d5ba71fee9c9902c4a7baa9425e663f7f0aecf73d31d54fe3dd357d62c1a7"}, + {file = "orjson-3.11.3-cp39-cp39-win32.whl", hash = "sha256:22724d80ee5a815a44fc76274bb7ba2e7464f5564aacb6ecddaa9970a83e3225"}, + {file = "orjson-3.11.3-cp39-cp39-win_amd64.whl", hash = "sha256:215c595c792a87d4407cb72dd5e0f6ee8e694ceeb7f9102b533c5a9bf2a916bb"}, + {file = "orjson-3.11.3.tar.gz", hash = "sha256:1c0603b1d2ffcd43a411d64797a19556ef76958aef1c182f22dc30860152a98a"}, ] [[package]] @@ -2350,14 +2344,14 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.3.8" +version = "4.4.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"}, - {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"}, + {file = "platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85"}, + {file = "platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf"}, ] [package.extras] @@ -2816,14 +2810,14 @@ test = ["pretend", "pytest (>=3.0.1)", "pytest-rerunfailures"] [[package]] name = "pyrfc3339" -version = "2.0.1" +version = "2.1.0" description = "Generate and parse RFC 3339 timestamps" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pyRFC3339-2.0.1-py3-none-any.whl", hash = "sha256:30b70a366acac3df7386b558c21af871522560ed7f3f73cf344b8c2cbb8b0c9d"}, - {file = "pyrfc3339-2.0.1.tar.gz", hash = "sha256:e47843379ea35c1296c3b6c67a948a1a490ae0584edfcbdea0eaffb5dd29960b"}, + {file = "pyrfc3339-2.1.0-py3-none-any.whl", hash = "sha256:560f3f972e339f579513fe1396974352fd575ef27caff160a38b312252fcddf3"}, + {file = "pyrfc3339-2.1.0.tar.gz", hash = "sha256:c569a9714faf115cdb20b51e830e798c1f4de8dabb07f6ff25d221b5d09d8d7f"}, ] [[package]] @@ -3073,14 +3067,14 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruamel-yaml" -version = "0.18.14" +version = "0.18.15" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "ruamel.yaml-0.18.14-py3-none-any.whl", hash = "sha256:710ff198bb53da66718c7db27eec4fbcc9aa6ca7204e4c1df2f282b6fe5eb6b2"}, - {file = "ruamel.yaml-0.18.14.tar.gz", hash = "sha256:7227b76aaec364df15936730efbf7d72b30c0b79b1d578bbb8e3dcb2d81f52b7"}, + {file = "ruamel.yaml-0.18.15-py3-none-any.whl", hash = "sha256:148f6488d698b7a5eded5ea793a025308b25eca97208181b6a026037f391f701"}, + {file = "ruamel.yaml-0.18.15.tar.gz", hash = "sha256:dbfca74b018c4c3fba0b9cc9ee33e53c371194a9000e694995e620490fd40700"}, ] [package.dependencies] @@ -3149,30 +3143,31 @@ files = [ [[package]] name = "ruff" -version = "0.12.8" +version = "0.12.10" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.12.8-py3-none-linux_armv6l.whl", hash = "sha256:63cb5a5e933fc913e5823a0dfdc3c99add73f52d139d6cd5cc8639d0e0465513"}, - {file = "ruff-0.12.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a9bbe28f9f551accf84a24c366c1aa8774d6748438b47174f8e8565ab9dedbc"}, - {file = "ruff-0.12.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2fae54e752a3150f7ee0e09bce2e133caf10ce9d971510a9b925392dc98d2fec"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0acbcf01206df963d9331b5838fb31f3b44fa979ee7fa368b9b9057d89f4a53"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae3e7504666ad4c62f9ac8eedb52a93f9ebdeb34742b8b71cd3cccd24912719f"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb82efb5d35d07497813a1c5647867390a7d83304562607f3579602fa3d7d46f"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dbea798fc0065ad0b84a2947b0aff4233f0cb30f226f00a2c5850ca4393de609"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49ebcaccc2bdad86fd51b7864e3d808aad404aab8df33d469b6e65584656263a"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ac9c570634b98c71c88cb17badd90f13fc076a472ba6ef1d113d8ed3df109fb"}, - {file = "ruff-0.12.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560e0cd641e45591a3e42cb50ef61ce07162b9c233786663fdce2d8557d99818"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:71c83121512e7743fba5a8848c261dcc454cafb3ef2934a43f1b7a4eb5a447ea"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:de4429ef2ba091ecddedd300f4c3f24bca875d3d8b23340728c3cb0da81072c3"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a2cab5f60d5b65b50fba39a8950c8746df1627d54ba1197f970763917184b161"}, - {file = "ruff-0.12.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:45c32487e14f60b88aad6be9fd5da5093dbefb0e3e1224131cb1d441d7cb7d46"}, - {file = "ruff-0.12.8-py3-none-win32.whl", hash = "sha256:daf3475060a617fd5bc80638aeaf2f5937f10af3ec44464e280a9d2218e720d3"}, - {file = "ruff-0.12.8-py3-none-win_amd64.whl", hash = "sha256:7209531f1a1fcfbe8e46bcd7ab30e2f43604d8ba1c49029bb420b103d0b5f76e"}, - {file = "ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749"}, - {file = "ruff-0.12.8.tar.gz", hash = "sha256:4cb3a45525176e1009b2b64126acf5f9444ea59066262791febf55e40493a033"}, + {file = "ruff-0.12.10-py3-none-linux_armv6l.whl", hash = "sha256:8b593cb0fb55cc8692dac7b06deb29afda78c721c7ccfed22db941201b7b8f7b"}, + {file = "ruff-0.12.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ebb7333a45d56efc7c110a46a69a1b32365d5c5161e7244aaf3aa20ce62399c1"}, + {file = "ruff-0.12.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d59e58586829f8e4a9920788f6efba97a13d1fa320b047814e8afede381c6839"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:822d9677b560f1fdeab69b89d1f444bf5459da4aa04e06e766cf0121771ab844"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b4a64f4062a50c75019c61c7017ff598cb444984b638511f48539d3a1c98db"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6f4064c69d2542029b2a61d39920c85240c39837599d7f2e32e80d36401d6e"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:059e863ea3a9ade41407ad71c1de2badfbe01539117f38f763ba42a1206f7559"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bef6161e297c68908b7218fa6e0e93e99a286e5ed9653d4be71e687dff101cf"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f1345fbf8fb0531cd722285b5f15af49b2932742fc96b633e883da8d841896b"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f68433c4fbc63efbfa3ba5db31727db229fa4e61000f452c540474b03de52a9"}, + {file = "ruff-0.12.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:141ce3d88803c625257b8a6debf4a0473eb6eed9643a6189b68838b43e78165a"}, + {file = "ruff-0.12.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f3fc21178cd44c98142ae7590f42ddcb587b8e09a3b849cbc84edb62ee95de60"}, + {file = "ruff-0.12.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7d1a4e0bdfafcd2e3e235ecf50bf0176f74dd37902f241588ae1f6c827a36c56"}, + {file = "ruff-0.12.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e67d96827854f50b9e3e8327b031647e7bcc090dbe7bb11101a81a3a2cbf1cc9"}, + {file = "ruff-0.12.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ae479e1a18b439c59138f066ae79cc0f3ee250712a873d00dbafadaad9481e5b"}, + {file = "ruff-0.12.10-py3-none-win32.whl", hash = "sha256:9de785e95dc2f09846c5e6e1d3a3d32ecd0b283a979898ad427a9be7be22b266"}, + {file = "ruff-0.12.10-py3-none-win_amd64.whl", hash = "sha256:7837eca8787f076f67aba2ca559cefd9c5cbc3a9852fd66186f4201b87c1563e"}, + {file = "ruff-0.12.10-py3-none-win_arm64.whl", hash = "sha256:cc138cc06ed9d4bfa9d667a65af7172b47840e1a98b02ce7011c391e54635ffc"}, + {file = "ruff-0.12.10.tar.gz", hash = "sha256:189ab65149d11ea69a2d775343adf5f49bb2426fc4780f65ee33b423ad2e47f9"}, ] [[package]] @@ -3252,25 +3247,23 @@ files = [ [[package]] name = "snitun" -version = "0.40.0" +version = "0.44.0" description = "SNI proxy with TCP multiplexer" optional = false -python-versions = ">=3.10" +python-versions = ">=3.12" groups = ["main"] files = [ - {file = "snitun-0.40.0-py3-none-any.whl", hash = "sha256:dedb58d3042d13311142b55337ad6ce6ed339e43da9dca4c4c2c83df77c64ac0"}, - {file = "snitun-0.40.0.tar.gz", hash = "sha256:f5a70b3aab07524f196d27baf7a8f8774b3b00c442e91392539dd11dbd033c9c"}, + {file = "snitun-0.44.0-py3-none-any.whl", hash = "sha256:8c351ed936c9768d68b1dc5a33ad91c1b8d57cad09f29e73e0b19df0e573c08b"}, + {file = "snitun-0.44.0.tar.gz", hash = "sha256:b9f693568ea6a7da6a9fa459597a404c1657bfb9259eb076005a8eb1247df087"}, ] [package.dependencies] aiohttp = ">=3.9.3" -async_timeout = ">=3.0.1" -attrs = ">=18.2.0" cryptography = ">=2.5" [package.extras] -lint = ["pylint (==3.2.7)", "ruff (==0.8.1)"] -test = ["pytest (==8.3.4)", "pytest-aiohttp (==1.0.5)", "pytest-timeout (==2.3.1)"] +lint = ["ruff (==0.12.4)"] +test = ["covdefaults (==2.3.0)", "pytest (==8.4.1)", "pytest-aiohttp (==1.1.0)", "pytest-codspeed (==3.2.0)", "pytest-cov (==6.2.1)", "pytest-timeout (==2.4.0)"] [[package]] name = "sqlalchemy" @@ -3434,14 +3427,14 @@ files = [ [[package]] name = "typing-extensions" -version = "4.14.1" +version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, - {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, ] [[package]] @@ -3512,42 +3505,43 @@ files = [ [[package]] name = "uv" -version = "0.7.1" +version = "0.8.9" description = "An extremely fast Python package and project manager, written in Rust." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "uv-0.7.1-py3-none-linux_armv6l.whl", hash = "sha256:ea2024e6a9daeea3ff6cab8ad4afe3b2aa0be9e07bad57646a749896e58648ad"}, - {file = "uv-0.7.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d9c0c70bd3734cdae20cf22889a0394307a86451bb7c9126f0542eb998dd1472"}, - {file = "uv-0.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5526f68ce9a5ba35ef13a14d144dc834b4940bd460fedc55f8313f9b7534b63c"}, - {file = "uv-0.7.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:1d6f914601b769ad0f9a090573e2dc4365e0eaeb377d09cd74c5d47c97002c20"}, - {file = "uv-0.7.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c5572a2b1d6dbf1cbff315e55931f891d8706ef5ed76e94a7d5e6e6dae075b3a"}, - {file = "uv-0.7.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53eabd3aabc774d01da7836c58675c3e5cafd4285540e846debddfd056345d2c"}, - {file = "uv-0.7.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6bbf096970de17be0c2a1e28f24ebddaad9ad4d0f8d8f75364149cdde75d7462"}, - {file = "uv-0.7.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c94cb14377c0efa65eb0267cfebfb5212729dc73fd61e4897e38839e3e72d763"}, - {file = "uv-0.7.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7025c9ba6f6f3d842a2b2915a579ff87eda901736105ee0379653bb4ff6b50d2"}, - {file = "uv-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b503d808310a978453bb91a448ffaf61542b192127c30be136443debac9cdaa"}, - {file = "uv-0.7.1-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:57690b6e3b946dcf8b7b5836806d632f1a0d7667eae7af1302da812dbb7be7e5"}, - {file = "uv-0.7.1-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:bf54fab715d6eb2332ff3276f80fddc6ee9e7faf29669d4bfb1918dd53ffc408"}, - {file = "uv-0.7.1-py3-none-musllinux_1_1_i686.whl", hash = "sha256:877145523c348344c6fa2651559e9555dc4210730ad246afb4dd3414424afb3d"}, - {file = "uv-0.7.1-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:ef8765771785a56b2e5485f3c6f9ec04cbd2c077be2fe1f2786ded5710e33c0d"}, - {file = "uv-0.7.1-py3-none-win32.whl", hash = "sha256:2220b942b2eb8a0c5cc91af5d57c2eef7a25053037f9f311e85a2d5dd9154f88"}, - {file = "uv-0.7.1-py3-none-win_amd64.whl", hash = "sha256:425064544f1e20b014447cf523e04e891bf6962e60dd25f495724b271f8911e0"}, - {file = "uv-0.7.1-py3-none-win_arm64.whl", hash = "sha256:7239a0ffd4695300a3b6d2004ab664e80be7ef2c46b677b0f47d6409affe2212"}, - {file = "uv-0.7.1.tar.gz", hash = "sha256:40a15f1fc73df852d7655530e5768e29dc7227ab25d9baeb711a8dde9e7f8234"}, + {file = "uv-0.8.9-py3-none-linux_armv6l.whl", hash = "sha256:4633c693c79c57a77c52608cbca8a6bb17801bfa223326fbc5c5142654c23cc3"}, + {file = "uv-0.8.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1cdc11cbc81824e51ebb1bac35745a79048557e869ef9da458e99f1c3a96c7f9"}, + {file = "uv-0.8.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7b20ee83e3bf294e0b1347d0b27c56ea1a4fa7eeff4361fbf1f39587d4273059"}, + {file = "uv-0.8.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:3418315e624f60a1c4ed37987b35d5ff0d03961d380e7e7946a3378499d5d779"}, + {file = "uv-0.8.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7efe01b3ed9816e07e6cd4e088472a558a1d2946177f31002b4c42cd55cb4604"}, + {file = "uv-0.8.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e571132495d7ab24d2f0270c559d6facd4224745d9db7dff8c20ec0c71ae105a"}, + {file = "uv-0.8.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:67507c66837d8465daaad9f2ccd7da7af981d8c94eb8e32798f62a98c28de82d"}, + {file = "uv-0.8.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3162f495805a26fba5aacbee49c8650e1e74313c7a2e6df6aec5de9d1299087"}, + {file = "uv-0.8.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60eb70afeb1c66180e12a15afd706bcc0968dbefccf7ef6e5d27a1aaa765419b"}, + {file = "uv-0.8.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011d2b2d4781555f7f7d29d2f0d6b2638fc60eeff479406ed570052664589e6a"}, + {file = "uv-0.8.9-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:97621843e087a68c0b4969676367d757e1de43c00a9f554eb7da35641bdff8a2"}, + {file = "uv-0.8.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b1be6a7b49d23b75d598691cc5c065a9e3cdf5e6e75d7b7f42f24d758ceef3c4"}, + {file = "uv-0.8.9-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:91598361309c3601382c552dc22256f70b2491ad03357b66caa4be6fdf1111dd"}, + {file = "uv-0.8.9-py3-none-musllinux_1_1_i686.whl", hash = "sha256:dc81df9dd7571756e34255592caab92821652face35c3f52ad05efaa4bcc39d3"}, + {file = "uv-0.8.9-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:9ef728e0a5caa2bb129c009a68b30819552e7addf934916a466116e302748bed"}, + {file = "uv-0.8.9-py3-none-win32.whl", hash = "sha256:a347c2f2630a45a3b7ceae28a78a528137edfec4847bb29da1561bd8d1f7d254"}, + {file = "uv-0.8.9-py3-none-win_amd64.whl", hash = "sha256:dc12048cdb53210d0c7218bb403ad30118b1fe8eeff3fbcc184c13c26fcc47d4"}, + {file = "uv-0.8.9-py3-none-win_arm64.whl", hash = "sha256:53332de28e9ee00effb695a15cdc70b2455d6b5f6b596d556076b5dd1fd3aa26"}, + {file = "uv-0.8.9.tar.gz", hash = "sha256:54d76faf5338d1e5643a32b048c600de0cdaa7084e5909106103df04f3306615"}, ] [[package]] name = "virtualenv" -version = "20.33.1" +version = "20.34.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.33.1-py3-none-any.whl", hash = "sha256:07c19bc66c11acab6a5958b815cbcee30891cd1c2ccf53785a28651a0d8d8a67"}, - {file = "virtualenv-20.33.1.tar.gz", hash = "sha256:1b44478d9e261b3fb8baa5e74a0ca3bc0e05f21aa36167bf9cbf850e542765b8"}, + {file = "virtualenv-20.34.0-py3-none-any.whl", hash = "sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026"}, + {file = "virtualenv-20.34.0.tar.gz", hash = "sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a"}, ] [package.dependencies] @@ -3588,14 +3582,14 @@ voluptuous = "*" [[package]] name = "voluptuous-serialize" -version = "2.6.0" +version = "2.7.0" description = "Convert voluptuous schemas to dictionaries" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "voluptuous-serialize-2.6.0.tar.gz", hash = "sha256:79acdc58239582a393144402d827fa8efd6df0f5350cdc606d9242f6f9bca7c4"}, - {file = "voluptuous_serialize-2.6.0-py3-none-any.whl", hash = "sha256:85a5c8d4d829cb49186c1b5396a8a517413cc5938e1bb0e374350190cd139616"}, + {file = "voluptuous_serialize-2.7.0-py3-none-any.whl", hash = "sha256:ee3ebecace6136f38d0bf8c20ee97155db2486c6b2d0795563fafd04a519e76f"}, + {file = "voluptuous_serialize-2.7.0.tar.gz", hash = "sha256:d0da959f2fd93c8f1eb779c5d116231940493b51020c2c1026bab76eb56cd09e"}, ] [package.dependencies] @@ -4093,4 +4087,4 @@ ifaddr = ">=0.1.7" [metadata] lock-version = "2.1" python-versions = ">=3.13.2,<3.14" -content-hash = "792fb2f76bfc132e921609b4f3b404b48ad3d69fb04826ae8434446ee18aeb97" +content-hash = "320c249da4e05da8d4004506c42422ab8a94e381d5bd0713d0b192987373b4a5" diff --git a/pyproject.toml b/pyproject.toml index e7ea87f1b..8ef18bb41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ repository = "https://github.com/andrew-codechimp/HA-Battery-Notes" version = "0.0.0" [tool.poetry.dependencies] -homeassistant = "2025.8.0" +homeassistant = "2025.9.0" python = ">=3.13.2,<3.14" [tool.poetry.group.dev.dependencies] diff --git a/requirements.txt b/requirements.txt index c87d47cf3..fb13e613b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ colorlog>=6.8.2,<7.0 -homeassistant==2025.8.0 +homeassistant==2025.9.0 ruff>=0.5.0,<0.12.7 From b6a3e1ab89c1f01505cb37f65de081119fa405a7 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 7 Sep 2025 11:11:41 +0100 Subject: [PATCH 173/235] Update docs for v3 --- README.md | 22 +++++----------------- docs/configuration.md | 37 ++++++++++++------------------------- docs/entities.md | 4 ++-- docs/events.md | 8 ++++---- docs/faq.md | 24 ++++-------------------- 5 files changed, 27 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 7ff0dc5b3..4c5441968 100644 --- a/README.md +++ b/README.md @@ -29,16 +29,6 @@ _If you want to show your support please_ ## Installation -**Important** - -Once you have installed battery notes using either HACS or manually as per the instructions below you must add the following entry to your `configuration.yaml`, then restart Home Assistant. This will enable discovery of your devices. - -``` -battery_notes: -``` - -If you need to add a device that is not automatically discovered from the library go to Settings -> Integrations click "+" and search for "Battery Notes" - ### HACS Installation [![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=andrew-codechimp&repository=HA-Battery-Notes&category=Integration) @@ -46,6 +36,10 @@ If you need to add a device that is not automatically discovered from the librar Or Search for `Battery Notes` in HACS and install it under the "Integrations" category. +Restart Home Assistant + +In the HA UI go to Settings -> Integrations click "+ Add integration" and search for "Battery Notes" + ### Manual Installation
@@ -53,14 +47,8 @@ Search for `Battery Notes` in HACS and install it under the "Integrations" categ - You should take the battery_notes.zip file from the latest [published release](https://github.com/andrew-codechimp/ha-battery-notes/releases). - To install, place the contents of `custom_components` into the `/custom_components` folder of your Home Assistant installation. -- Add the following entry to your `configuration.yaml` - -``` -battery_notes: -``` - - Restart Home Assistant -- In the HA UI go to Settings -> Integrations click "+" and search for "Battery Notes" +- In the HA UI go to Settings -> Integrations click "+ Add integration" and search for "Battery Notes"
## Docs diff --git a/docs/configuration.md b/docs/configuration.md index 91ba5857a..018b1b2dd 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,30 +1,17 @@ # Configuration -You can add these options to change the default behaviour of Battery Notes by adding them to your Home Assistant configuration.yaml under the battery_notes: property, like so: - -``` -battery_notes: - enable_autodiscovery: true - show_all_devices: false - enable_replaced: true - default_battery_low_threshold: 10 - battery_increase_threshold: 25 - hide_battery: false - round_battery: false -``` - -A restart of Home Assistant is required for the changed to take effect. - -Name | Type | Requirement | Default | Description | --- | -- | -- | -- | -- | -enable_autodiscovery | Boolean | Optional | True | If set to true will automatically match devices against the library and create a setup flow within the integrations page. | -show_all_devices | Boolean | Optional | False | If set to true will show all devices in the manual add dropdown, rather than just those with batteries. | -enable_replaced | Boolean | Optional | True | If set to false new devices added to battery notes will have the battery replaced sensor and button disabled. Any devices you have previously added to Battery Notes you will have to disable these sensors manually, which also means you can enable specific sensors of important ones you want to track. | -default_battery_low_threshold | Int | Optional | 10 | The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired, can be overriden per device in device configuration. | -battery_increase_threshold | Int | Optional | 25 | The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level. | -hide_battery | Boolean | Optional | False | Hide the standard battery when adding Battery+. This will not effect existing dashboards, automations etc.| -round_battery | Boolean | Optional | False | Round battery+ to whole percentages.| -user_library | String | Optional | | If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in the same folder (config/.storage/battery_notes). Only really used for dev purposes. | +Global configuration settings can be changed by selecting the configuration cog on the main Battery Notes service. + +| Name | Description | +| ---------------- | ---------------------------------------------------------------------------------------- | +| Show all devices | Will show all devices in the manual add dropdown, rather than just those with batteries. | +| Hide battery | Hide the standard battery when adding Battery+. This will not effect existing dashboards, automations etc.| +| Round battery | Round battery+ to whole percentages.| +| Default battery low threshold | The default threshold where a devices battery_low entity is set to true and the battery_notes_battery_threshold event is fired, can be overriden per device in device configuration. | +|Battery increase threshold | The threshold where the battery_notes_battery_increased event is fired, use this event for battery replaced automations. The threshold is the difference in increase between previous and current battery level. | +| Auto discovery | Will automatically match devices against the library and create a setup flow within the integrations page, this occurs at instegration startup and repeats every 24 hours. | +| Enable battery replaced | New battery notes will have a battery replaced sensor and butoon. If disabled new devices added to battery notes will have the battery replaced sensor and button disabled. Any battery notes you have previously added you will have to disable/re-enable these sensors manually, which also means you can enable specific sensors of important ones you want to track. | +| User library | If specified then a user library file will be searched prior to the main library, the user library must be in the same format as the library and placed in the same folder (config/.storage/battery_notes). Only really used for dev purposes. | # Debug Logging diff --git a/docs/entities.md b/docs/entities.md index e3a2d84df..ed0c93a62 100644 --- a/docs/entities.md +++ b/docs/entities.md @@ -22,7 +22,7 @@ See how to use this entity in the [community contributions](./community.md) | `battery_last_reported` | `datetime` | The datetime when the battery level was last reported | | `battery_last_reported_level` | `float` | The level when the battery was last reported | | `device_id` | `string` | The device_id of the device | -| `device_name` | `string` | The name of the device | +| `device_name` | `string` | The name of the device, if you have renamed the battery note it will use this name | | `source_entity_id` | `string` | The entity_id the battery note is associated with | ### Adding a battery percentage @@ -86,5 +86,5 @@ If you have specified a manual template then this will be created, reflecting th | `battery_type_and_quantity` | `string` | The type of batteries with the quantity if more than 1 | | `battery_last_replaced` | `string` | The date and time the battery was last replaced | | `device_id` | `string` | The device_id of the device | -| `device_name` | `string` | The name of the device | +| `device_name` | `string` | The name of the device, if you have renamed the battery note it will use this name | | `source_entity_id` | `string` | The entity_id the battery note is associated with | diff --git a/docs/events.md b/docs/events.md index 62ee80205..368ce7f0d 100644 --- a/docs/events.md +++ b/docs/events.md @@ -17,7 +17,7 @@ You can use this to send notifications in your preferred method. An example aut |-----------|------|-------------| | `device_id` | `string` | The device id of the device. | | `source_entity_id` | `string` | The entity id of the sensor associated with the battery note. | -| `device_name` | `string` | The device name (or associated sensor name if no device). | +| `device_name` | `string` | The device name (or associated sensor name if no device), if you have renamed the battery note it will use this name. | | `battery_low` | `bool` | Returns true if the battery has gone below the threshold, false when the battery has returned above the threshold. **Your automations will almost certainly want to examine this value and set/clear notifications or other indicators.** | | `battery_low_threshold` | `string` | Battery low threshold (or global if 0). | | `battery_type_and_quantity` | `string` | Battery type & quantity. | @@ -93,7 +93,7 @@ An example automation below shows how to update the battery_replaced. |-----------|------|-------------| | `device_id` | `string` | The device id of the device. | | `source_entity_id` | `string` | The entity id of the sensor associated with the battery note. | -| `device_name` | `string` | The device name (or associated sensor name if no device). | +| `device_name` | `string` | The device name (or associated sensor name if no device), if you have renamed the battery note it will use this name. | | `battery_low` | `bool` | Returns true if the battery has gone below the threshold, false when the battery has returned above the threshold. | | `battery_low_threshold` | `string` | Battery low threshold (or global if 0). | | `battery_type_and_quantity` | `string` | Battery type & quantity. | @@ -134,7 +134,7 @@ The action can raise multiple events quickly so when using with an automation it |-----------|------|-------------| | `device_id` | `string` | The device id of the device. | | `source_entity_id` | `string` | The entity id of the sensor associated with the battery note. | -| `device_name` | `string` | The device name (or associated sensor name if no device). | +| `device_name` | `string` | The device name (or associated sensor name if no device), if you have renamed the battery note it will use this name. | | `battery_type_and_quantity` | `string` | Battery type & quantity. | | `battery_type` | `string` | Battery type. | | `battery_quantity` | `int` | Battery quantity. | @@ -183,7 +183,7 @@ This can be useful for adding batteries to a shopping list or inventory system. |-----------|------|-------------| | `device_id` | `string` | The device id of the device. | | `source_entity_id` | `string` | The entity id of the sensor associated with the battery note. | -| `device_name` | `string` | The device name (or associated sensor name if no device). | +| `device_name` | `string` | The device name (or associated sensor name if no device), if you have renamed the battery note it will use this name. | | `battery_type_and_quantity` | `string` | Battery type & quantity. | | `battery_type` | `string` | Battery type. | | `battery_quantity` | `int` | Battery quantity. | diff --git a/docs/faq.md b/docs/faq.md index 9d18039ee..d5e2ab26c 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -23,30 +23,15 @@ Go into Settings -> Integrations -> Battery Notes and click Configure on the dev ## Why am I only able to see some of my devices when adding manually? -By default Battery Notes filters the device list to only devices with a battery, if you want to add a battery note to a random device then you can disable this filtering by adding the following configuration to your `configuration.yaml` and restart Home Assistant to see all devices. - -``` -battery_notes: - show_all_devices: True -``` +By default Battery Notes filters the device list to only devices with a battery, if you want to add a battery note to a random device then you can disable this filtering by turning on the Show all devices configuration setting. ## I only want to add notes to a few devices, can I disable auto discovery? -If you want to disable this functionality you can add the following to your `configuration.yaml`, after a restart of Home Assistant you will not see discovered battery notes. - -``` -battery_notes: - enable_autodiscovery: False -``` +If you want to disable this functionality you can turn off auto discovery in the configuration settings ## I don't want to track battery replacement, can I disable this? -Yes, you can add the following to your `configuration.yaml`, after a restart of Home Assistant _new_ devices added to battery notes will have the battery replaced sensor and button disabled. Any devices you have previously added to Battery Notes you will have to disable/enable these sensors manually, which also means you can just enable specific sensors of important ones you want to track. - -``` -battery_notes: - enable_replaced: False -``` +Yes, you can turn off enable replaced within configuration settings. _new_ devices added to battery notes will have the battery replaced sensor and button disabled. Any devices you have previously added to Battery Notes you will have to disable/enable these sensors manually, which also means you can just enable specific sensors of important ones you want to track. ## My device doesn't show a Battery+ sensor @@ -94,10 +79,9 @@ HACS will now show updates available for pre-releases if there are any ## How do I uninstall Battery Notes Within Home Assistant go to Settings -> Integrations -> Battery Notes -For each Battery Note click on the three dots and select Delete +Click on the three dots for the top Battery Notes service and select Delete Go to HACS from your sidebar Click on the three dots next to Battery Notes and select Remove -Edit your configuration.yaml file and remove the battery_notes section and any options indented directly under it Restart Home Assistant ## How can I show my support? From 2298b589f25e30045ee384017e820d36db9278a3 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 7 Sep 2025 14:54:57 +0100 Subject: [PATCH 174/235] Update bug report checklist for clarity on Home Assistant restart --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 2bb64c657..8975dcb49 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -10,7 +10,7 @@ body: attributes: label: Checklist options: - - label: I have added `battery_notes:` to my configuration.yaml and restarted. + - label: I have restarted Home Assistant after the HACS or manual install. required: true - label: I have read the [FAQ's](https://andrew-codechimp.github.io/HA-Battery-Notes/faq). required: true From a2638389ecccdf9adcc3c6b95f88ddbb669e663a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 7 Sep 2025 14:03:09 +0000 Subject: [PATCH 175/235] Fix default value retrieval for CONF_BATTERY_LOW_THRESHOLD in config flow --- custom_components/battery_notes/config_flow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 712283d58..4e8a19c85 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -871,7 +871,7 @@ async def async_step_reconfigure( min=1, max=100, mode=selector.NumberSelectorMode.BOX ), ), - vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data[CONF_BATTERY_LOW_THRESHOLD]): selector.NumberSelector( + vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data.get(CONF_BATTERY_LOW_THRESHOLD, 0)): selector.NumberSelector( selector.NumberSelectorConfig( min=0, max=99, mode=selector.NumberSelectorMode.BOX ), @@ -894,7 +894,7 @@ async def async_step_reconfigure( min=1, max=100, mode=selector.NumberSelectorMode.BOX ), ), - vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data[CONF_BATTERY_LOW_THRESHOLD]): selector.NumberSelector( + vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data.get(CONF_BATTERY_LOW_THRESHOLD, 0)): selector.NumberSelector( selector.NumberSelectorConfig( min=0, max=99, mode=selector.NumberSelectorMode.BOX ), From 30fbf9059fc8c60f1a9026d58ef423d52d3270a6 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 7 Sep 2025 14:12:52 +0000 Subject: [PATCH 176/235] Update device info screenshot --- docs/assets/screenshot-device-info.png | Bin 20813 -> 21376 bytes docs/library.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/assets/screenshot-device-info.png b/docs/assets/screenshot-device-info.png index 9c80894474ac2f3620708c1f03015e1fb1ed0b23..dc50e6cb20682ef7bcac2395f3c9182a62ec9646 100644 GIT binary patch literal 21376 zcmeFYWmsL!(l&?%HttUF0KwheB{&2~u#J=8?(Q1G#yuo~1cC>55AN;~+}*zgJm)=U z&b;$)uK6`^!CrfAzgNj6i1O)|!Dkm$c1_cHE3Ak0fk zJHY3G<&6HiS`pww1`?64|{izC<)R>=?uee2t#xTLuWvqNhQ-ePZE z8kB0~Bnjl*!|p?|lmgvnWGK-uCO(s z(0Xkjg2eOMJ{8Get2{h%S^O3bs*FF2r58#xm-x8QOALN2r_I7YUXm_RbQhsi*=FB_ zqTP|A(x2N-sa7p3<2+EQbCGitp6lv1N~|#ATk$8@b_Yu|-|L5zmff$Aebss9@rTv06ghV^x?je)Ru!)1DJLrNV!kaNfg33$!)i-lcyi3e>q-gud<}SgERg1Q!Z?z>V9`IVwmGc*4RwTtu>gT&8!|1jR} zQoy_|MG##LXAfqsk2e6fNAhUD09!g0c81mI;O4}G&Bd>6hizB3fR`RWvY zCZOf!#M2l_Mx=w zK%}wAhp#WKyb$$cw3eMOEpLhLF%CMLFfHID0)$%Po2jCxOfbGk4*&tP}f>r@ZvKH_cI{VbURC3sz1NE;l0aXg(rbB4;8k zF8z_$P73^?!g2bdEZ@ko4Zgcts&W3}tV#9ipH9V14dt@6Jhx!0khYZiu>OH*c;<(* z*iH?%+^oES%KQ8VQO|<&*Lz(kQQ(0kcDSgkDC;PWD72SfVt%73(<~qc|&F9wcy@|5ySYvZc?oGZ);YrB~Aw*q8!A5;ASm-h}4n8;w*}2*ZKaDs$ z-<%)1`8qg)J~lXEkYiBny9mWo!V$)u{GnucDN1b8E@N50?L}K;=mFV%8pQ_-a{^=D zHoF3FBsey%RJ9~-%pzm>buP2<_tGr;#G?P z8y}J^wZN{^q`zIu@n>yIY>CAPmf6JFzc{orAvhz%NHj`Bw@Ju+H?B6$F>YAxjl-jg zmnkA}w^`$%)ygBuvsQAIv5ZA}smc4(e(a;UfVsb8@X6V5#jsfJMwAV~T~Eh?)LPl_ zdL=`fbK#Eoq}gP#&AttL)w?PsSL6$gi?jWzDgIr$bF6cB^nlQ&E|OT9*w{>)O!v$i zp@(CK!=Ce*tuwEvGlJn{YhzN+H20H+Dz~be5-&Ax?wg96)azq!25+*flpDmm${V58 zDTgxNI$oB$j9b(D(Az~vp_=k)T9^{QCBGHF3DLdg%jV-|1Tix)LNP9}`Ie#( z->n&Ukz1JiUGil(jkJuEmZV5DAub2UUtLBj7q#7iDOdY@``(rP&e?W`l{D;4#Mg-9 zhzHoPSXwldvBZ2f6V(cG@Nz3(Lrl~h#E;L{GLQUMC!-Ez?G<0k*YLG?v{oSE(-6Js zOL23;^2YKV@z)UlV6;6j#&Rp`^Qwt9I;m3l*ZXGNLfm?cYeX$%0jY&A317^&7Pc5h zv&`Mh3wt*EPWu`Acd;Bh)>pK2D0I@w7R+VL4!ZaI<@%=M6$TXhg&2nuO%#-rxibZ= z9n!}1-%(pAmF4)>NFHj5&8Sa8(oZ+!~7xxJZnN_3x6+Pq+w*FXT@OUJ;CxBa;Ty_pvu zbJUl6TB}a5H+Yy?-?6&3tY!uH{(L<`_ZfHo-R5t*QA)2kH`Se$;mAp*`?rjYjoK?3 zYVVFs!wvs*WXas=o;x0loPPV&JC|s!tE9`UxP zEu;6t5RsJPMiE3$%LQTACf_-KzAUsR&xB>FVCtr;am<_NB6QDIxLH`mbLe>KS|UoK z!&!Fzw08fx@A^FCYe;2VPG}l&0}=X5d%?2YKNUY#^7n^LyYjp6NOpwu?dmszP9-P* zM8(IZ(Q+*caqW+tjSlC%9}LRi^X1;${o$DI*fr>xWm~)CzI-Tk-f^v9leGO#_dVL( z_VrHA+p3A$-u)!vA~#)2E8^7g)RvFSCzbXBRIj>VA`X6C9STtM2C3#lDC&5R4PK8Yx|R zy=S?_5pO;|n32Wf4DYOeWqeEalI1Iluq*D}kF$;IByJY;`}GSgg^TL_7_Bm`hT^39 zVc+uAU%j(`GxIYM4jdM}eGG2J9wf$P&bu75utbDz1kaGS6sEOii=!7?8|QcW_x2Kw zO>Y|wpi$^zxwoL|7oee-5TW1&dDOZJ2131GsAgE+U|cF|JBREt*g%c7`d)7`U%EOX z`!&o$l>}U$;y`_|fNFP#ays2?;kQfN5pbnP#>_Qps}D}fh%a>7YdpP>c!JF6qGzP@&8<_ zLDT(H1_lZ$)DjBrpEB=&&&Quf*9EBk&nN8X5GVxT8y4^vlnwK*($Jr>VgGdv)doC+ z5>uCulLJ20jU7x)Z5%CZon~MEoB?hi+R5rTLP6oZdi;ZyQ=>kFf`XN@)X;X)R(!*6 zY-`O7HnBA_Wp=Z+du#_v(2XCsv^I4Dle<}4**NmM2~j?k;0LZBZ?jO6KNWHMC`75P zs6sAb>tIUG&CJToN-2y)PEIc9U}DCvCMo?-b>N#2rG=A|9X|_;tE(%sD+jZ!gE+B>%N%`2( z|NK0^r>UFezk9NA{AXCe09hWNu&^<+vixt=oGi`$AF4e*d9L;}uIKIq9~Cyd((5^cQkFD$C`^0sj%Z$N|2G0Wshq;gI zMS2Q{?EvQ=DI`h?a=0Kr3=Ei8ltUHm$Mnq4-^80SK0yzY1pp7kML}c8(1f2nTE5Ez z*C1#La@a3T!2idR`S>vG%H~JR=e2#x_WAhc$-iF*soYN?#PSNg3DsEX4&Lcn8?!on^Ng(YB zl4YdZsO_ezberCF)H~aWSB^^7C`&c@^;&4w%(y$ zBh@V)4VPYoC+}R4CAZ*Fa@oQl#!u+o2_~Z-E}|IN@xK;%v1pBsU-c)mQJwBibIiHS zS}*^h%|f}mx#0QcdD74GUK58YVtQ5~D}%>*(fdM=gK@11c+KU;oBg!Gp=5>EZ^_9d zR`%N3Mt-8gU3is2zPry4iaZGJR*WhwZxxZ>itYl=_YNNoFr3$mtV3R5g^|ve0+yYOL`Usc1yG z+}+=7ln><{Xpu&Uqbm z;Mee~r?5nCgsJTZgQQpyX7-rU1)9_ z%~(Vr^ZHcq^Jm$4miM_1gA(E4v~|_I!!Y@~)YT3N#l6u`u|W7c<*Vs(^RzdKm`%Fy znSUZVcn4EiShDhoAJ?L&5Jvt53S2Zu>IJUPS%E?DYK#E$(uY;x-|i9(%Ze&-L` zuJg`qdsT}zmX06C9*8rQ_GW&Uzn8uoqRsNc8W6geI~>ir=iL20slV)xKw9D?y({u? zHE0d**hy$UwY#49-UiY4dNiw*y_XR?hWEG|BccA!-QP6Z5UN#J*+8wqagl=Sd4)l!Niy^$kahU=m#0O5}tXr-wcpjj7 zU!Nk1+#kiZ>AB9EG7FnA43h^7>{qv4mkkQv1nm^n4J_cgGr!k&n}6K3aNB{RLQzVM z5wT_7A&0#N_v|7bG)(k0bN2`&pKgwOS$-+;vk!3mSf}aD!n|Gk6Yp5uaQ<$8C6Z+z z!{>U7dp3Ix@4Z!A-C--TBZv7wU&Hlw0rv_SpTpPaYIhnDqJ+8At2Qj
  • MrfIR76W`6>2qWcmtFOzf?2K$ z?pHpwyXxQHl-4d`q9%LOwZEaMU3Z8Txvw72>7OVl&aB)1S>P~y_%{Td%;rqr>qx5C zyz}?n`Rv9Q%w8!f6U$-4wc3kKa5A}ZmCd}v-St^{{bpwGUiE4W-;C?k!+BMcj{c8> z7WyrPM@9BY%x`!TCXPX#hf;>j+iCw-)j|*O=TXD^d4L$5MN8gTzsvogw2QQcH?7-V zDo5n@u&omfA5|X9VV%Gnwq~ceX<_7Y#-W$Vah3K>w}{By>1d4v8Xxt8R~stNniB7F z&@Bh^w}A|SjTIuPg=#~S^v;-o-3vJW989-CpIuLQ(bf`Hbg**9@=&(_P!Zbjy)mO4XYywGl#{gfjajZD=Qq9J>Vi zaZmat2he;5;N`N`m!sbm(+-ci$U@uDMFg#?mqV5>S7XtAuX+u{PyY5ZHBp>f={ojv zQ4rCr@>q^ge+)G+my#k&)N`4(o6s>&nf;+z@OC+Zp$K#_=cqhZ>Ns!Z63xs_J10{; zldhfL)gMIsntr1Mn2nI(T$#}P(_glb$ZXG}lA})IG-O61g`HKR(ucj-s;XOY8_GG) z>ZbjshkFcjB>(ef#NBM(awL1j_WihzfIdb8r07F%wi0>1!!c)F{mqV0e7`n#@Q|F0 zN1v0@-@xak+mb&85&cJO*C}WO5{z1>EhFbG1ont0Yl0lm3`6{>!v6M{PB`qN1VQxG zB@37G+@?NKmlRcphh&~ohIlC2%T{1d6MuQnP*~E6bgsTwO<+A9_wk1|k7jCjVo#TH zkZPyQOJ@in#&){z{nfcT7=>yLo_c`!4cNfvYMo-h#438VPvo{`MCI?{S=mwNw#WNI zTS=`fLSA-V8WbjJ)Z^L;Y;%Jvc1yDAP^HK_J;!LSJ`2XGIfopnNW2gs5oh>Vxnb4@ zL9qDd%8p!VS48wO`^sc>tmn0z6b z=t2F767ztaLpOA(4|Iprg>Jh0`UEiJb03SFY%H0}4d#QnUe%VRFChqf!D~MJjQEY4 zc{gbVX;=zCcF4>0_^BBg@_Lf0$Q6Z*tu^z?S(7vUiVFwJa@6;S%ik39zs;SNhf6Ir z7KIKX8V~$vK2JEJIe@&`qH1AH9&6R#VaE62&Ki?Aq|uE;@7=k&+K9a7yMe_7yL8Mo zn-~$o7%JcQ#(d{f#{In6Lu~M#`!(i81`qc&@k;!EAZ+XP^OrmH@8b!%t&+cWq(mlw zGlG62nnX6y^zPN}6x9IcVhB>j;G}g~l&;5IGzR|F6&-Og+*^OK;5iXfJnY7Yx3m1v zj;*|AdV90@V6(%#Hmr3#AEruo&(1hmpjABgi9(_bGYJX9-*c6Ox~LcMh=)ubXG&IGx@G-%AG??U31rU|m+fXJk$dkOzxfgQ>s?Z`b*z4bq#x|Vn= zY3pLqyI5rmTUK{gddEW19WLiJB~t^95Jq&C4Z*wVVoUyu;OiyRyKU!cJo)m|nv@q; zaj%|WASWEm88%P;Bb;?vyW98f%PkmdMS2KDD&1zLB=)Eirt`kn4y zw`@pc13`hu%TlyItsrtZdUOCu_jsCr)_$}kAx`v*W-m0YCIU= zJLClbtxb=JsDqwV`!N8>f7H9uga<#ObyI&o6j_~mcti@gM-(myU~T$?3^^m9&md79 za&lNTykar&C#(Pecj^ECo?ulf;i;2)6JCg7i9dNla7a`tpP^GY%$2(7T{7itWmB=; zxh+S&Qs{8=vRvN+#uxBpMBGf+zSy@Fy+azT;w0>W_vJC71Ey(}e2AL9{B!8FhFHtZ zZwe_z_wN^|)19p=2|Z~G_#asMl@E{;G*h2up9GW668?DRV{z~n02Dd{hdHE808qQU zo@9Ww==;!c7VGqoO+aCWli7(&8S6wlq8ArKD#V}ewi3P^h%Q`WC4H?g!gOFcrXT`2 z+Sv8hPu#A|2(40fS9T;7%#$1kKo3I{2_HKOnXsTAG90P0(3yrC0O|J@*eGoKlG&E) z4jPdGV1^hgbe_DfZo579!zJsS&3e#uIYRJRQPhwFlGp+OdiDOyM@1JcGiAXe$w#Gj z`FGZqsljsedyB|^$Oj_af;{_g%;!Ryngld zHot2lPKFfGw(;uw_z~yjRl|7XdLgql?vjM*#@?Bm3*Vo?^}j(JgMy;~b{fuJ@H**V zzTPROWvB<>DR?5uVCGIufyq>>kq$vIOIS$oVz=By#PM(6A>ejQdCzoJ2qgtG9Crs1 z=w1W*CmRJLId6FzBLwrf7;qj~?UtJD*5YJBG_~}&`eJ%whfgU&Nw6Hob5Fr-At^?B z#Xsp!r@b%yjHvf!Ee!R2@6Jj(@ZJXjMuf%-u+-d+)An62+mck5**_o5*SWgg9(A<= zPUHu70F&EX0*JcR_u*#o@MEw-MmL-AfdWkXac(!{I2^XsXVr%D)p)|$!5Va?6V0Rh6=`#4JgO~jyFMvL*X(~F2K2Du{DEMXOJjybsDqLVV5vU6Q zMe$2uJ@qf0ZVtDhECSPDG0t4ONx8#w>pgMQ42zz;oZD>cd-HyWrCe~|9yMSZ5Qy3F z@<3a+=$2JC*6FK9#jFhn!V!W6pY|~>b&1^D18#_b)fiyS2SevwW|>e3Seqe~xegHC z2;#t2Su!Jyfz3w6G;Z)g!$svZ6xEFeTRg%qAjoiTx!BksbWqmI3~miVLI`{HD>dXf_~(!sUe&{D7fW>(x%}qUaNFf~=nHs#LV-a4P6q#~XiV#5wV( zIl?X1&7l^EZ6qF3>s0A#Uq|qW@!NpbAeE)4AqpJ2K{`XNplbiy%s3$=B3HDa&ossF zt8AdF2;2`3k9FT`)&&tvw-Fmb&!R%@Q)$hu83&P%uzLLZLMh{3ZWpTyx!Nu$E{yW+ z=X!aMQ+Pl?Ip?vF?p;~)xBDB@HI%)xyPCTmvvRIg?Gl>JDH;AGp?Nx3`XGeZ2E@{E ziX~<3V#4#d_eDXB;&2h%9 zz-y}x6tr_e@N?@vI_TCBa9XG=FiG=0;9@)5OAW*Ce=jJiAHiXOe~cR_U(&_grra6! zk>hYMbAlu;PDhnPE$!j$dYP)$qTy}0lfJ3vDbdXS9QMoZ(^-&G%U z7++e%2YaBP!^PSbpn`1Zc-~g$(uJxXr4X9VXGjTqe>(u2K=%AEKCp+Fs*)}%s4}a(D?XzT~%8HQLkTq1tD?5 z9C#Cmb{);eqy5|*tNsGW_(^qH7NMSQ<#YqB{LIwSHy?{?%q-?>ou^FV6%YW!!lnUy#7R$n_J5K3@*U zY?m5mp75WGmLj~4D(D;ilY7svdXKB6JG?!rH6v*@6HM#;61~Wf{lget+ggH_KH{TG zR&!*R@!M*8#LW3HCrdcjp0Ci}`zfM`2Mu#JBdcw|M_5z0qHyqWMN2(Jd@FdQ%&XkA zZ18tN@eixi%mt2FJABR5ee185eQGhn*PC`{<63EP-`=DiIDb%3?%mXXwBkbqAe_Bc zaRSH}?2A4ma%Gt<9gnl|Q6bb-)y+&!mbByC`jb=kBJGS=gVC}>QSQN$TFV=VTvh|) z)||v^<$ZPeUN?^(^wk#Ocn$p?ci(zO%Rc$tyrEJ-I9uDn_2YuP_hSFNGzCmFKdesB zoyO=R;sd&F20=JsEte`gn8ljSIpsdvJj1(aKQnUEI}hsgC+qL^X#H1wE-M7~N0moE z)D;(aWn9I%69vUp=BuNblqH2TuKR_WJbIHy(%JeP7&xZhc#fkUTMZJrbp0niXAylW z-iLIP!g9<{>x1pFQ!qAp8k}lk5%08Ee+ciza{NF;|644?DGM2)03xi^c6T?OqOUEz zJo|*PePNl=ZoAX6;pU5f6kq1;3JqGOCMlTGhq$pci%bA*^gvH_Cn5u)4BJ zJ)sc#CVqzW2a>4Z-mg`edgNt^_DKHQzxUZhlpva<}S#@BkyCtHvVqs5;6m)c$aX2Q|>zQUrbdhO; z^0R4#eZhsE>O$q+fV-+sV_E6k!`F^$8@u$-i&27|XKxPXgQAm>B}E zCA!e*C#mT>iUo-vGzv3pf#T_D)SP`@zi_|cwPIY?cnLZdmk8|7LE2gblqjeI?Gz9W zF^uV&=vEqZ)9!?FN%F-MMIzJuHfARjWa~18O!h}7JsAV{&MeJ_2na+UM-X>}>-H51 zN0)KMg4Oe5bq^(&7p;|&Fp(604gF_8OO9y6SQ35DbzGy5(fG0GNX zzNKDV;axM=7q+;o_;tgG3F7UBF2I}mQn)heCs&zC(EH^m0mpy zK+GaKN_%u;R9R#`ij)8oC7zp2@)_E`2H{wXsyJL;`kv;J1ye|bXcMOw$|T!M|00M6 z0*7O*br;*?3?#$}tJ!WoFXTVi)jPD3AC&`uq@=#A_HXJ(s}NBX2I)xxA_%*+SUOp2 zH_<(vLB1s?h)xx z`R^2vsp_>LcG?aQ%HwGhw_?ex>mr2aU`L_y_P43sqFMd3tU~}J-X#%r%I6hvxCi$w zoy43HgI%=ns5wus&gC(lS8`m4$W~w+(#-hj6D?$!v`r?=Yi)gr5rr@WZkksMZZ*dL zMPB1k3bg3O{yft;p7s#_7mQI-cHVQEsAq8Zn_Q&=8F@Xb7k&~IDY5NKV+4FKHhg%L zf^bCd{M+8nIQN208t~hIvQ<`kixdlTR;;L?nlhSzo6WU&W$qWshvKe;HFI=aS|uWq z`VC+FulsF%R;SHWytrGUU;}ulTt+O(B+k7AZSdUh3Nd-)50!EA>Z0>^_Bng5Qz&&+ zPccO356=kPvYUT|I&><+4ZB{0Fs+7VZn`&$c$0z~!9n}sJCcWBvzDkRzsNqwW)}dn zZ3Q=TPXbuj<6Nu-T?k-jn|ytdMZ@g_^Qu~IRvY|Ydr=Ug2Z}wee28E39N0S!mtgrz zwr5waIo~FtfnX2BKr=_uz4H!+%}9DWN05zw--Qr&o{j+Vl6Cu)EwHM7AMPBAPuG=o zXmWAT^V8Xieo^cAy*>yrU(R5V$4SDoVVToNHO)$_ybBJ3XD-29R|h=lY30fjEt zp=1h&hfI#KHh<^PepJsgtTGOFCqkg~4MyZLowZ306ACEgGshC)`f5a*iXSYM_smiz zA!6BR7ye2Vf-B+iNgFJLvz+r9jk#~LIm&|>c}MJ)6`F?v-gwr!>US9dv`Kv)+eT5-!7pmFgj6;)tQweDK&HmZ2!RHXJyBr54AeppfDJ1&DT9Sm-9y_b1TuXc)Nt4@llcr;q1 zFL=rze{knLwpQbZgspI_& zznIhYe#+|NF~Pj*2h?gXoubUv6)lqjA%xbGd1|av=;vZ@Z5eelS=wHiq<4?#+{uZy z&pk5Ps%FN9>B#k3Thj4;B=rdSxoNf47A~Lq!kjvpu>Pc}SsV3@y6naIl^o09VNgBe zUt9WAYm}H16r&AI5uN zSg!4mD2t3uSNd=z~cCcCNw;!+a5y^B1y2kd&JS}?&k zb+lYDA&``8w*#GKa1gWk7-~*BU)mbrte3fI!MzMh=E4{Wbn)gEvv7o=xWB(>LJ#fI zn|{nN74Ckr&|szPBK0hMK|t-mEC~k|_rnl!YY)S`YWwwA^u6wnQ6uWvS)00k@$Vcb ztEQp}TD5?(R2jZDq|jJq*PtKvE#@1*-`@KRi^cs2|hSu3;#M;19D))Va^i z9==WWy@!JNg@`pKU0lXF0d7not&73WWv8B5i zK_Wn~+9T|Jhb*ahj`(AGQU`8X=I07yAO?B6?>269I}oa}G+kQH_380U#(@ZhL=wKp zQ37F?X>fW-;(k{q02#TflI31y_k6AFo7PvUnq@n$~1DnzuyTzrq z?}TbY!yum9Kk@(vx4H#~7`)(nUY@0MOJ@d6XR`TOfw}bhP?B&ZMw}0io&0OfXGua& zLLAQ0N;@Go5AzDNn$ni>_BR3Kk-GNKIYDf6?QKSQ;@VePw`;U-(Mi)0TNz=lRF5l= zMY3KEbF*K*>7wr})?gk<#^h5aYwN-d4E5g}&J6{NHCe`P)~92N3lK1Ng$p|zbb>Pb zv^No$Ig$ovM>PNCZ2@S?t2z*b(=GH7CTb$QxtB4B6SDI52u=hviA1}WGo|{~M~zG# zM=HEbN_C}E%%9_(jOFKjwr^@sO9veI2H7-Oo-@q^qJV~uz|ACakb={jdoQ%Q3*CVX z2Jy;a1cp+E@EX8o7W$Ky6Jxl!3l({lMWkIC{Mh}G?qftnz$S2VMvX!MfA~oPt(1^- zqX2^oKQR6LMIZvaQehwl4yHKTb3(NgGdVAA+k((E1X}D0`&D9x=^R_N&)lAPnBDCa zMrW`S-mlkfn~S6KxDwiD!uCfQ&Y&;jSc-VLD^zzHOl1p8RCaTk!mwg-Wpo1wtE)TI z73_Tcm8T_}k| zdCs4wldm)4Fq#inEjAycP>v^HSqc*|C0$dD9hs%FnGXfiIm%x#_3+)b@_{@jqx5L* zCbt|4^7?aJ=5go4e!~cfV~FZb1@$EA!0o3L6xH_N^(hPNaqhs{ zFyqi7Z!w~&ldVt-PKerZl;-zw!@a{ySHCT#j;Ij)&f zsLW*6YD*z%5_u3<&YUJO|9^J-h_tx$44oS!n?Vl3$pH_kV_-jbXXW2mMT!~bjTnj! ztaDA)c@w+wwovCzUF&jXUx%hL9?RO3c+R-wQy_Qxr@-3Y4nhg}uj;}~k%H5N$W*sx z!=IKMB(B;P=Om6Ij?IQigd3NXNKJ2(-rn!9+orkvadpKXtO&o&jERi)G-EwfHfKGw zzaTkw^E6B(qOn!hdNRz$lz^-ILxEMxPJbZlZhOn8|GRlsgRV7TGU=9U^C4x24y#?> z^zYd&#$G3?`B=X6_}lRF$D4Qh7tcyt60rK8=}U$`wKaZ*3kqPe|3JQe&R zglB!koTcEIpTveq_s5U(yWxj_(o;Re{$G59H5cYTIX(6c#3!aejO?)NgNWl(dT%}d zxrYIQn244Mdu5heb|9@swsj=3?YkKSQlok1oC(zKyC^V|5z+*l8mM zM&{rk_)3RCqtB{+2X|%5vIBBd=EL+|sq#$(tXJ99x5E&8oAF~6 zZv?{LRx;cfVn@+2X?s)P0ihcn!3LV(54pSAc-xCjP1gCVnFiM1AVfGD>+-W%8w_O8 zgc|QtDg-YMm(}0Dw2fr<5#b84z8dtsk2lvMj-7E6fMo^q2w(<^#NLRK+xGTu(mzIP z>15#K*~#hnxLf!XGdceR;2igLikjhW`779H$X=XCj9h0P>=WbUya2P!OG-2 zLH?L%etfBtrRaRc&Nc^XFJ}N39oiq8_Z(74BBr6&xHfK?iS($4c;!pYUCNB<(Qb(8 z?Y|xrlI+Iq9#!Y7N7)FQ1Bg}20R0BNeAP@GMEXxQg-XSV4jV$g+^4RE9OtO_8msUV z#!G@QAjQx*&_Mo1AV+?xM)6QoJmrzGkfV^qj3*t`mH-lA=Oe9<#L)v3l%3iE!G{bF z5_%~w##Z-|6QWh85jk3&>=tB}`k~e`AU1ygcK_Nxf-Js8yjort{7sPWoB#zy`wm!WVZ{$KKi|+ zOn}qcX51aay8=QcmlK(awhiGRVhP|2z`g@`Ahte90()3-Nr#6&mMQe8pTzA77m?{d zgeg5nLKiH)aY!xQZ;7KDKuPM@$A(87fyv#II79-FpNd{Pt*GYYUm2RH)Y3VwsEGmW z7*Ot)VX&E4wF3$scmUDOt><-~wu;1xDCXg(I05r0LjqE_C1~QaEKGDyN)04vJPID0 z_Vm_dv2;0cjBeFjX&qt`&S0^&WY$RW#KkUbJb|w4$e;o;?0F{==HI}2d#8=*R$Cub z+(qX=NwvJhQn$1g78`rindl4kscxD68d&oDMDY%R>3E ztX)2~s@)%%IP4%yW0;mCzbFEDP;md708C-6nIKk>%4CsV8`II4r1+36ULfw5KE4-m zVJ$(Q^MrF|+1w7#3`0oj6mFSO;H0B;5KM(KCjnlK4SW=LzOqQTWpE$K4YEA}#8`4| zK9w$GdR#+#>q);jh-X{C21LGi)pfN{?Lm%$h=jeOLMMGjXC6~y8q^=E124&c0Y^&x z`Io^TiD|68L`W-X) z<6EN^M}cPM4C9|)nSLeN+VM#h&3!p?Cp-n(+|^KWlQ=GzO;@t_On5j}&i*CHShfyM z_-j@-2pyD^NzAU0zuaq1&1J%%^QehbTtJYuRwJfnTq+^4xLWp(U`HT7IU9DLNl-~* z8p-|_i7m~rVWs|L06ASH%(H8rhX4bINuD$bZ^N2(CNw#GsnTOJC)DaLkkjqUsrQ(Y z+ZhnZN%o8=*$lF+au}vFBp^4#tIp*uhua=6Na}yftCU!>pWfDj!oVfkCktX5v<$BZ zRzO`{5`kOtaxhb>?z7uiP7U;`?C_4j2k$Q<*65yNG|3Krch4+(7OiCVrnWX6kMvZv zx!t&E5LwrHJBUnz9o!1X0YkTvU_8UahDz1CEH`Ej=?BZwY0l{~MwL%RtA*g#Z?rp% zuC^%7-Q;^26`nY2ln@Z$@D-7p_#=eAE=~0lTb_DnCQFdRI1CSup`(Xq()sJR8pO8E zqMh|kIuMNQiNK9XD|B=adeyB;Vy3{TBa#sD4}y|Jp{Y*MM=WNL5~4jvI4Ebf5(Nqkh= zeF4ICD9?Tr9>SyIj2iMbQQA<=$Dp#`|8t=OyFTK@K+r_DDyhSgb*yyo`h7m2>1TZC zbE|^CT4}#IK^p&ayq@CFz2&_!eKpqJb|Wp^?wD9*s^L4Hn3Oo$@D%#i#Q-c6By#Ap z#IyH`Cj|3~=?ja8{VV^+=Rmv$8K6n5AJb5WK9z5Mq)C+E)7U=`BmkgE)YK#Xd8SFQ zKGGz1gXMIeEOX7HU(9SP?f|SVfSG{;Ff))m!B|>PtBv`QnbDi}iR5W2ksg^Dt@_FB zxc?t^X}G`q_Z4W5b~iyqO6qAi;@JThhw(-`ST)qJ$3W~n7|`Luz8cngeF-d&8WjU3 zA+&i!f#v1pn3Pmq2`kB>&&{tW8ND!ifSUqrp=D6^&hVA9>M*>?KsulEks4r>9|y!p z0|Jp%!0%R5>KqRlWoeRpJgb?y5gyj+(+DGX%V+H%6bYq>>j_W)L zvkhQ{kJxEP#6PxZ7%py@L-@(54eZe*nNu+Ep}K6^NrAmlHHYW zzYFruk52aY0#Zn3lHZjwh$euPC@a9hEdesfLE+f6ApixKx*kZjC*CgwqR&K`ZVu(( z(Yy!@JTgSS1Cr+^XN^Gazhr=a2X3agU~gtkE%RCaII&Q*B!eo}8lE=RTpzn7{uo2O ztFn2?J?}KiYB5Cas6){w&+yBH<1@O*EvpwW4sbu$Bud?GnL;w3d;p@9mJTf9( zVpW^R*Tw4GIy+vdhB$u)xXU2`PeONxJS5^dWVjwI8c2+R*I+LJ7G%YkwJKNK1b7V= z(`BaG0QsTq@@Ta`qXUMI0|Uf^@BFU90$dJJ%HU7IG@>B&anMVcB#Zuv`MA>jMC0?b zBd=4iIbNWMm-dh(;qKt+Ua__TXS|V{Qa9ZBwKn#&dX7Ib7G-{)qC#f*}64+m(GgE1k!+16ogr8<>Ce$1$(ZJLEQ(50X|J zQQuDYniXdrgtVg~PeN=f_4Nk1#zXU}R1HX-$JL+qfT6tvuwpSLc;^hq@HvYIuR$F6 zi&ol&Wy-VP(9Y6$Y%^)nmJL&-iJgyLW$CCUc6p(k0lNUm@QY(;Tfheik?qRLEY}+S z?Xg%CF-%uf=)LCuqpmE3duhoca%Wl$63hrSxbwc^n1tXvPnF2talXtw1}MEj7mL1& zC~xSM-=WeTT{*QxLuocKT?woMAvfjob6+sIvW@a zm<|;uEi+o?tz$h_ z?(T6*{}In_!5>!rGDKfcXhh|*FDF4bn99X)d(rfOn&oqCIR%_$km!neX|2UC?XNkio2Lo}SzJ0>8RkK#R<|GH;90lwBBe8tSW9OGO6=ly|IBh0q*UuJUENgq8 zjWcB&cl)vV0R(T-2|ZUm$M?|yd46PS4diP=!fNQZ_k9r{T10gLm>IvQdIgDt^A^W_ zJwdCotWTKK`*fJqvrML);$Vn0W#Sl^r!W^jPM~ip1KU3n46Krt{J)$J+QMcL^#W? z6>&mqO~TAfr9vX}NoAH)la~ykfT(<>j|-tMXQUtQ@0j*+*@_AJbEB>dG04q8)j!?- z%9FyOH*G{vcD|B!r@V1EShJzeEJsSyfg+|%QCx!Y1WxC)0qZGgkx|0kG4BI1vqAqH zNDf+OsZ1=XS;Z#=P5JF8(_pe7wj_0vO#l zg|Vad^k z7IYFiBlgycF*e1IM@lAySjqeNwd?apq|v8Y-;8x#Uha0-KgZ})VnEp(>Vpatg!u0m z8RwKhOY)2(eGi1S!(H4y9XHYD-P>rx$Uh4e)XL)0`BE#YzbJD-K# z!nW{Q{ie#B3a^=v-h}n#GV|V6+Jw=o?Ps6f9B#-ya?FpDn|A>${V*pXEMaM-GxlV7 zvp-|ndB2-PFwIp>x-ekD8JGPZtbdt=AGH9oN-^*arR>B zU-C;}V&Jce8c6kq*YQBVDS$4Qz~kLyHiV^$5Nx(=EK_%7o?*fC{AIT0LI%l z4in-T-oEyEyISsSQ0e`0vwNATg&|>Pes}h#=nTK@WpYj{JfwLmqv771tMS-qNVzxp zJLWeZILP$r7waP6R4VvZ87Dq@vqj6BLK*I3FBlGhYibiHp;wt|wOCs$7gANcurJBk--%sdG7=iZ?7mE9oiB``LWl`dz(f76|Z+|QK+Z?XbqI( z<f zu|M(995jDuuy=u1;?ftDO^kh6wt3%hCrw^|qXqb46pCwCVNqs>x(W{4S?gwlaHSaL zd;?v#%YJh26mN-UYItT!T-=>P5$-frgD{-V9q?vBjvHare(ME2(V}Ccl4?P)^+NGQ zH~VWSEYHqXENU6%^N0ipsDk!M#a2a`qjFOA=DGazEfk>k2FNMzBuP;+j>N|Sh~{cr znp)_0SZG}!f_JpNC*^LuD)}K{A+VmI^JCp7J4e>-%aQ1+-}tY>YaS41>f%Vt9QHR* zreg^!@JzaZm)P)`wdd$L_{^867-TW)a~j}~ss*O==u5viA|Ya)TEcy?j(OrcdlD}x zlcVfLXZ8DTT*AoD=vQMQAkCz++pVV#?bxhzw{Wd|i}~l|dlOMXmPzQkJzYgAwc%Jq zH%~+!uKHZf!T~O-lIU{fnL2Oqyi|GyOK*D;042%%D7+v0rQV6M)&mCVM-hQnTyu~+ z%4RG3;t*WU=wk;iG?|I4ot7>82$C!u&($5{8^tkzUGP4V3*%Fojwlz zv75xX&`lFqLoHA7CYsaTo zg4q}~BZgvAB3pe&re@|$_74^wajnlPi_O$p<}-WE=6rkgv3z7w{|{V~;&hJ4bCz_7 zJbfFzFqi$wBVU#1%{xWZ@t9P(AhVa_|NS%M^6pAi44dnu#P0muhe!ykX@+nKR zwyM*I>kZh}@bvRYXM?!;??C30lN9|*uidBS(!fb1*hyS! z75+dPWXJ-F6hKuc=pouw8QuJOZ?nyHfuWr;t}mRlgpAA2wZMa~GO!RoCzrW*cD3(! ze>HxE<~&J;f%A!NpaQ_EH?tZAYtg7)v+?m@``d}G7HHGHp{XseI>y!yXG$}+U%7Eb zKnsKqNmeR?d$sOwKX7OlUNFmgK`?2xP_NvIZ2@evp$A=Vgm%_7R*~=df_0s-)Gb`# zmBy`z07xQWJfMKg!$L~%aJFvFyLEr%uEPxotvRjkwyG_W>Hgy48uLP}t$M&mbWm(x z;>LXQXUYBUAjca!lg_x$#a8km7_c})Pluh8-xY~)@IgA1rFs)*H_STWGKU6G4^G$W z;JueP6Y067 zbX4H!t6zWNig=Pi#*Rm(&4@4Iqp;MMCJato1((TUfQN)VSqyda1r(N%%N zm59X9z8-DEXv4VDx8)T*q9ourSas^@;ojX1eEahqxQ?jAtTr`>@KDg12;$||#WJrO zPB|y$fT1eybCt+6yWG38Ix#OY*bEl|TCZv~VZ=+LLztLYz8?JxAZ})e5ExI=*H~5^ z>(ruh)8}5*7M1YZWb@lVm6e#BGI4N8wprzdI2uQfYa~m1bhMgYoSMQ;s8Gk5EDxuF zNQ~tHK(C6NB#eMQ|%~)P+jyBJMI)j0HYE_H5^yd5A+_#I0KK7F-uyd+wJ42^wJs zalKz0fPH)1$z$U6;1rR|bP+4N|CVZ%%mBc5=Y<+~8hru1B5-tOIFL$&qUEL;} z3tN)xNOu|g))o}JJ@9?Zs50?N6@A@gtSQGMcsjs#_G{5)Yv}o`rD34DeoubzHN{$( zLb^@iaZ103IfH50T@E#?edGP1ecN}cBqhf#VlC2l@uy8(huY^Z4)<`bF3|Wx zma&>>=!4aAD!zee@cDKOt80+!5siBAX!h*0n+hK35hu~X80i-7Q~*i2kp zQAS*xQqkVV*v!%h0pWdEV)E0^O0zG6M_P8Ma_K(5$>kCKDuVEas#;N;m0Jv-GJyz5 zv^xqj>UStLHPUV--jlJ0A7~WPJw&Rs!w3k|ddM?`F(89(;xSE&LO2$>Ye#NgMM!NsjbRT;gvM zl~6Pe8Yj{Fex|!`ZzC`;(~J;p=6uo!=!90PhCZ0|3~@xStuSb(<8KQOo*=O%aVelO zSti}=WaU=9)xo3w^Mciw!#I^DYmi9>J9#(EGl|PvMPF_Gt;sWLBojVCz6qP*kT;Xv zakyspp1F0mS~{#di%R2dunJ!~?etipO_~J(lXCCY7 z4?^K9#2nAG@$&j_E6Y-(bf@O6d^L_JdN<<`;<;*i)8)2yOk0x z(9iTIrmZOT`zQK8@k^hii?H-Pg|)LNqFx3By~(utFL(Sn%!KG5l7j-SmIsYoFZ8ftO#*J zZi0d9UvUzTk$g&<`xMQ4a@Q}AWDa?dNhgG!+pQ%ihjtXhO7LRg?+^g%neUauW*#;ak> ztq6<`J6qybEx8*Tu=<#^)Nq$!8ac2z+BuL?BRRfv zNE?<9U=DavzloEVksrg43#^X(EY1&Yly;Y+kH_k_UMI3gbt7qr@{GMpx%-$zZ9z2{ zx6yAM!<=lD)IxVF8%1eC*&CxtpG>Dp?IM3zFfZrk-<%6k%A#r0Y1Ml8=9zt0k0jYH zOZA>gIaefCXC%D&M&d?E_FwIDPd{!n4P+~GDHAbzCYCWqGS+<- zDjHUDQrall{K5U>ve;WC|A$*KUCDu>#Yc~CQ7SyjI4Zh7TA}y9{tdcKxG9{~pPg=! zWxD7hPq9s+jjH9_DdsB~Xer5!Ybt$fkUq=Xlw&qx<|(5s(=V&i$e(*|MQG*cTzScN zu*F69Dj-RW>AQAb}|&#`R!Lb!F$Gg+&e;JG`pi0s~2A{<}P~9Yc7z_ zr+0a_mv|_N{$k-{Ig>aNd9rbFL~zaP&*)zdy`Kysi+J6{8W8fGf-<@mvQqm z_uN^rhYl}{TdOy=SacKaQ)iNAMRHRxLs#nf9fb`h4I zMKV%0XBDW|@m`-)zuCUdk+3P-_VKr)VYxxpm57_G$GV%N8>4%$N0OV+<=BPnvH9_< zv)T)tHLt~|YinCoorTfg`&WPMsu{Fiw(fbd-o)OC-4EPlU8nyGzlR|$BP{u5BH|!p zAqDv{i&BQZsOH?pgN0`H2)&5FGJcx;R2ZxBnL5cBo-DdHxdz2Qp&`LiwtdlhyL#GY zK`|D6842yKkoVDjd3}CGPd@JDSxb~iW8`TX*s|lXPqMFt3lbh_K$^RpWe($-YC3WTG{ig%}jIi9XTt3`tWY(llVV4_}3j74`U)Smtuo#?y)k)IAGi6O} zExUNGS!?9{@v`YpY&y)I%Yl0n^M3hWT)f<}oVU&Q<19{%h$K)4rys_sk>}Au$ZrC z5cYZ8%6=kzMR6?jSIbOI-5%G2?QD6xIJ7uQce`yuxkPnK)u#+^3UeZOLZ`T@qNHTH zh}F`Ugcd75B#CraXy2~BX0-W4B;H=>0nb*#e*LDRvTadt*QNTN=w5BjE@15i!)u1q zwA{_fKL*TU%*bVMcnUG{B>$~RdyFm`od#t{MX>;nap z=x{k$+dt_&Qd)v~_T3g;R$da^EA?*mjnEJ+GNCm%)=BO0|BX z*yp>phUlt`~!rSBc&S&G!&p&ZhR!V4m+7n!dBvR&txo86$NMyJPK4M*Z~a z`Astbue?TTGR7Z1ATWae(GUVJ~StVXr}Dy)%4*=SGk2w1){SH z)vhEiCZ>d_;w##305-@@k*F1^kzU9pXoN|Mph$?IkRpZ^wxa#_{WB!|kxwGyRPYa!ClfCJ{Vppiva0^f zlwSh=Fr&>||31@}GPTMMl`;*Z64eT4ACmOKC_=weksPt0XSLP~{A&bqwL?PL!5fAz zbdsUaTnmhe@8ysLg+=T&gx&tWsvKT>QDx ze6qMGO|I-y?s-N4-GA!}Y7iSF19Pbd!#TKH!dN z)R-q~NXXG;$tAsIe|TMQz0eq(HwdDYpwvYx)oz-4$)ZIx$zEOhO-27itJ*Y{S+jO1 zjmvCxektx{(K-BWW0+9Tcph%HvQ_e>uu7B)6~c;@sgv<+;>+E~3qH_g&~=n{f#(|D z`(87+2bVMJG}lWgV=`w6^~~1W87RqDNkk;7f%Zbsb4<2hA$=VVs`ZYqoF*JCy_Ox z1rzH%3T;-9W9_60e275V0<7;G_=tF~X~D!2s|uUrsdhS`-_y;P=&U^@nc;_%uKDUTAdU zYd1b!@8|Zo+|MY&z%jhvDa^J!n5!}Sfn$T(d^u-PW(BLAsxpD@&DE56-JSHB^=qbr zH^T2L+UggVa+x(srp|D4IW;KudMyU4SO!5G)3Zlvq8wfIAPQkil@@% zegBJv!{}iv(#LRb*Qdvt}^gXEQLS z__%#VuBd}c?t5hmgGtByg&)$5UA>@!7YTxAL!8c|l7zFVCRt`L7(b(te<~Pkc2AH# zKEsY5NURE`o9k(G+H2h4ciNSxOLRtrJ~nJ+IfN|Pc49ft+w~@LGm$YMQ6CEQyv5vr{W-r8vyNY-)hcV6 ze0>f@;Z75|ye+i*z11|Yc<7xN1oZMhdntV8rJ~6X z7JKTzh&70&iDUE8rdW+_^pblFwccN9?oE~?hj+)>uJ^@8^(zP*7@A}{C57ufT(v#E z+YM%O-Wls2=3R?0o$*5~d`jWT#*fBrvj}k^b&I{+&W|=8C9cr)I;ff6FRNR$*8*{_ z*I(|8GZcg@kMAj=Jj)ar4r5?gPf${@TkSVJ{$(_ncND=O^bgd&u;_KA?Xvia%XAs# zxTK=hUjN@;aUAvA%Y(8{-(_p{yPw^HfwTfsweD<0Sa=h{=^tq#U@}Z9uo6fx-`X8c z*o2rSVW%=+fDm#T7J^UGUGoUK@c_(J=at}`URj=-6oV-Cf+w*_UZFbzN6l+d#JsjS zB?j`}S5s% zWjwBbTcd^k^;vZYe1E%pe0Me?;JuaQVciiPI3k`+t!Rp3UjQRV8To=Ad@Y~J|E_Uw zO4G)vqXA~!#D^#L8aMXg{uVah;BXKp#}d}+kV-^xx#)2u8GVI88e+?BH8*iN?*MJ% zTVXIG{!RVT9cEQG8!h~>EwOvpbmW{ri8l3tXW_ZvOPlKnC8*QI@A&Rp@jxBV6G@ok z_=f{9dtI^|&V4_eu!DSnAIa`ojU%EYNJ9>%t`?J(6 z*asZkMzNxK^s_?9oKpyP!J2PSM{4zKUU8*a3}a(|7k>Wzo$*@~6UG>v8|TCMStH`} zsct#Q*o5RO4aSK3n60e2ab@ZvgL){jF>t=MxFk@5i=lW%}J;oqNe#BzS15 z!O3o?154KRHoNO4A?I+CTy8ET$}Xth^QK+!XxBSE(J^mwKES6hgbn+W3L-$RK_~L) z@moFj6QhZVU+u@4#PGce?uj5?8^$^je261HlWbYZ9Q_Wuru6=#mtu;aWB1S?CxV*L zB$R4%Pf^Q#HJzw(P6CMn;%xvK`65Kpgh}!?G3M5*9b>#Fsbo!(atVF?o2&b12h1P_ z`HWprDrl{#v^^g89Cv46?48fD-&3vW`~9jBFkf9Gx}9eG<9GOpXioHort#WaPkKm{ z$UkLFr=Ko!9UAr^5i&tG4SSw5L};4AkN7=!)zr>2qEE@5zxY#DJ2%i1O>tDfd^5B7 zkN(?3bcl?%YsL`OMwpn#L5->`bZ~3?s5md3qUY`{VgcGg)re3xwp37mRp~gc@MV_U zuV2S=m6oP?N^{s}k&NmJ0hf2=1-P=ZdhO>p2SfzyV zo_e1<-cq=&r zZBK-s#0B+KM7_OGN(L)fJ8Do$hOYRg;O$~v+x92c!&J&^*i?c2B=NI5+#IHM8;Poo zJL29H+4C|1byxii*(f|sMyyHl2KurJSBDGX-(;%&s=af<8ZzWbuX@huHbptS3IR5= z9^(s8pCDIY94{q{vXJS<#pwPZef&Loj-rZaSf`Rw(=4O4l2hw?!e z0aTvXG^xzJL<_Hv+pp9K)}RzhL?x^um4&B>iP-pWw`8H~ijq`66`~SZPq)Z$MsSiw zlxp$}OW5(S=Y-t+SgioGgh8^tBGz4HOHJ6_82={p3)lI>UeE z?Bs9GnDHtlI%a`Vo4C_}}wA_0zkU!@dWjzaCi1c>||Z6 zdqX9H#xyh(2S95n6iUV_tczU((g#XDzn`nA1jthT>A8Y%BpZ_s@M43T&Sxfo7fBf? zPliqizU=~FxK0m%p>-DFq%0`ai~b(saEJ249TZ8W!!>@1^)AlU__Dc(3zV`K1Bg~Z z;aeINsE!;-?}#nVwIHO<9uJ^S29yaaRtAPoe{d1;`aU3?LLAPTi&Q`@d$*PI2B;xKO%{l;2Aw!fQftD zRG8qHSe`P$H8|5Qd$aM403N&Xm1~N6p8918$e??+klkhXJLBy{u zLBt(Gk4AI>!oveEG&b)rN<#d3l)^wDbgzbw6iwcj0 zlly*UujPo~Rdw1si$;Dp7QZ~GTbld&g2}S!pti~&ijRH(H`nW8QuP2FKXtN+j1Bjh z0xq=x;WZf$zE%4YfQt1?_~E(}o)dy6+HTJx1B7oG6f#WZZLMLoWn^yau^|0?mmGLB zHOSg#>2rUPTmqdg*R}#D{YeN(o}l-gD;y*$|M=8RMzTPxPQ-1Q;&r_eawzuqmyz5R z+2Op<=zNzhA!xNTdN`>H)sfhNbh^Sc`{X*Wd_UQ_@qk z+4m5e5M98}FtS4Cy7{rAF_S1fl?iQNxn=?Z$_N@$Q^@Pw$5t6NdL>{EoIV4ZOc1F);lvSHoH7npWEhH?pj2=NZjtRaELba|#g76#E$ zw$I%fMXlv52SY-_Y>6tXcuKbW?wh@t%6z+W+-;sk*G}}a&2$^6W})+m_f9l=cg+^>v`VJHOtYwpr#ndy{SKoK961kxBFEFV`ks?(bf-W zZ-gK3#sLT?6Axxx2APF^?Ml$`_j`ct;+!Ypnb#Kja;)cRKf~}@u7$KJK5GE$#cFrB z!ReEEkc#Y&LxpQVymM}{w7+kO+4Tc&V^5zj*tB`AbOc$a`t(PcEbY%$9fVML+Zui1 zc3Sq28>%l_e&+?Ud(>pt&iD?dRaUj9yWCE@pRc3^=;c#zeTtaXe|1Skk(w=eo<$O5 zd_jWHN+200P;i}QaTtBwQ-Gs?ti!J?4)ZKc`}o=n6_*Dvn2M&A5!w_uqStv9pJG;E zL2*}#wVP_mT$lY0N&lqtjBE~PT5uW<+2#d)iN(o#B8)lu&EmGM?H(kVmYkj9;=;f!?za;ubU&EEfAX&6@!XrSQj{lr4fwV)Y@4~1tKJdJT^ud;~p0&%G@e{L_e z35PT`uly#&#QVwB-Y1G^9&2eV8d%Ns6VEX$`H5t z*;CcU8}hS5=}bx^<=UaUAvlQV(gB-&pioGSIvV*S<}0%zUBEfa8@DorQjotR#2V&Y z(q{EeAh=^0XBjZ`Xigq<6HS0ZPP$BE(cWg@olHGq7)ZF7=gOne{v)SlH0|VJ99`s? z2`=nZ<}vNU3o{C0hfwItsp@*wO#V>nMJHVCOvYf3t3T39F(7Z4coY}_V@|ejoEb_qn3qZ z4FXh@RA)-uho}2zod$VwZYSM@0w=%EL{aci6j-!J7h62iqgzI6B){zF=--Jn)?xZCLIh*&-a7>kYg2W~oh} z8DvHxCWJy_tm+oHgOP+$$~W~eM-p5Kg`I6Y8_*_hDe9JnP5!Q(sJcJW7z+D~*5T6F zOyNDnw0RPZRf%q(2PVVHURQKz?Q(y2c;VHrY>z`eLc+D)-SOpI+(B{5V^6lzAU_@m zJF9hd*fGi?k+wAN^2gH@4aR5>ZdS|X++dd1rTUiJTBY6Lj*MkQ&_UXhLCR(}$8E)? zWq*u3&-&k^1!uzoBUUu)wtHoD{3CHkMry3V7)V+VHzPi%;f{l@Ra#$+8YC&#K&}!^ zA^!Io>9iZu;EwkO4|SXd+q0c}>RQiz^we#%TW+21`o4W+j5K>+I>J=jbtOm&6H_!7 z+cD_G{U+B=>kfy}vJSf<>W=u{m@AokjJa?S%9ApZQ@Pa35C9`!R;sub6=g{>$#N?Q zcd(bw7V_GUl_q~Rl|!CR@pO> z2Ct>ArF7lV>oe<*)QR&HXE1u=WwNf!%N!*JcjnYDnM6|A#>o!P3w zTX6~ETzZ8tlaT5D1hVFixL4YyQERJ zN4>CjYCAu~L_)YP$Wbfsc%a2@*tCuC@%r?}dK?2yXTO0B?-Tz)^|&WDdv;*W_2Qs? z`0rr7cG4e&?RKs5S`A@*_%ucdb0kUv$Hzo$IeW4i1yO%57SuXR*21BSp8dph#*Pr) z%s>jGyXetml1t6&n%Q(S}SrI!^nALJ-8UV0Z&P|TsbWK)tIZ0?|u`SZI_QF#Vhdl2fcV5-Inuo zFo!^U^Y*Z5B&<9-8($;WnsnqU5QB;I&bxr{BloQt&JqI)dAn%F7s0h;bSGSBk0t|D zmq&=bK*SDv8Ok>i3#E9KN9ua2z1k!zpL*zN>l=U_}j%fa#ue?-FYR}=FV1d7TZ z>cWmB|C7unh~gU$DlSnZtqAluivnl0=Q8pgN+1OrIXRLn*y;4#!+E^l4s{wlgWjR} zq^x-fb$flHC&x$DAkvm>tni+26)_xM2aJ|Y-I8|`0YS3?YF-DCwj+I_uFHZGi|{4| zeo1FaMwH1pAhQIHlI-VX?|Ucd6AY^9o|SEV5M=-%}Tog{k!==;uoJ<@P9zRC6CqDm!nOt&;SE zzm%Kj(Xx!`6TNkT&PE%G)qaFGi-J0D$Qdq9THZi>Sm<4A!XgY(3VNS2s9WO|;fB2^ zV=9-`y1DxzXJ=k@Zy&`P9g2$wYBjA zjji5*-t{BXuTVK{Q{ez8-MiJm>P`&%V^?8~%+mQUbJs?zqw**EU+Cgd8M@eK-QEly zVI0stUdK8udAr*Cy}!&n-B}gBr@g(#aPs6YD~v`sIcL+$%-E~-K)FNvgwC*YotG43 z8|PBY%BQ_$D6AOO{fVqiNV5L1nl;h)WAYdp!*>TQ>J>wZytHDiFX`577k`_g zI7CJ~f2Ec2-TesHf1uL?PUHm1Q11JFe0?I%AlBFonGH5^J$;@!6>CC89Sm^`W>~%s znLk~pC2#eU4s#*4ajke*!I%$`^@dC_z0R7q7*dL@H;QIxyM+;&5N37tFGhvcX$2rT0)(w7Yq_ zpOEB2$Jbn@3CdX7i9Ua`n>Bwo227Y6Wu&mc|p$31# znmhi)pfXhoR5y9rM*6@`6PQ(qzUlGrnf?g&?m%T1B}2ork2l4E#d z)&wTn4P}ho38ucm?~oaqlMm#LgSTeKLT*E^D*rB*JoE3Z9DTf+xsS8*Ech8npvmf_jnh4T5M#C^mNCEG;usrsLMbkCePT5RDHQT$=(;g z-LfsDO)pF=)5|Hvn~L52y4j~#NH5s%2x-8OOgRYz{|^m?tod_;aWhOI`4Z%E&H=nb zh37|Uxp5IGoZFq0ip7QYh31NlSL{|hxgq5CM-YaW9ups>C9`$1ceO=!%0o`!tOusw zPpZ~Z2qv+S$)RE1H2%ELgSIoko~Zd|`pF+j5NxEX+iWj-}x3!Ap2?dvSR2^r_yJgIie`PdFyT?*S===OIg40uS@PocdGNeK z*cI~nHv=Ry6NpTcbTm0S&c-ASpvfCxF6*(GpOQZn6V!ePW5{}a)zL4o>$c39 zy_Mk*RbvI?4y86u<#B@N4_0f4qs^48iLpz6bH&R*{(4Au@nZ~|n4`0}AGSb|q7)N)a!d}r4wRctK;>MnMGMd2Nt3Ri_{wi9oF*yQIDQ1P#q+8dr#6y^ zy<=PdbkPOnr)q@`x8)35GLFr;=TXbmd~Voo2lnE4ln7pM{YH{zhIC{OHRC?bqXbaw zM)=xS-}N{ypexZ<0WOW#u2_wI!puI8@X@-+&}|85b5XfVP*((Y`SXX@mx7lw22yI> zBxbWhKtR16@p&+?X}M7OWCwMGWHB6cihu9*TOO34%ti}5g^bVU09u2QzR9X~wg;Pc z**C??8_xJU@BS!kRBjgT3Zr1u`Q!ftBZ9|rRrD8*2cY^EqOajHvY41>4B^1a!5H&` zVf=>-1{kmeFj#9hIr|?X7F)qy3HT-Dt=D_o? z_4cq`nZaL3kk!Oup|K`>DM|!ecdz zp^=C-kH`Jov=d{K)wI1aCJKU1=t`q<4R|uX6M6a!G(OgbP7kS4_GW1FM+(^ajnQd* zIARuENAmWDM>OO#^sE%m!v^!&iXee*_wjEaqwPYjGM(r8862|1q6!H`_UnuWlUT3_ zTSWsb~o0iw-YeRt$z-0=q#^{iu6wzXWA6x}g?? z6CL@4_OKr(apzsSRc-2R>=HQ9te1ay-~TJ;$AKLCk~s{qTd${Jh5n#Oko~NSs&F0a zpe2L(vA{y!Wy#}LD7}syb#w)-TQdDYR~Uh|+IpHrIs0mJ7-q!@AaQvh_c?Ye*MP^) z(|d6_T0*%=Qf=7FDfu-VZ3R1G=aVg^5F>$~Cnc^mEj5KkTuxNPSI(KP46)UGqD6*r zgOsc_tco45G201$X)X;Rckk<7xn^hJ=nC}28<7lu$v65X4X09RAFN8}MXNl6RB5p5 z5>rxL%D50y86BgDClG~U8-(f>BNkpm{M~5gy6m9*JG4B$lJet^H)|>F$K8awGeFnb z=aCeygINm@Rv1np@bEMPrExgjMUBmp&Z$9yhYLDalz`S6rRU^(5%z=)6}%*Q~quQCL4KTvw@8MK8qfP zyZHMlO~f|xocbz=oLEG!8-a3gP+U@OKVIxP_qms|-5ahvk7uM^qxYbrh!Rnn(K%mLP9w#?zHPSI-hO%@mANm`BS*-hn~NdN`1p> zsu#s<^)GId>@CA2M;6V(Kgxj5I{~-b1rCTOR0+#M%;6&3Xlw8G@P@m`5&7ARj7kRW{BGJ1v5b6Z9v1h@i_eK08qtS{1{hbywSK#$|S;DdIwt45}+xL1}*8pl@@ol z_c|GJ%AY{60q|f^_ww_A=Rty!706bT8V~pPlH67+X@Qfs(!FU@KO`puZ>vAT{dXLq zB3UN%uS+mNIQG(%CXf*)ylRTO+79|Zy|B_RXUP>Gp53m6F&*@(Ta=p9RatAQ))+fc zV{rVZ>QVY-;Elv8sm>BCv0zM|Q<#+1Qdrf<2^e28HsxC^DE7VqZaDxI!$pd$J?IbF z(yF)`3R88;;#%hU;F*8xQIAh-tGk~U4F z^FbOvL!Wh~+oRAowd2?y9jL_UX2dCeC08mrcu&CzpU45=#kkgl=N zXhc#-ChXmOaR8fUX}#8m3x3s}FR=yB74xkCyf7cSG-OIGcKCH#)8a|6>;i`(vvW0j z;x0GTIl2EjQ=2=BBo7+!eC#vH#%&k`wk9s8a=e{9j@Fj;uQ_$9rmT)Cqn--sL9xiK zYKlvLK4G#*+Nm@Dzrb_`2v#<%t=D;EP7@!UfqF3u&X1SH^T37m*BS(xQr%1H5a9*r zZ+6&#eh};G*mt>uD1pPDZzL_*fZ?1lPHxM77xEE&e7gTK^T^Je7J|ZOfK7> zQlwmoIkfciZMoH!a!#`g+|?6W4mW?VUAuJ6N}uyJaH$l$GPRB`c>B{SmOZa#k8x(A z8>>wA`!C6ekZr+UI4)WAzO{mjj%T~C-GJNn670q^aPJ%dUsL7U0tUVZiK;r4KnDDi z^j2LTfUV~H0~;TQyau?p>vWK{3`m-_Km%wTps`0|)UgKAyd~HV9boDdoW>D=4|j&^ zCYmEzf>uEEuLTv&7NlG6jsXgH0bpu}Ej-n7t#e0iv#~CgwmW+dfO)n5Nj&1t!JU0@ zbt{sD2l#Uv8~&}}VUqDr$bK?8?S+vGdDgGokM#gOljCFM96i!Uq^A8};hN-JrZEJH zD)tM=SQ~CqnkjxkNi|#bpM*S)Xm3~V;}7P?1=R9`-&s!W(P(WZn4}*8srU-T0jS;Ze9g_Qq3<@&cJn22m4AtPdKeZoNc@ zOd61;7Xfw>@K^~VyrYs7s%W{?5CHh{U|QFw#t-=^e{2?T2@-hEX~yx#*Mc-Dcv=u( zW`WgEntfmpd-JJ)J5&UMh{BZ(`I}cR>lx0`y!dO_{p8zBFqXO6mO|OQuID>?R_o_& zKjf!?{AsimyFv!wdYv-}rSVW8hzi?kuG&uf2AG#;|HI!;qp@tF4REzkFxLo15+TRb z>>UWMA!w9RZa{?1m+R!$?`mbPo$*)R8!wD*0d(!hSb7x+OU~39%h@q_vP3AfJ@!33 zybg7IbyVnT-r*A1TQz_SEQ8?#4;fwy$gO0xOq#z0UIF|W-c`t?UZK;n51Mv5_@YgZ z^aG7DClLK94td5Ix#@7&7Sus==Igt}$U~2oV!3$xtY*{rZ?|I&$gF3+$k?{R-i_Jf z!I+i6Y6b)9_d(-!*K@p4JQ^upC_!a@(+5(9h*4#0kTDT_7+cFd-C9ey*pr4FJfbt) z;*EG5wM+-00HuBxqJ`@7i5OYxsQD~P8>stW0HV8T?{`ZoEP-}q+tH7G`VIB~gzTiTHExhp5Dg@=ZY zCHB%-5fjUs>v&`-S5yyt&_3-=*kCx3VpTw!7Jj^ePJfVwoUom6!&Q5@oi3a(=^IO{ zK*U!6asp3dOMfY_OVom%<3Fl$KA5Woz22mb&_7m{DRKu^*JktYx^M`dh;Ein5o4h`Wu=zqi z)nH@#FrdNhW6gYPXFX^do5)yNL;sF&#{Wf49*m>mFYxN{e33|nXRP7xgn&7>JbVDX z4Y&x!R70#Sfu@^*Kn-5N{e1iSgLS4gKeCAH_ZE*Ug%o;k8uAs82AE81yJViR+}zi|C0S zy~d_>K5?wfnVhPL@y}2*LAVoOw#o!XV$-~W5^oI&PVRPY+`+_N0B&RJrYq``*Cz@m zQ_YosT>59F?&4$JIuJuy{oM{5wt7g{qA#+$8`b}l+Yh0ZN4PYTnapo7^|r0w zEwFmU?VRG$?5KnBvOzW76di;Li`eoMq=@j02r&?S(hZ^b7R z4a3#brWDuc6kc{@qpnXz)G?t5*ix;IlK~eMxHqGOw}x0!P~sY9IS-ThXSXBUSaxkc zjV6C+v_C8q>ddSg#bF;Mu&~e^o&@uR@lwk!5(P1MMZS7>N55r;Pk~tweklL*_wzRe zgii#!Q2J%7cYtd_R>NCnPrixxx>%L9X{$g2A%WKd<*w^mE7Xp|B;8iS?&ZMQw_7?n zg&c4_K*ohbjes@uoyE%*&Sw>DLfU!q#LHBkBB~@KJef(wcX3mx&T_otZq5TPIt`R* zbabS$5V^D;W65NQjnl57L+zOEy>y4%}xI$N->Vr%7P~0D{ztL;&FxZo0kfNfs>w zXb=qw@M`dg!W%d`&0&LIL0E&7B!WlHfIJ}2sb~aj@t_beP1$8l%7TXf|CWGhig(2P zI|wrk9heF}#6dZo;6-At{->SIdp8wi&<+2Yx(XWP;lBYq3P-+Ig^E~kcNZ!^*xW@W z@}TZ!xLxg5sR$L|KEnV2d`Tvh3qakAa6o+j<}efhVo z;NFNPi$ZU2syv*pRV6^9b_D%a?R#;eeyxQhd<4g2C@ofRZsN0HXOEt(Gqu&G(;bcX zE$IiNE;uD>W&!#0Ic~@XO9X|2dUBi0Z{ncIN=?sa3$Wnb9m9e|GVxlQFL>xFmE|uZ zf)e#M;{lq2JGO3e;TyZAAA=vby=Sgds;zL$EmW~v#<*eDRVfE@4~&cj?C90h@V+9E z$>|tKWHPvILFWLxRY47Kg|%m$TWZwWrhcFhSfG!}Ff|Y&H&_dfteRv}CG5{Q^w^3Q z&}>Wpr(TmbnRkmfc#GXO;{Eu~rLJsb(yO$WPB8Db1_Vcmq=zn_#?=oTWh$1ZimQAE zJ(v~%7*?i!XKK&m3)g};^mU3`9NU?gRa+V^G7`E%_3g^!R0Yr$icbY63P zM{uw8-9a=9v4nk!df=(PN6WKu{bkyN4oldTr3Z3t!BODEanQ#T(;1^esZA)JTgRnC`WO-@Ae51@N0NQ;kj*$w2O={)PM63PIU z-)O!x44j=AzRrLc{`DqDPjCb{*-s;L_Pq8G>*m6f+f3z)fF1c;)zfUN#1d=UG~&_rzhjDb>mJ!PbIiGQG`VyG_S30 zF;S!!O5yV%z5FWb<{WmcfT!4|)8_3}0xohqxN*1x=ji?mO%@4W6*C!Ai~GedU@C+0EO`?Au?GIROW-M#7KA!4D?fmQ zWD0)UY+W9j#qDSB`E6_jL@awphxm%NDL+UGC40qvDX0 z{<*A~)^Rw~aanZR+OD-*>zM@$Jws87=fMW?=oIv1)KaMv*dTe4(6%dk$ZD^l!iax;S{M{wtiW=5T<~A5RRU}E%W-f4q2+?>rhw(%>uI z-|q>oELpYtKVji%Jh3#8Sb*(L?ulcBv2Zy`;#*zyf=M7j`G{ut0pde)lJ0eRZNlxm zt)|)P>W10io<3FOkR{NIZf4uNPC*aLX~X$ytzSHb$3uaqZKBslBR;n4RjyGp04{^^ z@D!Z^=-YUBoA5@d)Mlx*N5}^Fs>;9}$NtFXTdRlo(JpY+0YzK;G;Cm5;Bj;awQ#QxRfv1CPP<5Vf=J+RiZ?qc(TQN>pKTAW3o%f>#NMu$i* ze~FxIL8`R+!n!PfZ;+6=?jvirg5TG}`Oqi+vzYiRPGgb(r;;m=hq7J69r^mKC8Cfe zd$J@^7!%odvL&Ii4A~<4`cY&H*|KGXi5bgaG?pQ$;n*^KLXGWper2!Qk8q%V@eBJog%B~2gY`{?kxw&i zzym*FvX!&<5Ow17xVHAVv@L3O1t0WjpXyk)6c{Q$-nPEh@m)c5gUu~az1_3_us-Cn zJ}?iZEa^b*QGV`}iyP6GQt*m;TXQc(>&ChRL{H=o07YT^{xg9py;GB($b>w6;xR^w z$#wK&sZE*Wp&*vDMy1NJFNEXMZ~ti;CZl?~s6LIbaJ_Q4$@D6<(BQGx-qy#`6~Zog zqzQ$Sd2X-)urMA_uv4+ebvmx71^sY`Od|zY-F%=VjhTeq0Pxe{B|O)r4m^}PCRDT(mojnhln4(dZ%EjcgD^pTl z$&W^y(7d|y4Bf@l+9+^pVn}|TD5+pEAL0m#G`hTB615=dH<4L5zgf62(eq`9C*X>d z-+VQf*fjGsE}m{9#eb2cMGMy7UlYTwbX(5~hP2S2B`J`6=~mecJ0IGGRV?XT57DR! zUJ{Bjj%_hn?jq`x{{DAP`a{DsS#nBzOQY@W1PbL8fK>da?;;*|KQpI*_+u;yVyLpX zW2zDne(Q1+_9E)ai5M431WKBJDv7ss`qlQ~>z)ZT^poI-sTZsLHl%&g@M1FB(7|-= zf$>wPecR>mp_hr z^pZr(rJ;DC%w6L*YVoDx3 zmCshF2zV#`D|XN=+SQ_#0)X@Xx-|e+mA0j!GG-(MR;fSGYv3^KM8N?oSzq*A(4%ia z>Tmw`eDymFU~JRn86j>da(~+|T4sR|7Z&dJ?pl4-@{Q2VJK-A(+{(^NWDy-$o3Cv6 zYMS+n_G|?j9_!R2H;oGGSFQ#Hxg1Tv-%ht{o48VeG)`J^GlE^4*}hPSGS!PrGy*ig+9LgIvRM1+^lAUQ+mOU zI0{A!kXw>=+$}m$_S}B^@!E`D-P_g!$0y!exT-nRFg7^KzPZ+cf>ZxpZ&GU7&WXqv zb$gq-sp`>%l}6M)aaQ~K<`pixX?=AnVTU%S?7z!LbIRrvA5lIn^^>utX@=$FEb;b0 z@TDo&UUOD{o65zO=5~4V;BSXfYkc9+%hH~=oFkRSbctKIguNk$-Js#%zSRtD&Yh1B zxvL^)dw09avX%eBp`sc)g|u1(_^te-*>qM%jvYI366ysItxchZ9_BBGW%4bht%?*L z@t#Fn7GUt>64@m?f5tMM;fpybpxRWUIvJR=HF-0%D9_ymn=lrPAkq$`L~_b~oj!3> zHC>t?YF{HX>N|ciLsZodm|Pl1sbSMZ@o3wgH6h%@8(BNgPoCUu$|2v%jy-)mKnVB8L;k#$Fq^(jJkQ-Pz%VE#%$F zs-zKg#)N2D0o-f!VR+OBLwg>ThVl9A)m5LjTr7yIvurX%R!N;*Z-dFMjNipLOL|$3Ocgftrltj?+4?dizj8KN50gFFvw<_bfu_&Z`B{#Gfll=>`> zyk+H*I%i#)(@aJ7FMZEd+pW4^Fk<|zKBt3<;mM2J4q3Ras{6gms2^gX<6R#f8tX7O~)3NC8^Wh z_rbPbN!Q=y_=!h6C_Zk1W9A)f7Iu5hWJ6C2WGD!(By6y*&Wk%SmtPZURNz;H3G zuB%Bt`BuukHhCiHzKn~Q-wCT!o1?vbo7>I)u62sNluB_!Nr zHvmpT89i~3Z=^0m5&wN|MKk?lG9X}~a}jmtvmxH#J(N!voJ-~b>`Kt60}-@Sv>Pe zK%olW&18N$Q4p_bNasAnFZ@yTsYrbsTur&jD`H23GX^u@Dq|1GEiX_>h6m-#%02W< z>&sm13`)iWQZLNdakB34rS7pYV`gS<-3ARBfU?5r@hBn)vdnSBq;TGQ@yukHE_#nmttTtOg?@~qjEniDc0^_B_fu^mXLy7Dkb0Mj z;xR+Mz;djugNlwxzllrX45XK;!lM!RmaT-|6TtKlr+f$3avobEbq{%RP7pWp>LrM{Y!+ zBXY^{4SX|@%~Cf)?avo_5zVNcOxVl{57HO2^Jh+;4Cy)As2(=kXo)!F=#{p{G?8j8 zGiJ6ZEBv4%h$sZ;q1GAZwe{%(c(OEj{mLMjH@vpe1<&^Xx8T@|#*E{iXr`)VK;2>t MbWF8tZr+Ri7v372Y5)KL diff --git a/docs/library.md b/docs/library.md index 89c4fb16b..401a9866c 100644 --- a/docs/library.md +++ b/docs/library.md @@ -32,7 +32,7 @@ For the example image below, your JSON entry will look like this: "manufacturer": "Philips", "model": "Hue motion sensor", "model_id": "9290012607", < Optional, only add it if your device shows it. - "hw_version": "Some specific hardware detail", < Optional, only add it if your device shows it. + "hw_version": "1", < Optional, only add it if your device shows it. "battery_type": "AAA", "battery_quantity": 2, < Only use if more than 1 battery "model_match_method": "startswith|endswith|contains" < Only use if you are creating a model with unique identifier (ex. trailing serial numbers) From ea2b55dd2209fa81df0c15ba7d8f152cb19817fd Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 7 Sep 2025 14:38:02 +0000 Subject: [PATCH 177/235] Increase discovery delay from 10 to 30 seconds for improved stability --- custom_components/battery_notes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index ec5e3af65..31ef00e23 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -67,7 +67,7 @@ _LOGGER = logging.getLogger(__name__) -DISCOVERY_DELAY = 10 +DISCOVERY_DELAY = 30 # seconds CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.All( From 730210d69bb27b59b935232dec1af265e4c86a3e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 7 Sep 2025 16:02:55 +0100 Subject: [PATCH 178/235] Revert "Increase discovery delay from 10 to 30 seconds for improved stability" This reverts commit ea2b55dd2209fa81df0c15ba7d8f152cb19817fd. --- custom_components/battery_notes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 31ef00e23..ec5e3af65 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -67,7 +67,7 @@ _LOGGER = logging.getLogger(__name__) -DISCOVERY_DELAY = 30 # seconds +DISCOVERY_DELAY = 10 CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.All( From b47affa8ac037a145cfdffd6237ae7c197322428 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 9 Sep 2025 13:41:57 +0000 Subject: [PATCH 179/235] Refactor device matching logic to simplify conditions and improve readability --- custom_components/battery_notes/library.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 8efe00a02..e8c54552e 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -109,6 +109,9 @@ async def get_device_battery_details( # device_to_find = ModelInfo("Aqara", "Aqara Climate Sensor W100", "8196", None) # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Battery") # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Wired") + # device_to_find = ModelInfo("Philips", "Hue dimmer switch (929002398602)", None, None) + # device_to_find = ModelInfo("Philips", "Hue dimmer switch", "929002398602", None) + # Get all devices matching manufacturer & model matching_devices = None @@ -205,14 +208,6 @@ def device_partial_match( return False if model_info.hw_version is None or model_info.model_id is None: - if ( - device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() - == str(model_info.hw_version).casefold() - and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() - == str(model_info.model_id).casefold() - ): - return True - else: if ( device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() == str(model_info.hw_version).casefold() @@ -220,6 +215,7 @@ def device_partial_match( == str(model_info.model_id).casefold() ): return True + return False def device_full_match(self, device: dict[str, Any], model_info: ModelInfo) -> bool: From bbcadec57e9101cb7cad496735d7ab92b7d0fba9 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 9 Sep 2025 15:11:49 +0000 Subject: [PATCH 180/235] Add check to ensure only one matching device is returned in get_device_battery_details --- custom_components/battery_notes/library.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index e8c54552e..1ac12a1c3 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -111,6 +111,7 @@ async def get_device_battery_details( # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Wired") # device_to_find = ModelInfo("Philips", "Hue dimmer switch (929002398602)", None, None) # device_to_find = ModelInfo("Philips", "Hue dimmer switch", "929002398602", None) + # device_to_find = ModelInfo("Philips", "Hue dimmer switch", "929002398602", "1") # Get all devices matching manufacturer & model @@ -143,6 +144,9 @@ async def get_device_battery_details( if not matching_devices: return None + if len(matching_devices) > 1: + return None + matched_device = matching_devices[0] return DeviceBatteryDetails( manufacturer=matched_device[LIBRARY_MANUFACTURER], From 529775307b7800707996b6fc88586484848da93b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 9 Sep 2025 15:44:36 +0000 Subject: [PATCH 181/235] Refactor device matching methods to use consistent parameter naming for clarity --- custom_components/battery_notes/library.py | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 1ac12a1c3..b028ec12b 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -161,47 +161,47 @@ def loaded(self) -> bool: """Library loaded successfully.""" return self._devices is not None - def device_basic_match(self, device: dict[str, Any], model_info: ModelInfo) -> bool: + def device_basic_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: """Check if device match on manufacturer and model.""" if ( str(device[LIBRARY_MANUFACTURER] or "").casefold() - != str(model_info.manufacturer or "").casefold() + != str(device_to_find.manufacturer or "").casefold() ): return False if LIBRARY_MODEL_MATCH_METHOD in device: if device[LIBRARY_MODEL_MATCH_METHOD] == "startswith": if ( - str(model_info.model or "") + str(device_to_find.model or "") .casefold() .startswith(str(device[LIBRARY_MODEL] or "").casefold()) ): return True if device[LIBRARY_MODEL_MATCH_METHOD] == "endswith": if ( - str(model_info.model or "") + str(device_to_find.model or "") .casefold() .endswith(str(device[LIBRARY_MODEL] or "").casefold()) ): return True if device[LIBRARY_MODEL_MATCH_METHOD] == "contains": - if str(model_info.model or "").casefold() in ( + if str(device_to_find.model or "").casefold() in ( str(device[LIBRARY_MODEL] or "").casefold() ): return True else: if ( str(device[LIBRARY_MODEL] or "").casefold() - == str(model_info.model or "").casefold() + == str(device_to_find.model or "").casefold() ): return True return False def device_partial_match( - self, device: dict[str, Any], model_info: ModelInfo + self, device: dict[str, Any], device_to_find: ModelInfo ) -> bool: """Check if device match on hw_version or model_id.""" - if model_info.hw_version is None and model_info.model_id is None: + if device_to_find.hw_version is None and device_to_find.model_id is None: if ( device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING) == LIBRARY_MISSING @@ -211,24 +211,24 @@ def device_partial_match( return True return False - if model_info.hw_version is None or model_info.model_id is None: + if device_to_find.hw_version is None or device_to_find.model_id is None: if ( device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() - == str(model_info.hw_version).casefold() + == str(device_to_find.hw_version).casefold() or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() - == str(model_info.model_id).casefold() + == str(device_to_find.model_id).casefold() ): return True return False - def device_full_match(self, device: dict[str, Any], model_info: ModelInfo) -> bool: + def device_full_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: """Check if device match on hw_version and model_id.""" if ( device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() - == str(model_info.hw_version).casefold() + == str(device_to_find.hw_version).casefold() and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() - == str(model_info.model_id).casefold() + == str(device_to_find.model_id).casefold() ): return True return False From c206ac64220f89ec3d8a382c0d3b04fb1f1e9c01 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 9 Sep 2025 16:04:27 +0000 Subject: [PATCH 182/235] Refactor device matching logic to use exact matching and simplify code structure --- custom_components/battery_notes/library.py | 284 +++++++++++++-------- 1 file changed, 175 insertions(+), 109 deletions(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index b028ec12b..5db88c898 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -106,7 +106,7 @@ async def get_device_battery_details( return None # Test only - # device_to_find = ModelInfo("Aqara", "Aqara Climate Sensor W100", "8196", None) + device_to_find = ModelInfo("Aqara", "Aqara Climate Sensor W100", "8196", None) # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Battery") # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Wired") # device_to_find = ModelInfo("Philips", "Hue dimmer switch (929002398602)", None, None) @@ -114,124 +114,190 @@ async def get_device_battery_details( # device_to_find = ModelInfo("Philips", "Hue dimmer switch", "929002398602", "1") - # Get all devices matching manufacturer & model - matching_devices = None - partial_matching_devices = None - fully_matching_devices = None - - matching_devices = [ - x for x in self._devices if self.device_basic_match(x, device_to_find) - ] + matched_device = self.find_exact_device_match(device_to_find) + if matched_device: + return DeviceBatteryDetails( + manufacturer=matched_device.manufacturer, + model=matched_device.model, + model_id=matched_device.model_id, + hw_version=matched_device.hw_version, + battery_type=matched_device.battery_type, + battery_quantity=matched_device.battery_quantity, + ) + return None + + # # Get all devices matching manufacturer & model + # matching_devices = None + # partial_matching_devices = None + # fully_matching_devices = None + + # matching_devices = [ + # x for x in self._devices if self.device_basic_match(x, device_to_find) + # ] + + # if matching_devices and len(matching_devices) > 1: + # partial_matching_devices = [ + # x + # for x in matching_devices + # if self.device_partial_match(x, device_to_find) + # ] + + # if partial_matching_devices and len(partial_matching_devices) > 0: + # matching_devices = partial_matching_devices + + # if matching_devices and len(matching_devices) > 1: + # fully_matching_devices = [ + # x for x in matching_devices if self.device_full_match(x, device_to_find) + # ] + + # if fully_matching_devices and len(fully_matching_devices) > 0: + # matching_devices = fully_matching_devices + + # if not matching_devices: + # return None + + # if len(matching_devices) > 1: + # return None + + # matched_device = matching_devices[0] + # return DeviceBatteryDetails( + # manufacturer=matched_device[LIBRARY_MANUFACTURER], + # model=matched_device[LIBRARY_MODEL], + # model_id=matched_device.get(LIBRARY_MODEL_ID, ""), + # hw_version=matched_device.get(LIBRARY_HW_VERSION, ""), + # battery_type=matched_device[LIBRARY_BATTERY_TYPE], + # battery_quantity=matched_device.get(LIBRARY_BATTERY_QUANTITY, 1), + # ) - if matching_devices and len(matching_devices) > 1: - partial_matching_devices = [ - x - for x in matching_devices - if self.device_partial_match(x, device_to_find) - ] + def loaded(self) -> bool: + """Library loaded successfully.""" + return self._devices is not None - if partial_matching_devices and len(partial_matching_devices) > 0: - matching_devices = partial_matching_devices + def find_exact_device_match(self, device_to_find: ModelInfo) -> DeviceBatteryDetails | None: + """Find an exact match for the given ModelInfo. - if matching_devices and len(matching_devices) > 1: - fully_matching_devices = [ - x for x in matching_devices if self.device_full_match(x, device_to_find) - ] + Manufacturer and Model are mandatory fields that must match exactly. + Model_id and hw_version are optional - if provided, they must match exactly. + Only returns a match if all mandatory and specified optional fields match. - if fully_matching_devices and len(fully_matching_devices) > 0: - matching_devices = fully_matching_devices + Args: + device_to_find: ModelInfo object with device details to match - if not matching_devices: + Returns: + DeviceBatteryDetails if exact match found, None otherwise + """ + if self._devices is None: return None - if len(matching_devices) > 1: + if not device_to_find.manufacturer or not device_to_find.model: return None - matched_device = matching_devices[0] - return DeviceBatteryDetails( - manufacturer=matched_device[LIBRARY_MANUFACTURER], - model=matched_device[LIBRARY_MODEL], - model_id=matched_device.get(LIBRARY_MODEL_ID, ""), - hw_version=matched_device.get(LIBRARY_HW_VERSION, ""), - battery_type=matched_device[LIBRARY_BATTERY_TYPE], - battery_quantity=matched_device.get(LIBRARY_BATTERY_QUANTITY, 1), - ) - - def loaded(self) -> bool: - """Library loaded successfully.""" - return self._devices is not None - - def device_basic_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: - """Check if device match on manufacturer and model.""" - if ( - str(device[LIBRARY_MANUFACTURER] or "").casefold() - != str(device_to_find.manufacturer or "").casefold() - ): - return False - - if LIBRARY_MODEL_MATCH_METHOD in device: - if device[LIBRARY_MODEL_MATCH_METHOD] == "startswith": - if ( - str(device_to_find.model or "") - .casefold() - .startswith(str(device[LIBRARY_MODEL] or "").casefold()) - ): - return True - if device[LIBRARY_MODEL_MATCH_METHOD] == "endswith": - if ( - str(device_to_find.model or "") - .casefold() - .endswith(str(device[LIBRARY_MODEL] or "").casefold()) - ): - return True - if device[LIBRARY_MODEL_MATCH_METHOD] == "contains": - if str(device_to_find.model or "").casefold() in ( - str(device[LIBRARY_MODEL] or "").casefold() - ): - return True - else: - if ( - str(device[LIBRARY_MODEL] or "").casefold() - == str(device_to_find.model or "").casefold() - ): - return True - return False - - def device_partial_match( - self, device: dict[str, Any], device_to_find: ModelInfo - ) -> bool: - """Check if device match on hw_version or model_id.""" - if device_to_find.hw_version is None and device_to_find.model_id is None: - if ( - device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING) - == LIBRARY_MISSING - and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING) - == LIBRARY_MISSING - ): - return True - return False - - if device_to_find.hw_version is None or device_to_find.model_id is None: - if ( - device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() - == str(device_to_find.hw_version).casefold() - or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() - == str(device_to_find.model_id).casefold() - ): - return True - - return False + for device in self._devices: + # Check mandatory fields (case-insensitive) + if (str(device.get(LIBRARY_MANUFACTURER, "")).casefold() != + str(device_to_find.manufacturer).casefold()): + continue + + if (str(device.get(LIBRARY_MODEL, "")).casefold() != + str(device_to_find.model).casefold()): + continue + + # Check optional fields - if provided in device_to_find, they must match + if device_to_find.model_id is not None: + device_model_id = device.get(LIBRARY_MODEL_ID, "") + if (str(device_model_id).casefold() != + str(device_to_find.model_id).casefold()): + continue + + if device_to_find.hw_version is not None: + device_hw_version = device.get(LIBRARY_HW_VERSION, "") + if (str(device_hw_version).casefold() != + str(device_to_find.hw_version).casefold()): + continue + + # All mandatory and specified optional fields match + return DeviceBatteryDetails( + manufacturer=device[LIBRARY_MANUFACTURER], + model=device[LIBRARY_MODEL], + model_id=device.get(LIBRARY_MODEL_ID, ""), + hw_version=device.get(LIBRARY_HW_VERSION, ""), + battery_type=device[LIBRARY_BATTERY_TYPE], + battery_quantity=device.get(LIBRARY_BATTERY_QUANTITY, 1), + ) - def device_full_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: - """Check if device match on hw_version and model_id.""" - if ( - device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() - == str(device_to_find.hw_version).casefold() - and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() - == str(device_to_find.model_id).casefold() - ): - return True - return False + return None + + # def device_basic_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: + # """Check if device match on manufacturer and model.""" + # if ( + # str(device[LIBRARY_MANUFACTURER] or "").casefold() + # != str(device_to_find.manufacturer or "").casefold() + # ): + # return False + + # if LIBRARY_MODEL_MATCH_METHOD in device: + # if device[LIBRARY_MODEL_MATCH_METHOD] == "startswith": + # if ( + # str(device_to_find.model or "") + # .casefold() + # .startswith(str(device[LIBRARY_MODEL] or "").casefold()) + # ): + # return True + # if device[LIBRARY_MODEL_MATCH_METHOD] == "endswith": + # if ( + # str(device_to_find.model or "") + # .casefold() + # .endswith(str(device[LIBRARY_MODEL] or "").casefold()) + # ): + # return True + # if device[LIBRARY_MODEL_MATCH_METHOD] == "contains": + # if str(device_to_find.model or "").casefold() in ( + # str(device[LIBRARY_MODEL] or "").casefold() + # ): + # return True + # else: + # if ( + # str(device[LIBRARY_MODEL] or "").casefold() + # == str(device_to_find.model or "").casefold() + # ): + # return True + # return False + + # def device_partial_match( + # self, device: dict[str, Any], device_to_find: ModelInfo + # ) -> bool: + # """Check if device match on hw_version or model_id.""" + # if device_to_find.hw_version is None and device_to_find.model_id is None: + # if ( + # device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING) + # == LIBRARY_MISSING + # and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING) + # == LIBRARY_MISSING + # ): + # return True + # return False + + # if device_to_find.hw_version is None or device_to_find.model_id is None: + # if ( + # device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() + # == str(device_to_find.hw_version).casefold() + # or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + # == str(device_to_find.model_id).casefold() + # ): + # return True + + # return False + + # def device_full_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: + # """Check if device match on hw_version and model_id.""" + # if ( + # device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() + # == str(device_to_find.hw_version).casefold() + # and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + # == str(device_to_find.model_id).casefold() + # ): + # return True + # return False class DeviceBatteryDetails(NamedTuple): From 6d41e392fec8ccf3d56e34bada1c596b76b924ec Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 9 Sep 2025 16:11:58 +0000 Subject: [PATCH 183/235] Add type check for devices in Library to ensure they are dictionaries --- custom_components/battery_notes/library.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 5db88c898..cd17bf920 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -193,6 +193,10 @@ def find_exact_device_match(self, device_to_find: ModelInfo) -> DeviceBatteryDet return None for device in self._devices: + # Ensure device is a dictionary + if not isinstance(device, dict): + continue + # Check mandatory fields (case-insensitive) if (str(device.get(LIBRARY_MANUFACTURER, "")).casefold() != str(device_to_find.manufacturer).casefold()): From f9ed54413337465bc26ecbba6d1e385685911ac0 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 10 Sep 2025 08:31:11 +0100 Subject: [PATCH 184/235] Revert "Add type check for devices in Library to ensure they are dictionaries" This reverts commit 6d41e392fec8ccf3d56e34bada1c596b76b924ec. --- custom_components/battery_notes/library.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index cd17bf920..5db88c898 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -193,10 +193,6 @@ def find_exact_device_match(self, device_to_find: ModelInfo) -> DeviceBatteryDet return None for device in self._devices: - # Ensure device is a dictionary - if not isinstance(device, dict): - continue - # Check mandatory fields (case-insensitive) if (str(device.get(LIBRARY_MANUFACTURER, "")).casefold() != str(device_to_find.manufacturer).casefold()): From 4245ef4d6ff2d72e7ba7e81bb6a2d59c45766978 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 10 Sep 2025 08:31:19 +0100 Subject: [PATCH 185/235] Revert "Refactor device matching logic to use exact matching and simplify code structure" This reverts commit c206ac64220f89ec3d8a382c0d3b04fb1f1e9c01. --- custom_components/battery_notes/library.py | 284 ++++++++------------- 1 file changed, 109 insertions(+), 175 deletions(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 5db88c898..b028ec12b 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -106,7 +106,7 @@ async def get_device_battery_details( return None # Test only - device_to_find = ModelInfo("Aqara", "Aqara Climate Sensor W100", "8196", None) + # device_to_find = ModelInfo("Aqara", "Aqara Climate Sensor W100", "8196", None) # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Battery") # device_to_find = ModelInfo("Google", "Topaz-2.7", None, "Wired") # device_to_find = ModelInfo("Philips", "Hue dimmer switch (929002398602)", None, None) @@ -114,190 +114,124 @@ async def get_device_battery_details( # device_to_find = ModelInfo("Philips", "Hue dimmer switch", "929002398602", "1") - matched_device = self.find_exact_device_match(device_to_find) - if matched_device: - return DeviceBatteryDetails( - manufacturer=matched_device.manufacturer, - model=matched_device.model, - model_id=matched_device.model_id, - hw_version=matched_device.hw_version, - battery_type=matched_device.battery_type, - battery_quantity=matched_device.battery_quantity, - ) - return None - - # # Get all devices matching manufacturer & model - # matching_devices = None - # partial_matching_devices = None - # fully_matching_devices = None - - # matching_devices = [ - # x for x in self._devices if self.device_basic_match(x, device_to_find) - # ] - - # if matching_devices and len(matching_devices) > 1: - # partial_matching_devices = [ - # x - # for x in matching_devices - # if self.device_partial_match(x, device_to_find) - # ] - - # if partial_matching_devices and len(partial_matching_devices) > 0: - # matching_devices = partial_matching_devices - - # if matching_devices and len(matching_devices) > 1: - # fully_matching_devices = [ - # x for x in matching_devices if self.device_full_match(x, device_to_find) - # ] - - # if fully_matching_devices and len(fully_matching_devices) > 0: - # matching_devices = fully_matching_devices - - # if not matching_devices: - # return None - - # if len(matching_devices) > 1: - # return None - - # matched_device = matching_devices[0] - # return DeviceBatteryDetails( - # manufacturer=matched_device[LIBRARY_MANUFACTURER], - # model=matched_device[LIBRARY_MODEL], - # model_id=matched_device.get(LIBRARY_MODEL_ID, ""), - # hw_version=matched_device.get(LIBRARY_HW_VERSION, ""), - # battery_type=matched_device[LIBRARY_BATTERY_TYPE], - # battery_quantity=matched_device.get(LIBRARY_BATTERY_QUANTITY, 1), - # ) + # Get all devices matching manufacturer & model + matching_devices = None + partial_matching_devices = None + fully_matching_devices = None - def loaded(self) -> bool: - """Library loaded successfully.""" - return self._devices is not None + matching_devices = [ + x for x in self._devices if self.device_basic_match(x, device_to_find) + ] - def find_exact_device_match(self, device_to_find: ModelInfo) -> DeviceBatteryDetails | None: - """Find an exact match for the given ModelInfo. + if matching_devices and len(matching_devices) > 1: + partial_matching_devices = [ + x + for x in matching_devices + if self.device_partial_match(x, device_to_find) + ] - Manufacturer and Model are mandatory fields that must match exactly. - Model_id and hw_version are optional - if provided, they must match exactly. - Only returns a match if all mandatory and specified optional fields match. + if partial_matching_devices and len(partial_matching_devices) > 0: + matching_devices = partial_matching_devices - Args: - device_to_find: ModelInfo object with device details to match + if matching_devices and len(matching_devices) > 1: + fully_matching_devices = [ + x for x in matching_devices if self.device_full_match(x, device_to_find) + ] - Returns: - DeviceBatteryDetails if exact match found, None otherwise - """ - if self._devices is None: + if fully_matching_devices and len(fully_matching_devices) > 0: + matching_devices = fully_matching_devices + + if not matching_devices: return None - if not device_to_find.manufacturer or not device_to_find.model: + if len(matching_devices) > 1: return None - for device in self._devices: - # Check mandatory fields (case-insensitive) - if (str(device.get(LIBRARY_MANUFACTURER, "")).casefold() != - str(device_to_find.manufacturer).casefold()): - continue - - if (str(device.get(LIBRARY_MODEL, "")).casefold() != - str(device_to_find.model).casefold()): - continue - - # Check optional fields - if provided in device_to_find, they must match - if device_to_find.model_id is not None: - device_model_id = device.get(LIBRARY_MODEL_ID, "") - if (str(device_model_id).casefold() != - str(device_to_find.model_id).casefold()): - continue - - if device_to_find.hw_version is not None: - device_hw_version = device.get(LIBRARY_HW_VERSION, "") - if (str(device_hw_version).casefold() != - str(device_to_find.hw_version).casefold()): - continue - - # All mandatory and specified optional fields match - return DeviceBatteryDetails( - manufacturer=device[LIBRARY_MANUFACTURER], - model=device[LIBRARY_MODEL], - model_id=device.get(LIBRARY_MODEL_ID, ""), - hw_version=device.get(LIBRARY_HW_VERSION, ""), - battery_type=device[LIBRARY_BATTERY_TYPE], - battery_quantity=device.get(LIBRARY_BATTERY_QUANTITY, 1), - ) + matched_device = matching_devices[0] + return DeviceBatteryDetails( + manufacturer=matched_device[LIBRARY_MANUFACTURER], + model=matched_device[LIBRARY_MODEL], + model_id=matched_device.get(LIBRARY_MODEL_ID, ""), + hw_version=matched_device.get(LIBRARY_HW_VERSION, ""), + battery_type=matched_device[LIBRARY_BATTERY_TYPE], + battery_quantity=matched_device.get(LIBRARY_BATTERY_QUANTITY, 1), + ) - return None - - # def device_basic_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: - # """Check if device match on manufacturer and model.""" - # if ( - # str(device[LIBRARY_MANUFACTURER] or "").casefold() - # != str(device_to_find.manufacturer or "").casefold() - # ): - # return False - - # if LIBRARY_MODEL_MATCH_METHOD in device: - # if device[LIBRARY_MODEL_MATCH_METHOD] == "startswith": - # if ( - # str(device_to_find.model or "") - # .casefold() - # .startswith(str(device[LIBRARY_MODEL] or "").casefold()) - # ): - # return True - # if device[LIBRARY_MODEL_MATCH_METHOD] == "endswith": - # if ( - # str(device_to_find.model or "") - # .casefold() - # .endswith(str(device[LIBRARY_MODEL] or "").casefold()) - # ): - # return True - # if device[LIBRARY_MODEL_MATCH_METHOD] == "contains": - # if str(device_to_find.model or "").casefold() in ( - # str(device[LIBRARY_MODEL] or "").casefold() - # ): - # return True - # else: - # if ( - # str(device[LIBRARY_MODEL] or "").casefold() - # == str(device_to_find.model or "").casefold() - # ): - # return True - # return False - - # def device_partial_match( - # self, device: dict[str, Any], device_to_find: ModelInfo - # ) -> bool: - # """Check if device match on hw_version or model_id.""" - # if device_to_find.hw_version is None and device_to_find.model_id is None: - # if ( - # device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING) - # == LIBRARY_MISSING - # and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING) - # == LIBRARY_MISSING - # ): - # return True - # return False - - # if device_to_find.hw_version is None or device_to_find.model_id is None: - # if ( - # device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() - # == str(device_to_find.hw_version).casefold() - # or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() - # == str(device_to_find.model_id).casefold() - # ): - # return True - - # return False - - # def device_full_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: - # """Check if device match on hw_version and model_id.""" - # if ( - # device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() - # == str(device_to_find.hw_version).casefold() - # and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() - # == str(device_to_find.model_id).casefold() - # ): - # return True - # return False + def loaded(self) -> bool: + """Library loaded successfully.""" + return self._devices is not None + + def device_basic_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: + """Check if device match on manufacturer and model.""" + if ( + str(device[LIBRARY_MANUFACTURER] or "").casefold() + != str(device_to_find.manufacturer or "").casefold() + ): + return False + + if LIBRARY_MODEL_MATCH_METHOD in device: + if device[LIBRARY_MODEL_MATCH_METHOD] == "startswith": + if ( + str(device_to_find.model or "") + .casefold() + .startswith(str(device[LIBRARY_MODEL] or "").casefold()) + ): + return True + if device[LIBRARY_MODEL_MATCH_METHOD] == "endswith": + if ( + str(device_to_find.model or "") + .casefold() + .endswith(str(device[LIBRARY_MODEL] or "").casefold()) + ): + return True + if device[LIBRARY_MODEL_MATCH_METHOD] == "contains": + if str(device_to_find.model or "").casefold() in ( + str(device[LIBRARY_MODEL] or "").casefold() + ): + return True + else: + if ( + str(device[LIBRARY_MODEL] or "").casefold() + == str(device_to_find.model or "").casefold() + ): + return True + return False + + def device_partial_match( + self, device: dict[str, Any], device_to_find: ModelInfo + ) -> bool: + """Check if device match on hw_version or model_id.""" + if device_to_find.hw_version is None and device_to_find.model_id is None: + if ( + device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING) + == LIBRARY_MISSING + and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING) + == LIBRARY_MISSING + ): + return True + return False + + if device_to_find.hw_version is None or device_to_find.model_id is None: + if ( + device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() + == str(device_to_find.hw_version).casefold() + or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + == str(device_to_find.model_id).casefold() + ): + return True + + return False + + def device_full_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: + """Check if device match on hw_version and model_id.""" + if ( + device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() + == str(device_to_find.hw_version).casefold() + and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + == str(device_to_find.model_id).casefold() + ): + return True + return False class DeviceBatteryDetails(NamedTuple): From 664553a296c27266d7193e720a508a9dc27f0938 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 10 Sep 2025 07:39:51 +0000 Subject: [PATCH 186/235] Update Portuguese translations for battery notes integration --- .../battery_notes/translations/pt-BR.json | 170 +++++++++--------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/custom_components/battery_notes/translations/pt-BR.json b/custom_components/battery_notes/translations/pt-BR.json index 9fccf4695..6653dad9f 100644 --- a/custom_components/battery_notes/translations/pt-BR.json +++ b/custom_components/battery_notes/translations/pt-BR.json @@ -6,18 +6,18 @@ "title": "Setup Battery Notes" }, "battery": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "description": "Fabricante: {manufacturer}\nModelo: {model}\nModelo ID: {model_id}\nVersão de hardware: {hw_version}", "data": { - "battery_type": "Battery type", - "battery_quantity": "Battery quantity", - "battery_low_threshold": "Battery low threshold", - "battery_low_template": "Battery low template", - "filter_outliers": "Filter outliers" + "battery_type": "Tipo de bateria", + "battery_quantity": "Quantidade de baterias", + "battery_low_threshold": "Limite de bateria fraca", + "battery_low_template": "Modelo de bateria fraca", + "filter_outliers": "Filtrar atípicos" }, "data_description": { - "battery_low_threshold": "0 will use the global default threshold", - "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + "battery_low_threshold": "0 irá usar o limite padrão global", + "battery_low_template": "Modelo para determinar se a bateria está fraca, deve retornar verdadeiro se estiver fraca\nNecessário apenas para níveis de bateria fora do padrão", + "filter_outliers": "Filtre grandes quedas no nível da bateria, reduzindo eventos de disparo falso em dispositivos que ocasionalmente relatam níveis incorretos." } } }, @@ -26,7 +26,7 @@ "created_sub_entry": "Battery Note created successfully" }, "error": { - "unknown": "Unknown error occurred." + "unknown": "Ocorreu um erro desconhecido." } }, "config_subentries": { @@ -37,52 +37,52 @@ "entry_type": "Battery note", "step": { "user": { - "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Se você precisar de ajuda com a configuração dê uma olhada aqui: https://andrew-codechimp.github.io/HA-Battery-Notes/", "data": { - "association_type": "Association type" + "association_type": "Tipos de Associação" }, "menu_options": { - "device": "Device (recommended)", - "entity": "Entity" + "device": "Dispositivo (recomendado)", + "entity": "Entidade" }, - "title": "Choose your association type" + "title": "Escolha o seu tipo de Associação" }, "device": { "data": { - "device_id": "Device", - "name": "Name" + "device_id": "Dispositivo", + "name": "Nome" }, "data_description": { - "name": "Leaving blank will take the name from the source device" + "name": "Deixar em branco utilizará o nome do dispositivo de origem" } }, "entity": { "data": { - "source_entity_id": "Entity", - "name": "Name" + "source_entity_id": "Entidade", + "name": "Nome" }, "data_description": { - "name": "Leaving blank will take the name from the source entity" + "name": "Deixar em branco levará o nome da entidade de origem" } }, "battery": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "description": "Fabricante: {manufacturer}\nModelo: {model}\nModelo ID: {model_id}\nVersão de hardware: {hw_version}", "data": { - "battery_type": "Battery type", - "battery_quantity": "Battery quantity", - "battery_low_threshold": "Battery low threshold", - "battery_low_template": "Battery low template", - "filter_outliers": "Filter outliers" + "battery_type": "Tipo de bateria", + "battery_quantity": "Quantidade de baterias", + "battery_low_threshold": "Limite de bateria fraca", + "battery_low_template": "Modelo de bateria fraca", + "filter_outliers": "Filtrar atípicos" }, "data_description": { - "battery_low_threshold": "0 will use the global default threshold", - "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + "battery_low_threshold": "0 irá usar o limite padrão global", + "battery_low_template": "Modelo para determinar se a bateria está fraca, deve retornar verdadeiro se estiver fraca\nNecessário apenas para níveis de bateria fora do padrão", + "filter_outliers": "Filtre grandes quedas no nível da bateria, reduzindo eventos de disparo falso em dispositivos que ocasionalmente relatam níveis incorretos." } }, "manual": { - "description": "This device is marked in the library as manual, variants use different battery types so it cannot be set in the library.\nThe next step will allow you to set your battery type but please do not submit a device request.", - "title": "Device manual configuration" + "description": "Esse dispositivo está marcado na biblioteca como manual, variantes usam diferentes tipos de bateria, então o dispositivo não pode ser definido na biblioteca.\nO próximo passo permitirá que você defina o tipo de bateria, mas por favor, não envie uma solicitação de dispositivo.", + "title": "Configuração manual do dispositivo" }, "reconfigure": { "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", @@ -104,12 +104,12 @@ }, "abort": { "reconfigure_successful": "Re-configuration was successful", - "already_configured": "Device is already configured" + "already_configured": "O dispositivo já está configurado" }, "error": { - "unknown": "Unknown error occurred.", - "unconfigurable_entity": "It is not possible to add this entity to Battery Notes.", - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note." + "unknown": "Ocorreu um erro desconhecido.", + "unconfigurable_entity": "Não é possível adicionar esta entidade ao Battery Notes.", + "orphaned_battery_note": "O dispositivo ou entidade associados não existe mais para o Battery Notes." } } }, @@ -154,141 +154,141 @@ "battery_note_options": { "step": { "init": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", + "description": "Fabricante: {manufacturer}\nModelo: {model}\nModelo ID: {model_id}\nVersão de hardware: {hw_version}", "data": { - "name": "Name", - "battery_type": "Battery type", - "battery_quantity": "Battery quantity", - "battery_low_threshold": "Battery low threshold", - "battery_low_template": "Battery low template", - "filter_outliers": "Filter outliers" + "name": "Nome", + "battery_type": "Tipo de bateria", + "battery_quantity": "Quantidade de baterias", + "battery_low_threshold": "Limite de bateria fraca", + "battery_low_template": "Modelo de bateria fraca", + "filter_outliers": "Filtros atípicos" }, "data_description": { - "name": "Leaving blank will take the name from the source device", - "battery_low_threshold": "0 will use the global default threshold", - "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" + "name": "Deixar em branco utilizará o nome do dispositivo de origem", + "battery_low_threshold": "0 irá usar o limite padrão global", + "battery_low_template": "Modelo para determinar se a bateria está fraca, deve retornar verdadeiro se estiver fraca\nNecessário apenas para níveis de bateria fora do padrão", + "filter_outliers": "Filtre grandes quedas no nível da bateria, reduzindo eventos de disparo falso em dispositivos que ocasionalmente relatam níveis incorretos." } } }, "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Unknown error occurred." + "orphaned_battery_note": "O dispositivo ou entidade associados não existe mais para o Battery Notes.", + "unknown": "Ocorreu um erro desconhecido." } }, "entity": { "binary_sensor": { "battery_low": { - "name": "{device_name}Battery low", + "name": "{device_name}Bateria fraca", "state_attributes": { "battery_low_threshold": { - "name": "Battery low threshold" + "name": "Limite de bateria fraca" } } } }, "button": { "battery_replaced": { - "name": "{device_name}Battery replaced" + "name": "{device_name}Bateria substituída" } }, "sensor": { "battery_plus": { - "name": "{device_name}Battery+", + "name": "{device_name}Bateria+", "state_attributes": { "battery_type": { - "name": "Battery type" + "name": "Tipo de bateria" }, "battery_quantity": { - "name": "Battery quantity" + "name": "Quantidade de baterias" }, "battery_type_and_quantity": { - "name": "Battery type and quantity" + "name": "Tipo e quantidade de baterias" }, "battery_last_replaced": { - "name": "Battery last replaced" + "name": "Última substituição da bateria" }, "battery_low": { - "name": "Battery low" + "name": "Bateria fraca" }, "battery_low_threshold": { - "name": "Battery low threshold" + "name": "Limite de Bateria fraca" }, "battery_last_reported": { - "name": "Battery last reported" + "name": "Última bateria relatada" }, "battery_last_reported_level": { - "name": "Battery last reported level" + "name": "Último nível reportado pela bateria" }, "source_entity_id": { - "name": "Source Entity Id" + "name": "ID da Entidade Fonte" }, "device_id": { - "name": "Device Id" + "name": "ID do dispositivo" }, "device_name": { - "name": "Device name" + "name": "Nome do dispositivo" } } }, "battery_type": { - "name": "{device_name}Battery type", + "name": "{device_name}Tipo de bateria ", "state_attributes": { "battery_type": { - "name": "Battery type" + "name": "Tipo de bateria" }, "battery_quantity": { - "name": "Battery quantity" + "name": "Quantidade de baterias" } } }, "battery_last_replaced": { - "name": "{device_name}Battery last replaced" + "name": "{device_name}Bateria substituída pela última vez" } } }, "services": { "set_battery_replaced": { - "description": "Set the battery last replaced.", + "description": "Definir a última substituição da bateria.", "fields": { "device_id": { - "description": "Device that has had its battery replaced.", - "name": "Device" + "description": "Dispositivo que teve sua bateria substituída.", + "name": "Dispositivo" }, "entity_id": { - "description": "Entity that has had its battery replaced (only used for entity associated battery notes).", - "name": "Entity" + "description": "Entidade que teve sua bateria substituída (usada apenas para notas de bateria associadas à entidade).", + "name": "Entidade" }, "datetime_replaced": { - "description": "Date replaced.", - "name": "Date" + "description": "Data de substituição.", + "name": "Data" } }, - "name": "Set battery replaced" + "name": "Definir a bateria como substituída" }, "check_battery_last_reported": { - "description": "Raise events for devices that haven't reported their battery level.", + "description": "Crie eventos para dispositivos que não relataram o nível da bateria deles.", "fields": { "days_last_reported": { - "description": "Number of days since a device last reported its battery level.", - "name": "Days" + "description": "Número de dias desde a última vez que um dispositivo relatou o nível da bateria.", + "name": "Dias" } }, - "name": "Check battery last reported" + "name": "Verificar a última atualização da bateria" }, "check_battery_low": { - "description": "Raise events for devices that have a low battery.", - "name": "Check battery low" + "description": "Crie eventos para dispositivos com bateria fraca.", + "name": "Verificar bateria fraca" } }, "issues": { "missing_device": { - "title": "Orphaned Battery Note", + "title": "Battery Note obsoleto", "fix_flow": { "step": { "confirm": { - "title": "Orphaned Battery Note", - "description": "The associated device or entity no longer exists for the Battery Note entry {name}, the Battery Note should be deleted.\nSelect **Submit** to delete this Battery Note." + "title": "Battery Note obsoleto", + "description": "O dispositivo ou entidade associados não existe mais para a entrada {name} do Battery Notes e deve ser apagada.\nSelecione **Enviar** para excluir esta nota de bateria." } } } From c93139683585ba9ddb185240a6d52394b6d039a0 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 10 Sep 2025 07:47:48 +0000 Subject: [PATCH 187/235] Add type check for matched device in get_device_battery_details method --- custom_components/battery_notes/library.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index b028ec12b..3e64739b0 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -148,6 +148,10 @@ async def get_device_battery_details( return None matched_device = matching_devices[0] + + if not isinstance(matched_device, dict): + return None + return DeviceBatteryDetails( manufacturer=matched_device[LIBRARY_MANUFACTURER], model=matched_device[LIBRARY_MODEL], From b7012331ca36a82b978dc9b31b0ba9d6e9200e3e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 10 Sep 2025 09:32:50 +0000 Subject: [PATCH 188/235] Add some basic AI tests --- pyproject.toml | 14 + requirements_dev.txt | 2 + requirements_test.txt | 1 + scripts/setup | 2 +- scripts/test | 15 + tests/README.md | 20 ++ tests/__init__.py | 1 + tests/conftest.py | 114 +++++++ tests/test_config_flow.py | 671 ++++++++++++++++++++++++++++++++++++++ tests/test_init.py | 252 ++++++++++++++ 10 files changed, 1091 insertions(+), 1 deletion(-) create mode 100644 requirements_dev.txt create mode 100644 requirements_test.txt create mode 100755 scripts/test create mode 100644 tests/README.md create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_config_flow.py create mode 100644 tests/test_init.py diff --git a/pyproject.toml b/pyproject.toml index 209a2a07f..20a70f5be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,3 +129,17 @@ ignore_missing_imports = true [tool.ruff.lint.mccabe] max-complexity = 25 + +[tool.pytest.ini_options] +minversion = "6.0" +addopts = ["--strict-markers", "--tb=short", "-v"] +testpaths = ["tests"] +python_files = ["test_*.py"] +python_classes = ["Test*"] +python_functions = ["test_*"] +markers = ["asyncio: mark test as asyncio"] +asyncio_mode = "auto" +filterwarnings = [ + "ignore::DeprecationWarning", + "ignore::PendingDeprecationWarning", +] diff --git a/requirements_dev.txt b/requirements_dev.txt new file mode 100644 index 000000000..40cfa9102 --- /dev/null +++ b/requirements_dev.txt @@ -0,0 +1,2 @@ +pre-commit +mypy \ No newline at end of file diff --git a/requirements_test.txt b/requirements_test.txt new file mode 100644 index 000000000..71f59992c --- /dev/null +++ b/requirements_test.txt @@ -0,0 +1 @@ +pytest-homeassistant-custom-component diff --git a/scripts/setup b/scripts/setup index 141d19f9d..c18e08450 100755 --- a/scripts/setup +++ b/scripts/setup @@ -4,4 +4,4 @@ set -e cd "$(dirname "$0")/.." -python3 -m pip install --requirement requirements.txt +python3 -m pip install -r requirements.txt -r requirements_dev.txt -r requirements_test.txt diff --git a/scripts/test b/scripts/test new file mode 100755 index 000000000..b4823c229 --- /dev/null +++ b/scripts/test @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -e + +# Change to project root directory +cd "$(dirname "$0")/.." + +# Run pytest with configuration +echo "Running tests..." +python -m pytest tests/ \ + -v \ + --tb=short \ + --strict-markers + +echo "Tests completed with exit code: $?" diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 000000000..fcddba1f2 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,20 @@ +# Battery Notes Test Framework + +## Running Tests + +```bash +# Run all tests using the test script +./scripts/test + +# Or run tests directly with pytest +python -m pytest tests/ -v + +# Run specific test file +python -m pytest tests/test_init.py -v + +# Run specific test +python -m pytest tests/test_init.py::TestBatteryNotesInit::test_async_setup_success -v + +# Run with coverage +pytest --cov-report term-missing --cov=custom_components.battery_notes tests +``` diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..8475f8162 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for battery_notes integration.""" diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..fedb2bbf8 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,114 @@ +"""Test configuration for battery_notes tests.""" + +from unittest.mock import AsyncMock, MagicMock + +import pytest +from homeassistant.config_entries import ConfigEntry, ConfigSubentry +from homeassistant.const import CONF_DEVICE_ID +from homeassistant.core import HomeAssistant + +from custom_components.battery_notes.const import ( + CONF_ADVANCED_SETTINGS, + CONF_BATTERY_INCREASE_THRESHOLD, + CONF_BATTERY_QUANTITY, + CONF_BATTERY_TYPE, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_ENABLE_AUTODISCOVERY, + CONF_ENABLE_REPLACED, + CONF_HIDE_BATTERY, + CONF_ROUND_BATTERY, + CONF_SHOW_ALL_DEVICES, + CONF_USER_LIBRARY, + DEFAULT_BATTERY_INCREASE_THRESHOLD, + DEFAULT_BATTERY_LOW_THRESHOLD, + DOMAIN, + SUBENTRY_BATTERY_NOTE, +) +from custom_components.battery_notes.coordinator import BatteryNotesDomainConfig + + +@pytest.fixture +def mock_config_entry(): + """Return a mock config entry.""" + config_entry = MagicMock(spec=ConfigEntry) + config_entry.version = 1 + config_entry.minor_version = 1 + config_entry.domain = DOMAIN + config_entry.title = "Battery Notes Test" + config_entry.data = {} + config_entry.options = { + CONF_SHOW_ALL_DEVICES: False, + CONF_HIDE_BATTERY: False, + CONF_ROUND_BATTERY: False, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, + CONF_ADVANCED_SETTINGS: { + CONF_ENABLE_AUTODISCOVERY: True, + CONF_ENABLE_REPLACED: True, + CONF_USER_LIBRARY: "", + }, + } + config_entry.source = "user" + config_entry.entry_id = "test_entry_id" + config_entry.unique_id = "test_unique_id" + config_entry.discovery_keys = set() + config_entry.subentries_data = {} + # Add subentries property as an empty dict by default + config_entry.subentries = {} + return config_entry + +@pytest.fixture +def mock_battery_subentry(): + """Return a mock battery subentry.""" + return ConfigSubentry( + subentry_type=SUBENTRY_BATTERY_NOTE, + subentry_id="test_subentry_id", + title="Test Battery Device", + data={ + CONF_DEVICE_ID: "test_device_id", + CONF_BATTERY_TYPE: "AA", + CONF_BATTERY_QUANTITY: 2, + }, + unique_id="test_subentry_unique_id", + ) + + +@pytest.fixture +def mock_hass(): + """Return a mock Home Assistant instance.""" + hass = MagicMock(spec=HomeAssistant) + hass.data = {} + + # Mock config + mock_config = MagicMock() + mock_config.config_dir = "/tmp/config" + hass.config = mock_config + + # Mock config_entries + hass.config_entries = MagicMock() + hass.config_entries.async_forward_entry_setups = AsyncMock() + + return hass + + +@pytest.fixture +def mock_store(): + """Return a mock store.""" + store = MagicMock() + store.async_load = AsyncMock(return_value={}) + return store + + +@pytest.fixture +def mock_domain_config(): + """Return a mock domain config.""" + return BatteryNotesDomainConfig( + enable_autodiscovery=True, + show_all_devices=False, + enable_replaced=True, + hide_battery=False, + round_battery=False, + default_battery_low_threshold=DEFAULT_BATTERY_LOW_THRESHOLD, + battery_increased_threshod=DEFAULT_BATTERY_INCREASE_THRESHOLD, + user_library="", + ) diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py new file mode 100644 index 000000000..af5aeb840 --- /dev/null +++ b/tests/test_config_flow.py @@ -0,0 +1,671 @@ +"""Test battery_notes config flow.""" + +from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch + +import pytest +from homeassistant.const import CONF_DEVICE_ID +from homeassistant.core import HomeAssistant +from homeassistant.data_entry_flow import FlowResultType + +from custom_components.battery_notes import config_flow +from custom_components.battery_notes.const import ( + CONF_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_QUANTITY, + CONF_BATTERY_TYPE, + CONF_DEVICE_NAME, + CONF_FILTER_OUTLIERS, + CONF_HW_VERSION, + CONF_MANUFACTURER, + CONF_MODEL, + CONF_MODEL_ID, + CONF_SOURCE_ENTITY_ID, + SUBENTRY_BATTERY_NOTE, +) +from custom_components.battery_notes.const import NAME as INTEGRATION_NAME +from custom_components.battery_notes.coordinator import MY_KEY, BatteryNotesDomainConfig +from custom_components.battery_notes.library import DeviceBatteryDetails + + +class TestBatteryNotesConfigFlow: + """Test class for battery_notes config flow.""" + + @pytest.fixture + def mock_hass(self): + """Return a mock Home Assistant instance.""" + hass = MagicMock(spec=HomeAssistant) + hass.data = {MY_KEY: BatteryNotesDomainConfig()} + + # Add config mock + config_mock = MagicMock() + config_mock.config_dir = "/test/config" + hass.config = config_mock + + # Add config_entries mock + hass.config_entries = MagicMock() + hass.config_entries.async_entries.return_value = [] + return hass + + @pytest.fixture + def mock_device_registry(self): + """Return mock device registry.""" + mock_registry = MagicMock() + mock_device = MagicMock() + mock_device.manufacturer = "Test Manufacturer" + mock_device.model = "Test Model" + mock_device.hw_version = "1.0" + mock_device.model_id = "TEST123" + mock_registry.async_get.return_value = mock_device + return mock_registry + + @pytest.fixture + def mock_entity_registry(self): + """Return mock entity registry.""" + mock_registry = MagicMock() + mock_entity = MagicMock() + mock_entity.device_id = "test_device_id" + mock_entity.entity_id = "sensor.test_battery" + mock_registry.async_get.return_value = mock_entity + return mock_registry + + @pytest.fixture + def mock_library(self): + """Return mock library.""" + mock_lib = MagicMock() + mock_lib.load_libraries = AsyncMock() + mock_lib.get_device_battery_details = AsyncMock() + return mock_lib + + @pytest.fixture + def mock_library_updater(self): + """Return mock library updater.""" + mock_updater = MagicMock() + mock_updater.time_to_update_library = AsyncMock(return_value=False) + mock_updater.get_library_updates = AsyncMock() + return mock_updater + + @pytest.mark.asyncio + async def test_config_flow_user_step_success(self, mock_hass): + """Test successful user step flow.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + + # Initialize context for flow handler + flow.context = {} + + # Test initial form + result = await flow.async_step_user() + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "user" + + # Test successful submission + result = await flow.async_step_user(user_input={}) + assert result["type"] == FlowResultType.CREATE_ENTRY + assert result["title"] == INTEGRATION_NAME + + @pytest.mark.asyncio + async def test_config_flow_user_step_already_configured(self, mock_hass): + """Test user step when already configured.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + + # Mock existing entry through hass.config_entries + existing_entry = MagicMock() + existing_entry.domain = "battery_notes" + mock_hass.config_entries.async_entries.return_value = [existing_entry] + + result = await flow.async_step_user() + assert result["type"] == FlowResultType.ABORT + assert result["reason"] == "already_configured" + + @pytest.mark.asyncio + async def test_config_flow_integration_discovery_new_entry(self, mock_hass): + """Test integration discovery with new config entry.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + + # Initialize context for flow handler + flow.context = {} + + # Mock the async_get_integration_entry method to return None first, then a config entry + created_entry = MagicMock() + created_entry.subentries = {} + flow.async_get_integration_entry = AsyncMock(side_effect=[None, created_entry]) + + # Mock create_entry to return a proper result + flow.async_create_entry = MagicMock(return_value={"type": "create_entry", "title": "Test"}) + flow.async_step_device = AsyncMock() + + discovery_info = { + CONF_DEVICE_ID: "test_device_id", + CONF_DEVICE_NAME: "Test Device", + CONF_MANUFACTURER: "Test Manufacturer", + CONF_MODEL: "Test Model", + CONF_MODEL_ID: "TEST123", + CONF_HW_VERSION: "1.0", + } + + # Mock no existing entry + mock_hass.config_entries.async_entries.return_value = [] + + await flow.async_step_integration_discovery(discovery_info) + + # Should create new entry and proceed to device step + flow.async_create_entry.assert_called_once() + flow.async_step_device.assert_called_once_with(discovery_info) + + @pytest.mark.asyncio + async def test_config_flow_integration_discovery_existing_entry(self, mock_hass): + """Test integration discovery with existing config entry.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + + # Initialize context for flow handler + flow.context = {} + + flow.async_step_device = AsyncMock() + + discovery_info = { + CONF_DEVICE_ID: "test_device_id", + CONF_DEVICE_NAME: "Test Device", + CONF_MANUFACTURER: "Test Manufacturer", + CONF_MODEL: "Test Model", + CONF_MODEL_ID: "TEST123", + CONF_HW_VERSION: "1.0", + } + + # Mock existing entry + existing_entry = MagicMock() + existing_entry.title = INTEGRATION_NAME + existing_entry.subentries = {} + mock_hass.config_entries.async_entries.return_value = [existing_entry] + + await flow.async_step_integration_discovery(discovery_info) + + # Should proceed to device step without creating new entry + flow.async_step_device.assert_called_once_with(discovery_info) + + @pytest.mark.asyncio + async def test_config_flow_integration_discovery_already_configured_subentry(self, mock_hass): + """Test integration discovery when subentry already exists.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + + discovery_info = { + CONF_DEVICE_ID: "test_device_id", + CONF_DEVICE_NAME: "Test Device", + CONF_MANUFACTURER: "Test Manufacturer", + CONF_MODEL: "Test Model", + CONF_MODEL_ID: "TEST123", + CONF_HW_VERSION: "1.0", + } + + # Mock existing entry with subentry + existing_entry = MagicMock() + existing_entry.title = INTEGRATION_NAME + existing_subentry = MagicMock() + existing_subentry.unique_id = "bn_test_device_id" + existing_entry.subentries = {"test": existing_subentry} + mock_hass.config_entries.async_entries.return_value = [existing_entry] + + result = await flow.async_step_integration_discovery(discovery_info) + + assert result["type"] == FlowResultType.ABORT + assert result["reason"] == "already_configured" + + @pytest.mark.asyncio + async def test_config_flow_device_step_with_library_lookup( + self, mock_hass, mock_device_registry, mock_library, mock_library_updater + ): + """Test device step with successful library lookup.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + flow.async_step_battery = AsyncMock() + + user_input = {CONF_DEVICE_ID: "test_device_id"} + + # Mock successful library lookup + battery_details = DeviceBatteryDetails( + manufacturer="Test Manufacturer", + model="Test Model", + model_id="TEST123", + hw_version="1.0", + battery_type="AA", + battery_quantity=2, + ) + mock_library.get_device_battery_details.return_value = battery_details + + with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ + patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ + patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): + + await flow.async_step_device(user_input) + + # Should set battery data from library and proceed to battery step + assert flow.data[CONF_BATTERY_TYPE] == "AA" + assert flow.data[CONF_BATTERY_QUANTITY] == 2 + flow.async_step_battery.assert_called_once() + + @pytest.mark.asyncio + async def test_config_flow_device_step_manual_device( + self, mock_hass, mock_device_registry, mock_library, mock_library_updater + ): + """Test device step with device not found in library (fallback to defaults).""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + flow.data = {} + + # Initialize context for flow handler + flow.context = {} + + flow.async_step_battery = AsyncMock() + + user_input = {CONF_DEVICE_ID: "test_device_id"} + + # Mock device not found in library (returns None) + mock_library.get_device_battery_details.return_value = None + + with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ + patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ + patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): + + await flow.async_step_device(user_input) + + # Should set default battery quantity and proceed to battery step + assert flow.data[CONF_BATTERY_QUANTITY] == 1 + flow.async_step_battery.assert_called_once() + + @pytest.mark.asyncio + async def test_config_flow_device_step_show_form(self, mock_hass): + """Test device step shows form when no user input.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + + result = await flow.async_step_device() + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "device" + assert result["last_step"] is False + + +class TestBatteryNotesOptionsFlow: + """Test class for battery_notes options flow.""" + + @pytest.mark.asyncio + async def test_options_flow_init_form(self): + """Test options flow shows initial form.""" + # Create mock config entry + mock_config_entry = MagicMock() + mock_config_entry.options = { + "show_all_devices": False, + "hide_battery": False, + "round_battery": False, + "default_battery_low_threshold": 10, + "battery_increase_threshold": 25, + "advanced_settings": { + "enable_autodiscovery": True, + "enable_replaced": True, + "user_library": "", + }, + } + + # Create flow instance and use PropertyMock for config_entry + flow = config_flow.OptionsFlowHandler() + + with patch.object(type(flow), 'config_entry', new_callable=lambda: PropertyMock(return_value=mock_config_entry)): + result = await flow.async_step_init() + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "init" + + @pytest.mark.asyncio + async def test_options_flow_init_success(self): + """Test successful options flow submission.""" + # Create mock config entry + mock_config_entry = MagicMock() + mock_config_entry.options = { + "show_all_devices": False, + "hide_battery": False, + "round_battery": False, + "default_battery_low_threshold": 10, + "battery_increase_threshold": 25, + "advanced_settings": { + "enable_autodiscovery": True, + "enable_replaced": True, + "user_library": "", + }, + } + + # Create flow instance and use PropertyMock for config_entry + flow = config_flow.OptionsFlowHandler() + + user_input = { + "show_all_devices": True, + "hide_battery": True, + "round_battery": True, + "default_battery_low_threshold": 15, + "battery_increase_threshold": 30, + "advanced_settings": { + "enable_autodiscovery": False, + "enable_replaced": False, + "user_library": "custom.json", + }, + } + + with patch.object(type(flow), 'config_entry', new_callable=lambda: PropertyMock(return_value=mock_config_entry)): + result = await flow.async_step_init(user_input) + + assert result["type"] == FlowResultType.CREATE_ENTRY + assert result["data"] == user_input + + +class TestBatteryNotesSubentryFlow: + """Test class for battery_notes subentry flow.""" + + @pytest.fixture + def mock_hass(self): + """Return a mock Home Assistant instance.""" + hass = MagicMock(spec=HomeAssistant) + hass.data = {MY_KEY: BatteryNotesDomainConfig()} + + # Add config mock + config_mock = MagicMock() + config_mock.config_dir = "/test/config" + hass.config = config_mock + + return hass + + @pytest.fixture + def mock_device_registry(self): + """Return mock device registry.""" + mock_registry = MagicMock() + mock_device = MagicMock() + mock_device.manufacturer = "Test Manufacturer" + mock_device.model = "Test Model" + mock_device.hw_version = "1.0" + mock_device.model_id = None + mock_registry.async_get.return_value = mock_device + return mock_registry + + @pytest.fixture + def mock_entity_registry(self): + """Return mock entity registry.""" + mock_registry = MagicMock() + mock_entity = MagicMock() + mock_entity.device_id = "test_device_id" + mock_entity.entity_id = "sensor.test_battery" + mock_registry.async_get.return_value = mock_entity + return mock_registry + + @pytest.fixture + def mock_library(self): + """Return mock library.""" + mock_lib = MagicMock() + mock_lib.load_libraries = AsyncMock() + mock_lib.get_device_battery_details = AsyncMock(return_value=None) + return mock_lib + + @pytest.fixture + def mock_library_updater(self): + """Return mock library updater.""" + mock_updater = MagicMock() + mock_updater.time_to_update_library = AsyncMock(return_value=False) + mock_updater.get_library_updates = AsyncMock() + return mock_updater + + @pytest.mark.asyncio + async def test_subentry_flow_user_step(self, mock_hass): + """Test subentry flow user step shows menu.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + + result = await flow.async_step_user() + + assert result["type"] == FlowResultType.MENU + assert result["step_id"] == "user" + assert "device" in result["menu_options"] + assert "entity" in result["menu_options"] + + @pytest.mark.asyncio + async def test_subentry_flow_device_step_form(self, mock_hass): + """Test subentry device step shows form.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + + result = await flow.async_step_device() + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "device" + assert result["last_step"] is False + + @pytest.mark.asyncio + async def test_subentry_flow_device_step_with_device( + self, mock_hass, mock_device_registry, mock_library, mock_library_updater + ): + """Test subentry device step with device selection.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + flow.async_step_battery = AsyncMock() + + user_input = {CONF_DEVICE_ID: "test_device_id"} + + with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ + patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ + patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): + + await flow.async_step_device(user_input) + + # Should set default battery quantity and proceed to battery step + assert flow.data[CONF_BATTERY_QUANTITY] == 1 + flow.async_step_battery.assert_called_once() + + @pytest.mark.asyncio + async def test_subentry_flow_entity_step_form(self, mock_hass): + """Test subentry entity step shows form.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + + result = await flow.async_step_entity() + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "entity" + assert result["last_step"] is False + + @pytest.mark.asyncio + async def test_subentry_flow_entity_step_with_entity( + self, mock_hass, mock_entity_registry, mock_device_registry, mock_library, mock_library_updater + ): + """Test subentry entity step with entity selection.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + flow.async_step_battery = AsyncMock() + + user_input = {CONF_SOURCE_ENTITY_ID: "sensor.test_battery"} + + with patch("custom_components.battery_notes.config_flow.er.async_get", return_value=mock_entity_registry), \ + patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ + patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ + patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): + + await flow.async_step_entity(user_input) + + # Should set source entity and default battery quantity + assert flow.data[CONF_SOURCE_ENTITY_ID] == "sensor.test_battery" + assert flow.data[CONF_BATTERY_QUANTITY] == 1 + flow.async_step_battery.assert_called_once() + + @pytest.mark.asyncio + async def test_subentry_flow_battery_step_form(self, mock_hass): + """Test subentry battery step shows form.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + flow.data = { + CONF_BATTERY_TYPE: "AA", + CONF_BATTERY_QUANTITY: 2, + } + + result = await flow.async_step_battery() + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "battery" + + @pytest.mark.asyncio + async def test_subentry_flow_battery_step_success(self, mock_hass): + """Test successful subentry battery step submission.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + flow.data = { + CONF_DEVICE_ID: "test_device_id", + CONF_BATTERY_TYPE: "AA", + CONF_BATTERY_QUANTITY: 2, + } + + # Mock the handler property and source to avoid entry ID issues + flow.handler = ("test_entry_id", "test_subentry_id") + flow.context = {"source": "user"} + + user_input = { + CONF_BATTERY_TYPE: "AAA", + CONF_BATTERY_QUANTITY: 4, + CONF_BATTERY_LOW_THRESHOLD: 15, + CONF_FILTER_OUTLIERS: True, + } + + # Mock device registry and config entry access + with patch("custom_components.battery_notes.config_flow.dr.async_get") as mock_dr: + mock_device = MagicMock() + mock_device.name_by_user = None + mock_device.name = "Test Device" + mock_dr.return_value.async_get.return_value = mock_device + + # Mock the config entry access + with patch.object(flow, '_get_entry') as mock_get_entry: + mock_entry = MagicMock() + mock_entry.subentries = {} + mock_get_entry.return_value = mock_entry + + result = await flow.async_step_battery(user_input) + + assert result["type"] == FlowResultType.CREATE_ENTRY + assert result["title"] == "Test Device" + assert result["data"][CONF_BATTERY_TYPE] == "AAA" + assert result["data"][CONF_BATTERY_QUANTITY] == 4 + assert result["data"][CONF_BATTERY_LOW_THRESHOLD] == 15 + assert result["data"][CONF_FILTER_OUTLIERS] is True + + @pytest.mark.asyncio + async def test_subentry_flow_manual_step_form(self, mock_hass): + """Test subentry manual step shows form.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + flow.data = {} + + result = await flow.async_step_manual() + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "manual" + + @pytest.mark.asyncio + async def test_subentry_flow_manual_step_success(self, mock_hass): + """Test successful subentry manual step submission.""" + flow = config_flow.BatteryNotesSubentryFlowHandler() + flow.hass = mock_hass + flow.data = {CONF_DEVICE_ID: "test_device_id"} + + # Mock the battery step to return proper result + flow.async_step_battery = AsyncMock(return_value={ + "type": FlowResultType.CREATE_ENTRY, + "title": "Test", + "data": {} + }) + + user_input = { + CONF_BATTERY_TYPE: "CR2032", + CONF_BATTERY_QUANTITY: 1, + CONF_BATTERY_LOW_THRESHOLD: 20, + } + + result = await flow.async_step_manual(user_input) + + # Manual step just forwards to battery step + flow.async_step_battery.assert_called_once() + assert result["type"] == FlowResultType.CREATE_ENTRY + + def test_config_flow_properties(self): + """Test config flow static properties and methods.""" + # Test version + assert config_flow.BatteryNotesFlowHandler.VERSION == config_flow.CONFIG_VERSION + + # Test options flow + mock_entry = MagicMock() + options_flow = config_flow.BatteryNotesFlowHandler.async_get_options_flow(mock_entry) + assert isinstance(options_flow, config_flow.OptionsFlowHandler) + + # Test supported subentry types + mock_entry = MagicMock() + subentry_types = config_flow.BatteryNotesFlowHandler.async_get_supported_subentry_types(mock_entry) + assert SUBENTRY_BATTERY_NOTE in subentry_types + assert subentry_types[SUBENTRY_BATTERY_NOTE] == config_flow.BatteryNotesSubentryFlowHandler + + def test_subentry_flow_is_new_property(self): + """Test subentry flow _is_new property behavior through public interface.""" + # Create a flow with proper context setup + flow = config_flow.BatteryNotesSubentryFlowHandler() + + # Mock the context with source="user" for new subentry + flow.context = {"source": "user"} + # We need to directly set the source property since it's readonly + with patch.object(type(flow), 'source', new_callable=lambda: property(lambda self: "user")): + # Test the behavior that depends on _is_new instead of accessing it directly + # The _is_new property affects flow behavior, so we test that behavior + assert hasattr(flow, '_is_new') # Just verify the property exists + + # Test existing subentry with different source + with patch.object(type(flow), 'source', new_callable=lambda: property(lambda self: "reconfigure")): + # Again, just verify the property exists rather than accessing it + assert hasattr(flow, '_is_new') + + @pytest.mark.asyncio + async def test_config_flow_device_step_no_device_info(self, mock_hass, mock_library_updater): + """Test device step when device has no manufacturer/model info.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + flow.async_step_battery = AsyncMock() + + user_input = {CONF_DEVICE_ID: "test_device_id"} + + # Mock device registry with no device info + mock_device_registry = MagicMock() + mock_device = MagicMock() + mock_device.manufacturer = None + mock_device.model = None + mock_device_registry.async_get.return_value = mock_device + + with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ + patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): + + await flow.async_step_device(user_input) + + # Should proceed to battery step even without device info + flow.async_step_battery.assert_called_once() + + @pytest.mark.asyncio + async def test_config_flow_library_update_triggered(self, mock_hass, mock_device_registry, mock_library, mock_library_updater): + """Test that library update is triggered when needed.""" + flow = config_flow.BatteryNotesFlowHandler() + flow.hass = mock_hass + flow.async_step_battery = AsyncMock() + + user_input = {CONF_DEVICE_ID: "test_device_id"} + + # Mock library update needed + mock_library_updater.time_to_update_library.return_value = True + + with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ + patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ + patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): + + await flow.async_step_device(user_input) + + # Should trigger library update + mock_library_updater.get_library_updates.assert_called_once() + flow.async_step_battery.assert_called_once() diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 000000000..d526a9713 --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,252 @@ +"""Test battery_notes integration initialization.""" + +from unittest.mock import MagicMock, patch + +import pytest +from awesomeversion.awesomeversion import AwesomeVersion +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import __version__ as HA_VERSION + +from custom_components.battery_notes import async_setup, async_setup_entry +from custom_components.battery_notes.const import DOMAIN, MIN_HA_VERSION +from custom_components.battery_notes.coordinator import MY_KEY, BatteryNotesDomainConfig + + +class TestBatteryNotesInit: + """Test class for battery_notes initialization.""" + + @pytest.mark.asyncio + async def test_async_setup_success(self, mock_hass): + """Test successful async_setup.""" + # Mock the domain config creation + with patch("custom_components.battery_notes.async_get_registry") as mock_registry, \ + patch("custom_components.battery_notes.async_migrate_integration") as mock_migrate, \ + patch("custom_components.battery_notes.async_setup_services") as mock_services: + + mock_store = MagicMock() + mock_registry.return_value = mock_store + + # Test configuration + config = { + DOMAIN: { + "enable_autodiscovery": True, + "user_library": "", + "show_all_devices": False, + "enable_replaced": True, + "hide_battery": False, + "round_battery": False, + "default_battery_low_threshold": 10, + "battery_increase_threshold": 25, + } + } + + # Call async_setup + result = await async_setup(mock_hass, config) + + # Verify result + assert result is True + assert MY_KEY in mock_hass.data + assert isinstance(mock_hass.data[MY_KEY], BatteryNotesDomainConfig) + + # Verify store was set + domain_config = mock_hass.data[MY_KEY] + assert domain_config.store == mock_store + + # Verify migration and services were called + mock_migrate.assert_called_once() + mock_services.assert_called_once() + + @pytest.mark.asyncio + async def test_async_setup_minimal_config(self, mock_hass): + """Test async_setup with minimal configuration.""" + with patch("custom_components.battery_notes.async_get_registry") as mock_registry, \ + patch("custom_components.battery_notes.async_migrate_integration"), \ + patch("custom_components.battery_notes.async_setup_services"): + + mock_store = MagicMock() + mock_registry.return_value = mock_store + + # Minimal config (using defaults) + config = {DOMAIN: {}} + + result = await async_setup(mock_hass, config) + + assert result is True + assert MY_KEY in mock_hass.data + + # Check defaults are applied + domain_config = mock_hass.data[MY_KEY] + assert domain_config.enable_autodiscovery is True + assert domain_config.show_all_devices is False + assert domain_config.enable_replaced is True + assert domain_config.default_battery_low_threshold == 10 + + @pytest.mark.asyncio + async def test_async_setup_entry_success(self, mock_hass, mock_config_entry, mock_battery_subentry): + """Test successful async_setup_entry.""" + # Setup domain config first + domain_config = BatteryNotesDomainConfig() + domain_config.store = MagicMock() + mock_hass.data[MY_KEY] = domain_config + + # Mock the subentries property to return our test subentry + subentries_dict = {"test_subentry_id": mock_battery_subentry} + with patch.object(mock_config_entry, 'subentries', subentries_dict): + + with patch("custom_components.battery_notes.DiscoveryManager"), \ + patch("custom_components.battery_notes.BatteryNotesSubentryCoordinator") as mock_coordinator, \ + patch("custom_components.battery_notes.async_call_later") as mock_call_later: + + # Mock the coordinator + mock_coordinator_instance = MagicMock() + mock_coordinator.return_value = mock_coordinator_instance + + # Call async_setup_entry + result = await async_setup_entry(mock_hass, mock_config_entry) + + # Verify result + assert result is True + + # Verify config entry runtime data is set + assert hasattr(mock_config_entry, 'runtime_data') + assert mock_config_entry.runtime_data.domain_config == domain_config + assert mock_config_entry.runtime_data.store == domain_config.store + + # Verify subentry coordinators are created + assert mock_config_entry.runtime_data.subentry_coordinators is not None + assert "test_subentry_id" in mock_config_entry.runtime_data.subentry_coordinators + + # Verify platforms are setup + mock_hass.config_entries.async_forward_entry_setups.assert_called_once() + + # Verify delayed discovery is scheduled + mock_call_later.assert_called_once() + + @pytest.mark.asyncio + async def test_async_setup_entry_no_subentries(self, mock_hass, mock_config_entry): + """Test async_setup_entry with no subentries.""" + # Setup domain config first + domain_config = BatteryNotesDomainConfig() + domain_config.store = MagicMock() + mock_hass.data[MY_KEY] = domain_config + + # Mock empty subentries + with patch.object(mock_config_entry, 'subentries', {}): + + with patch("custom_components.battery_notes.DiscoveryManager"), \ + patch("custom_components.battery_notes.async_call_later"): + + result = await async_setup_entry(mock_hass, mock_config_entry) + + # Should still succeed + assert result is True + + # Runtime data should be set + assert hasattr(mock_config_entry, 'runtime_data') + + # Subentry coordinators should be empty + assert mock_config_entry.runtime_data.subentry_coordinators == {} + + @pytest.mark.asyncio + async def test_async_setup_entry_domain_config_options(self, mock_hass): + """Test async_setup_entry applies config entry options to domain config.""" + # Setup domain config first + domain_config = BatteryNotesDomainConfig() + domain_config.store = MagicMock() + mock_hass.data[MY_KEY] = domain_config + + # Create a config entry with custom options + custom_config_entry = ConfigEntry( + version=1, + minor_version=1, + domain=DOMAIN, + title="Battery Notes Test", + data={}, + options={ + "show_all_devices": True, + "hide_battery": True, + "round_battery": True, + "default_battery_low_threshold": 15, + "battery_increase_threshold": 30, + "advanced_settings": { + "enable_autodiscovery": True, + "enable_replaced": True, + "user_library": "", + }, + }, + source="user", + entry_id="test_entry_id", + unique_id="test_unique_id", + discovery_keys=set(), + subentries_data={}, + ) + + with patch("custom_components.battery_notes.DiscoveryManager"), \ + patch("custom_components.battery_notes.async_call_later"): + + await async_setup_entry(mock_hass, custom_config_entry) + + # Verify domain config is updated with entry options + assert domain_config.show_all_devices is True + assert domain_config.hide_battery is True + assert domain_config.round_battery is True + assert domain_config.default_battery_low_threshold == 15 + assert domain_config.battery_increased_threshod == 30 + + def test_ha_version_check(self): + """Test that the integration checks Home Assistant version.""" + # This test verifies the HA version check logic exists + # In a real scenario, this would test the actual version validation + + # Test that MIN_HA_VERSION is properly defined + assert MIN_HA_VERSION is not None + assert AwesomeVersion(MIN_HA_VERSION) <= AwesomeVersion(HA_VERSION) + + @pytest.mark.asyncio + async def test_async_setup_entry_missing_domain_config(self, mock_hass, mock_config_entry): + """Test async_setup_entry fails gracefully when domain config is missing.""" + # Don't set up domain config in hass.data + + with pytest.raises(KeyError): + await async_setup_entry(mock_hass, mock_config_entry) + + @pytest.mark.asyncio + async def test_async_setup_entry_coordinator_creation(self, mock_hass, mock_config_entry): + """Test that coordinators are properly created for battery subentries.""" + # Setup domain config + domain_config = BatteryNotesDomainConfig() + domain_config.store = MagicMock() + mock_hass.data[MY_KEY] = domain_config + + # Create multiple subentries with different IDs + subentry1 = MagicMock() + subentry1.subentry_type = "battery_note" + subentry1.subentry_id = "subentry1" + subentry1.unique_id = "unique1" + + subentry2 = MagicMock() + subentry2.subentry_type = "battery_note" + subentry2.subentry_id = "subentry2" + subentry2.unique_id = "unique2" + + subentries_dict = { + "subentry1": subentry1, + "subentry2": subentry2, + } + + # Mock the subentries property + with patch.object(mock_config_entry, 'subentries', subentries_dict): + + with patch("custom_components.battery_notes.DiscoveryManager"), \ + patch("custom_components.battery_notes.BatteryNotesSubentryCoordinator") as mock_coordinator, \ + patch("custom_components.battery_notes.async_call_later"): + + await async_setup_entry(mock_hass, mock_config_entry) + + # Verify coordinator is created for each subentry + assert mock_coordinator.call_count == 2 + + # Verify coordinators are stored + assert len(mock_config_entry.runtime_data.subentry_coordinators) == 2 + assert "subentry1" in mock_config_entry.runtime_data.subentry_coordinators + assert "subentry2" in mock_config_entry.runtime_data.subentry_coordinators From c1df9f5cd8bcd1535ff7b455311c1eddc5e6b2f3 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 10 Sep 2025 10:38:50 +0100 Subject: [PATCH 189/235] Revert "Add some basic AI tests" This reverts commit b7012331ca36a82b978dc9b31b0ba9d6e9200e3e. --- pyproject.toml | 14 - requirements_dev.txt | 2 - requirements_test.txt | 1 - scripts/setup | 2 +- scripts/test | 15 - tests/README.md | 20 -- tests/__init__.py | 1 - tests/conftest.py | 114 ------- tests/test_config_flow.py | 671 -------------------------------------- tests/test_init.py | 252 -------------- 10 files changed, 1 insertion(+), 1091 deletions(-) delete mode 100644 requirements_dev.txt delete mode 100644 requirements_test.txt delete mode 100755 scripts/test delete mode 100644 tests/README.md delete mode 100644 tests/__init__.py delete mode 100644 tests/conftest.py delete mode 100644 tests/test_config_flow.py delete mode 100644 tests/test_init.py diff --git a/pyproject.toml b/pyproject.toml index 20a70f5be..209a2a07f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,17 +129,3 @@ ignore_missing_imports = true [tool.ruff.lint.mccabe] max-complexity = 25 - -[tool.pytest.ini_options] -minversion = "6.0" -addopts = ["--strict-markers", "--tb=short", "-v"] -testpaths = ["tests"] -python_files = ["test_*.py"] -python_classes = ["Test*"] -python_functions = ["test_*"] -markers = ["asyncio: mark test as asyncio"] -asyncio_mode = "auto" -filterwarnings = [ - "ignore::DeprecationWarning", - "ignore::PendingDeprecationWarning", -] diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index 40cfa9102..000000000 --- a/requirements_dev.txt +++ /dev/null @@ -1,2 +0,0 @@ -pre-commit -mypy \ No newline at end of file diff --git a/requirements_test.txt b/requirements_test.txt deleted file mode 100644 index 71f59992c..000000000 --- a/requirements_test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest-homeassistant-custom-component diff --git a/scripts/setup b/scripts/setup index c18e08450..141d19f9d 100755 --- a/scripts/setup +++ b/scripts/setup @@ -4,4 +4,4 @@ set -e cd "$(dirname "$0")/.." -python3 -m pip install -r requirements.txt -r requirements_dev.txt -r requirements_test.txt +python3 -m pip install --requirement requirements.txt diff --git a/scripts/test b/scripts/test deleted file mode 100755 index b4823c229..000000000 --- a/scripts/test +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -e - -# Change to project root directory -cd "$(dirname "$0")/.." - -# Run pytest with configuration -echo "Running tests..." -python -m pytest tests/ \ - -v \ - --tb=short \ - --strict-markers - -echo "Tests completed with exit code: $?" diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index fcddba1f2..000000000 --- a/tests/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Battery Notes Test Framework - -## Running Tests - -```bash -# Run all tests using the test script -./scripts/test - -# Or run tests directly with pytest -python -m pytest tests/ -v - -# Run specific test file -python -m pytest tests/test_init.py -v - -# Run specific test -python -m pytest tests/test_init.py::TestBatteryNotesInit::test_async_setup_success -v - -# Run with coverage -pytest --cov-report term-missing --cov=custom_components.battery_notes tests -``` diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 8475f8162..000000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Tests for battery_notes integration.""" diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index fedb2bbf8..000000000 --- a/tests/conftest.py +++ /dev/null @@ -1,114 +0,0 @@ -"""Test configuration for battery_notes tests.""" - -from unittest.mock import AsyncMock, MagicMock - -import pytest -from homeassistant.config_entries import ConfigEntry, ConfigSubentry -from homeassistant.const import CONF_DEVICE_ID -from homeassistant.core import HomeAssistant - -from custom_components.battery_notes.const import ( - CONF_ADVANCED_SETTINGS, - CONF_BATTERY_INCREASE_THRESHOLD, - CONF_BATTERY_QUANTITY, - CONF_BATTERY_TYPE, - CONF_DEFAULT_BATTERY_LOW_THRESHOLD, - CONF_ENABLE_AUTODISCOVERY, - CONF_ENABLE_REPLACED, - CONF_HIDE_BATTERY, - CONF_ROUND_BATTERY, - CONF_SHOW_ALL_DEVICES, - CONF_USER_LIBRARY, - DEFAULT_BATTERY_INCREASE_THRESHOLD, - DEFAULT_BATTERY_LOW_THRESHOLD, - DOMAIN, - SUBENTRY_BATTERY_NOTE, -) -from custom_components.battery_notes.coordinator import BatteryNotesDomainConfig - - -@pytest.fixture -def mock_config_entry(): - """Return a mock config entry.""" - config_entry = MagicMock(spec=ConfigEntry) - config_entry.version = 1 - config_entry.minor_version = 1 - config_entry.domain = DOMAIN - config_entry.title = "Battery Notes Test" - config_entry.data = {} - config_entry.options = { - CONF_SHOW_ALL_DEVICES: False, - CONF_HIDE_BATTERY: False, - CONF_ROUND_BATTERY: False, - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, - CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, - CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: True, - CONF_ENABLE_REPLACED: True, - CONF_USER_LIBRARY: "", - }, - } - config_entry.source = "user" - config_entry.entry_id = "test_entry_id" - config_entry.unique_id = "test_unique_id" - config_entry.discovery_keys = set() - config_entry.subentries_data = {} - # Add subentries property as an empty dict by default - config_entry.subentries = {} - return config_entry - -@pytest.fixture -def mock_battery_subentry(): - """Return a mock battery subentry.""" - return ConfigSubentry( - subentry_type=SUBENTRY_BATTERY_NOTE, - subentry_id="test_subentry_id", - title="Test Battery Device", - data={ - CONF_DEVICE_ID: "test_device_id", - CONF_BATTERY_TYPE: "AA", - CONF_BATTERY_QUANTITY: 2, - }, - unique_id="test_subentry_unique_id", - ) - - -@pytest.fixture -def mock_hass(): - """Return a mock Home Assistant instance.""" - hass = MagicMock(spec=HomeAssistant) - hass.data = {} - - # Mock config - mock_config = MagicMock() - mock_config.config_dir = "/tmp/config" - hass.config = mock_config - - # Mock config_entries - hass.config_entries = MagicMock() - hass.config_entries.async_forward_entry_setups = AsyncMock() - - return hass - - -@pytest.fixture -def mock_store(): - """Return a mock store.""" - store = MagicMock() - store.async_load = AsyncMock(return_value={}) - return store - - -@pytest.fixture -def mock_domain_config(): - """Return a mock domain config.""" - return BatteryNotesDomainConfig( - enable_autodiscovery=True, - show_all_devices=False, - enable_replaced=True, - hide_battery=False, - round_battery=False, - default_battery_low_threshold=DEFAULT_BATTERY_LOW_THRESHOLD, - battery_increased_threshod=DEFAULT_BATTERY_INCREASE_THRESHOLD, - user_library="", - ) diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py deleted file mode 100644 index af5aeb840..000000000 --- a/tests/test_config_flow.py +++ /dev/null @@ -1,671 +0,0 @@ -"""Test battery_notes config flow.""" - -from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch - -import pytest -from homeassistant.const import CONF_DEVICE_ID -from homeassistant.core import HomeAssistant -from homeassistant.data_entry_flow import FlowResultType - -from custom_components.battery_notes import config_flow -from custom_components.battery_notes.const import ( - CONF_BATTERY_LOW_THRESHOLD, - CONF_BATTERY_QUANTITY, - CONF_BATTERY_TYPE, - CONF_DEVICE_NAME, - CONF_FILTER_OUTLIERS, - CONF_HW_VERSION, - CONF_MANUFACTURER, - CONF_MODEL, - CONF_MODEL_ID, - CONF_SOURCE_ENTITY_ID, - SUBENTRY_BATTERY_NOTE, -) -from custom_components.battery_notes.const import NAME as INTEGRATION_NAME -from custom_components.battery_notes.coordinator import MY_KEY, BatteryNotesDomainConfig -from custom_components.battery_notes.library import DeviceBatteryDetails - - -class TestBatteryNotesConfigFlow: - """Test class for battery_notes config flow.""" - - @pytest.fixture - def mock_hass(self): - """Return a mock Home Assistant instance.""" - hass = MagicMock(spec=HomeAssistant) - hass.data = {MY_KEY: BatteryNotesDomainConfig()} - - # Add config mock - config_mock = MagicMock() - config_mock.config_dir = "/test/config" - hass.config = config_mock - - # Add config_entries mock - hass.config_entries = MagicMock() - hass.config_entries.async_entries.return_value = [] - return hass - - @pytest.fixture - def mock_device_registry(self): - """Return mock device registry.""" - mock_registry = MagicMock() - mock_device = MagicMock() - mock_device.manufacturer = "Test Manufacturer" - mock_device.model = "Test Model" - mock_device.hw_version = "1.0" - mock_device.model_id = "TEST123" - mock_registry.async_get.return_value = mock_device - return mock_registry - - @pytest.fixture - def mock_entity_registry(self): - """Return mock entity registry.""" - mock_registry = MagicMock() - mock_entity = MagicMock() - mock_entity.device_id = "test_device_id" - mock_entity.entity_id = "sensor.test_battery" - mock_registry.async_get.return_value = mock_entity - return mock_registry - - @pytest.fixture - def mock_library(self): - """Return mock library.""" - mock_lib = MagicMock() - mock_lib.load_libraries = AsyncMock() - mock_lib.get_device_battery_details = AsyncMock() - return mock_lib - - @pytest.fixture - def mock_library_updater(self): - """Return mock library updater.""" - mock_updater = MagicMock() - mock_updater.time_to_update_library = AsyncMock(return_value=False) - mock_updater.get_library_updates = AsyncMock() - return mock_updater - - @pytest.mark.asyncio - async def test_config_flow_user_step_success(self, mock_hass): - """Test successful user step flow.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - - # Initialize context for flow handler - flow.context = {} - - # Test initial form - result = await flow.async_step_user() - assert result["type"] == FlowResultType.FORM - assert result["step_id"] == "user" - - # Test successful submission - result = await flow.async_step_user(user_input={}) - assert result["type"] == FlowResultType.CREATE_ENTRY - assert result["title"] == INTEGRATION_NAME - - @pytest.mark.asyncio - async def test_config_flow_user_step_already_configured(self, mock_hass): - """Test user step when already configured.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - - # Mock existing entry through hass.config_entries - existing_entry = MagicMock() - existing_entry.domain = "battery_notes" - mock_hass.config_entries.async_entries.return_value = [existing_entry] - - result = await flow.async_step_user() - assert result["type"] == FlowResultType.ABORT - assert result["reason"] == "already_configured" - - @pytest.mark.asyncio - async def test_config_flow_integration_discovery_new_entry(self, mock_hass): - """Test integration discovery with new config entry.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - - # Initialize context for flow handler - flow.context = {} - - # Mock the async_get_integration_entry method to return None first, then a config entry - created_entry = MagicMock() - created_entry.subentries = {} - flow.async_get_integration_entry = AsyncMock(side_effect=[None, created_entry]) - - # Mock create_entry to return a proper result - flow.async_create_entry = MagicMock(return_value={"type": "create_entry", "title": "Test"}) - flow.async_step_device = AsyncMock() - - discovery_info = { - CONF_DEVICE_ID: "test_device_id", - CONF_DEVICE_NAME: "Test Device", - CONF_MANUFACTURER: "Test Manufacturer", - CONF_MODEL: "Test Model", - CONF_MODEL_ID: "TEST123", - CONF_HW_VERSION: "1.0", - } - - # Mock no existing entry - mock_hass.config_entries.async_entries.return_value = [] - - await flow.async_step_integration_discovery(discovery_info) - - # Should create new entry and proceed to device step - flow.async_create_entry.assert_called_once() - flow.async_step_device.assert_called_once_with(discovery_info) - - @pytest.mark.asyncio - async def test_config_flow_integration_discovery_existing_entry(self, mock_hass): - """Test integration discovery with existing config entry.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - - # Initialize context for flow handler - flow.context = {} - - flow.async_step_device = AsyncMock() - - discovery_info = { - CONF_DEVICE_ID: "test_device_id", - CONF_DEVICE_NAME: "Test Device", - CONF_MANUFACTURER: "Test Manufacturer", - CONF_MODEL: "Test Model", - CONF_MODEL_ID: "TEST123", - CONF_HW_VERSION: "1.0", - } - - # Mock existing entry - existing_entry = MagicMock() - existing_entry.title = INTEGRATION_NAME - existing_entry.subentries = {} - mock_hass.config_entries.async_entries.return_value = [existing_entry] - - await flow.async_step_integration_discovery(discovery_info) - - # Should proceed to device step without creating new entry - flow.async_step_device.assert_called_once_with(discovery_info) - - @pytest.mark.asyncio - async def test_config_flow_integration_discovery_already_configured_subentry(self, mock_hass): - """Test integration discovery when subentry already exists.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - - discovery_info = { - CONF_DEVICE_ID: "test_device_id", - CONF_DEVICE_NAME: "Test Device", - CONF_MANUFACTURER: "Test Manufacturer", - CONF_MODEL: "Test Model", - CONF_MODEL_ID: "TEST123", - CONF_HW_VERSION: "1.0", - } - - # Mock existing entry with subentry - existing_entry = MagicMock() - existing_entry.title = INTEGRATION_NAME - existing_subentry = MagicMock() - existing_subentry.unique_id = "bn_test_device_id" - existing_entry.subentries = {"test": existing_subentry} - mock_hass.config_entries.async_entries.return_value = [existing_entry] - - result = await flow.async_step_integration_discovery(discovery_info) - - assert result["type"] == FlowResultType.ABORT - assert result["reason"] == "already_configured" - - @pytest.mark.asyncio - async def test_config_flow_device_step_with_library_lookup( - self, mock_hass, mock_device_registry, mock_library, mock_library_updater - ): - """Test device step with successful library lookup.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - flow.async_step_battery = AsyncMock() - - user_input = {CONF_DEVICE_ID: "test_device_id"} - - # Mock successful library lookup - battery_details = DeviceBatteryDetails( - manufacturer="Test Manufacturer", - model="Test Model", - model_id="TEST123", - hw_version="1.0", - battery_type="AA", - battery_quantity=2, - ) - mock_library.get_device_battery_details.return_value = battery_details - - with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ - patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ - patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): - - await flow.async_step_device(user_input) - - # Should set battery data from library and proceed to battery step - assert flow.data[CONF_BATTERY_TYPE] == "AA" - assert flow.data[CONF_BATTERY_QUANTITY] == 2 - flow.async_step_battery.assert_called_once() - - @pytest.mark.asyncio - async def test_config_flow_device_step_manual_device( - self, mock_hass, mock_device_registry, mock_library, mock_library_updater - ): - """Test device step with device not found in library (fallback to defaults).""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - flow.data = {} - - # Initialize context for flow handler - flow.context = {} - - flow.async_step_battery = AsyncMock() - - user_input = {CONF_DEVICE_ID: "test_device_id"} - - # Mock device not found in library (returns None) - mock_library.get_device_battery_details.return_value = None - - with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ - patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ - patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): - - await flow.async_step_device(user_input) - - # Should set default battery quantity and proceed to battery step - assert flow.data[CONF_BATTERY_QUANTITY] == 1 - flow.async_step_battery.assert_called_once() - - @pytest.mark.asyncio - async def test_config_flow_device_step_show_form(self, mock_hass): - """Test device step shows form when no user input.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - - result = await flow.async_step_device() - - assert result["type"] == FlowResultType.FORM - assert result["step_id"] == "device" - assert result["last_step"] is False - - -class TestBatteryNotesOptionsFlow: - """Test class for battery_notes options flow.""" - - @pytest.mark.asyncio - async def test_options_flow_init_form(self): - """Test options flow shows initial form.""" - # Create mock config entry - mock_config_entry = MagicMock() - mock_config_entry.options = { - "show_all_devices": False, - "hide_battery": False, - "round_battery": False, - "default_battery_low_threshold": 10, - "battery_increase_threshold": 25, - "advanced_settings": { - "enable_autodiscovery": True, - "enable_replaced": True, - "user_library": "", - }, - } - - # Create flow instance and use PropertyMock for config_entry - flow = config_flow.OptionsFlowHandler() - - with patch.object(type(flow), 'config_entry', new_callable=lambda: PropertyMock(return_value=mock_config_entry)): - result = await flow.async_step_init() - - assert result["type"] == FlowResultType.FORM - assert result["step_id"] == "init" - - @pytest.mark.asyncio - async def test_options_flow_init_success(self): - """Test successful options flow submission.""" - # Create mock config entry - mock_config_entry = MagicMock() - mock_config_entry.options = { - "show_all_devices": False, - "hide_battery": False, - "round_battery": False, - "default_battery_low_threshold": 10, - "battery_increase_threshold": 25, - "advanced_settings": { - "enable_autodiscovery": True, - "enable_replaced": True, - "user_library": "", - }, - } - - # Create flow instance and use PropertyMock for config_entry - flow = config_flow.OptionsFlowHandler() - - user_input = { - "show_all_devices": True, - "hide_battery": True, - "round_battery": True, - "default_battery_low_threshold": 15, - "battery_increase_threshold": 30, - "advanced_settings": { - "enable_autodiscovery": False, - "enable_replaced": False, - "user_library": "custom.json", - }, - } - - with patch.object(type(flow), 'config_entry', new_callable=lambda: PropertyMock(return_value=mock_config_entry)): - result = await flow.async_step_init(user_input) - - assert result["type"] == FlowResultType.CREATE_ENTRY - assert result["data"] == user_input - - -class TestBatteryNotesSubentryFlow: - """Test class for battery_notes subentry flow.""" - - @pytest.fixture - def mock_hass(self): - """Return a mock Home Assistant instance.""" - hass = MagicMock(spec=HomeAssistant) - hass.data = {MY_KEY: BatteryNotesDomainConfig()} - - # Add config mock - config_mock = MagicMock() - config_mock.config_dir = "/test/config" - hass.config = config_mock - - return hass - - @pytest.fixture - def mock_device_registry(self): - """Return mock device registry.""" - mock_registry = MagicMock() - mock_device = MagicMock() - mock_device.manufacturer = "Test Manufacturer" - mock_device.model = "Test Model" - mock_device.hw_version = "1.0" - mock_device.model_id = None - mock_registry.async_get.return_value = mock_device - return mock_registry - - @pytest.fixture - def mock_entity_registry(self): - """Return mock entity registry.""" - mock_registry = MagicMock() - mock_entity = MagicMock() - mock_entity.device_id = "test_device_id" - mock_entity.entity_id = "sensor.test_battery" - mock_registry.async_get.return_value = mock_entity - return mock_registry - - @pytest.fixture - def mock_library(self): - """Return mock library.""" - mock_lib = MagicMock() - mock_lib.load_libraries = AsyncMock() - mock_lib.get_device_battery_details = AsyncMock(return_value=None) - return mock_lib - - @pytest.fixture - def mock_library_updater(self): - """Return mock library updater.""" - mock_updater = MagicMock() - mock_updater.time_to_update_library = AsyncMock(return_value=False) - mock_updater.get_library_updates = AsyncMock() - return mock_updater - - @pytest.mark.asyncio - async def test_subentry_flow_user_step(self, mock_hass): - """Test subentry flow user step shows menu.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - - result = await flow.async_step_user() - - assert result["type"] == FlowResultType.MENU - assert result["step_id"] == "user" - assert "device" in result["menu_options"] - assert "entity" in result["menu_options"] - - @pytest.mark.asyncio - async def test_subentry_flow_device_step_form(self, mock_hass): - """Test subentry device step shows form.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - - result = await flow.async_step_device() - - assert result["type"] == FlowResultType.FORM - assert result["step_id"] == "device" - assert result["last_step"] is False - - @pytest.mark.asyncio - async def test_subentry_flow_device_step_with_device( - self, mock_hass, mock_device_registry, mock_library, mock_library_updater - ): - """Test subentry device step with device selection.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - flow.async_step_battery = AsyncMock() - - user_input = {CONF_DEVICE_ID: "test_device_id"} - - with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ - patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ - patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): - - await flow.async_step_device(user_input) - - # Should set default battery quantity and proceed to battery step - assert flow.data[CONF_BATTERY_QUANTITY] == 1 - flow.async_step_battery.assert_called_once() - - @pytest.mark.asyncio - async def test_subentry_flow_entity_step_form(self, mock_hass): - """Test subentry entity step shows form.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - - result = await flow.async_step_entity() - - assert result["type"] == FlowResultType.FORM - assert result["step_id"] == "entity" - assert result["last_step"] is False - - @pytest.mark.asyncio - async def test_subentry_flow_entity_step_with_entity( - self, mock_hass, mock_entity_registry, mock_device_registry, mock_library, mock_library_updater - ): - """Test subentry entity step with entity selection.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - flow.async_step_battery = AsyncMock() - - user_input = {CONF_SOURCE_ENTITY_ID: "sensor.test_battery"} - - with patch("custom_components.battery_notes.config_flow.er.async_get", return_value=mock_entity_registry), \ - patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ - patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ - patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): - - await flow.async_step_entity(user_input) - - # Should set source entity and default battery quantity - assert flow.data[CONF_SOURCE_ENTITY_ID] == "sensor.test_battery" - assert flow.data[CONF_BATTERY_QUANTITY] == 1 - flow.async_step_battery.assert_called_once() - - @pytest.mark.asyncio - async def test_subentry_flow_battery_step_form(self, mock_hass): - """Test subentry battery step shows form.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - flow.data = { - CONF_BATTERY_TYPE: "AA", - CONF_BATTERY_QUANTITY: 2, - } - - result = await flow.async_step_battery() - - assert result["type"] == FlowResultType.FORM - assert result["step_id"] == "battery" - - @pytest.mark.asyncio - async def test_subentry_flow_battery_step_success(self, mock_hass): - """Test successful subentry battery step submission.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - flow.data = { - CONF_DEVICE_ID: "test_device_id", - CONF_BATTERY_TYPE: "AA", - CONF_BATTERY_QUANTITY: 2, - } - - # Mock the handler property and source to avoid entry ID issues - flow.handler = ("test_entry_id", "test_subentry_id") - flow.context = {"source": "user"} - - user_input = { - CONF_BATTERY_TYPE: "AAA", - CONF_BATTERY_QUANTITY: 4, - CONF_BATTERY_LOW_THRESHOLD: 15, - CONF_FILTER_OUTLIERS: True, - } - - # Mock device registry and config entry access - with patch("custom_components.battery_notes.config_flow.dr.async_get") as mock_dr: - mock_device = MagicMock() - mock_device.name_by_user = None - mock_device.name = "Test Device" - mock_dr.return_value.async_get.return_value = mock_device - - # Mock the config entry access - with patch.object(flow, '_get_entry') as mock_get_entry: - mock_entry = MagicMock() - mock_entry.subentries = {} - mock_get_entry.return_value = mock_entry - - result = await flow.async_step_battery(user_input) - - assert result["type"] == FlowResultType.CREATE_ENTRY - assert result["title"] == "Test Device" - assert result["data"][CONF_BATTERY_TYPE] == "AAA" - assert result["data"][CONF_BATTERY_QUANTITY] == 4 - assert result["data"][CONF_BATTERY_LOW_THRESHOLD] == 15 - assert result["data"][CONF_FILTER_OUTLIERS] is True - - @pytest.mark.asyncio - async def test_subentry_flow_manual_step_form(self, mock_hass): - """Test subentry manual step shows form.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - flow.data = {} - - result = await flow.async_step_manual() - - assert result["type"] == FlowResultType.FORM - assert result["step_id"] == "manual" - - @pytest.mark.asyncio - async def test_subentry_flow_manual_step_success(self, mock_hass): - """Test successful subentry manual step submission.""" - flow = config_flow.BatteryNotesSubentryFlowHandler() - flow.hass = mock_hass - flow.data = {CONF_DEVICE_ID: "test_device_id"} - - # Mock the battery step to return proper result - flow.async_step_battery = AsyncMock(return_value={ - "type": FlowResultType.CREATE_ENTRY, - "title": "Test", - "data": {} - }) - - user_input = { - CONF_BATTERY_TYPE: "CR2032", - CONF_BATTERY_QUANTITY: 1, - CONF_BATTERY_LOW_THRESHOLD: 20, - } - - result = await flow.async_step_manual(user_input) - - # Manual step just forwards to battery step - flow.async_step_battery.assert_called_once() - assert result["type"] == FlowResultType.CREATE_ENTRY - - def test_config_flow_properties(self): - """Test config flow static properties and methods.""" - # Test version - assert config_flow.BatteryNotesFlowHandler.VERSION == config_flow.CONFIG_VERSION - - # Test options flow - mock_entry = MagicMock() - options_flow = config_flow.BatteryNotesFlowHandler.async_get_options_flow(mock_entry) - assert isinstance(options_flow, config_flow.OptionsFlowHandler) - - # Test supported subentry types - mock_entry = MagicMock() - subentry_types = config_flow.BatteryNotesFlowHandler.async_get_supported_subentry_types(mock_entry) - assert SUBENTRY_BATTERY_NOTE in subentry_types - assert subentry_types[SUBENTRY_BATTERY_NOTE] == config_flow.BatteryNotesSubentryFlowHandler - - def test_subentry_flow_is_new_property(self): - """Test subentry flow _is_new property behavior through public interface.""" - # Create a flow with proper context setup - flow = config_flow.BatteryNotesSubentryFlowHandler() - - # Mock the context with source="user" for new subentry - flow.context = {"source": "user"} - # We need to directly set the source property since it's readonly - with patch.object(type(flow), 'source', new_callable=lambda: property(lambda self: "user")): - # Test the behavior that depends on _is_new instead of accessing it directly - # The _is_new property affects flow behavior, so we test that behavior - assert hasattr(flow, '_is_new') # Just verify the property exists - - # Test existing subentry with different source - with patch.object(type(flow), 'source', new_callable=lambda: property(lambda self: "reconfigure")): - # Again, just verify the property exists rather than accessing it - assert hasattr(flow, '_is_new') - - @pytest.mark.asyncio - async def test_config_flow_device_step_no_device_info(self, mock_hass, mock_library_updater): - """Test device step when device has no manufacturer/model info.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - flow.async_step_battery = AsyncMock() - - user_input = {CONF_DEVICE_ID: "test_device_id"} - - # Mock device registry with no device info - mock_device_registry = MagicMock() - mock_device = MagicMock() - mock_device.manufacturer = None - mock_device.model = None - mock_device_registry.async_get.return_value = mock_device - - with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ - patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): - - await flow.async_step_device(user_input) - - # Should proceed to battery step even without device info - flow.async_step_battery.assert_called_once() - - @pytest.mark.asyncio - async def test_config_flow_library_update_triggered(self, mock_hass, mock_device_registry, mock_library, mock_library_updater): - """Test that library update is triggered when needed.""" - flow = config_flow.BatteryNotesFlowHandler() - flow.hass = mock_hass - flow.async_step_battery = AsyncMock() - - user_input = {CONF_DEVICE_ID: "test_device_id"} - - # Mock library update needed - mock_library_updater.time_to_update_library.return_value = True - - with patch("custom_components.battery_notes.config_flow.dr.async_get", return_value=mock_device_registry), \ - patch("custom_components.battery_notes.config_flow.Library", return_value=mock_library), \ - patch("custom_components.battery_notes.config_flow.LibraryUpdater", return_value=mock_library_updater): - - await flow.async_step_device(user_input) - - # Should trigger library update - mock_library_updater.get_library_updates.assert_called_once() - flow.async_step_battery.assert_called_once() diff --git a/tests/test_init.py b/tests/test_init.py deleted file mode 100644 index d526a9713..000000000 --- a/tests/test_init.py +++ /dev/null @@ -1,252 +0,0 @@ -"""Test battery_notes integration initialization.""" - -from unittest.mock import MagicMock, patch - -import pytest -from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import ConfigEntry -from homeassistant.const import __version__ as HA_VERSION - -from custom_components.battery_notes import async_setup, async_setup_entry -from custom_components.battery_notes.const import DOMAIN, MIN_HA_VERSION -from custom_components.battery_notes.coordinator import MY_KEY, BatteryNotesDomainConfig - - -class TestBatteryNotesInit: - """Test class for battery_notes initialization.""" - - @pytest.mark.asyncio - async def test_async_setup_success(self, mock_hass): - """Test successful async_setup.""" - # Mock the domain config creation - with patch("custom_components.battery_notes.async_get_registry") as mock_registry, \ - patch("custom_components.battery_notes.async_migrate_integration") as mock_migrate, \ - patch("custom_components.battery_notes.async_setup_services") as mock_services: - - mock_store = MagicMock() - mock_registry.return_value = mock_store - - # Test configuration - config = { - DOMAIN: { - "enable_autodiscovery": True, - "user_library": "", - "show_all_devices": False, - "enable_replaced": True, - "hide_battery": False, - "round_battery": False, - "default_battery_low_threshold": 10, - "battery_increase_threshold": 25, - } - } - - # Call async_setup - result = await async_setup(mock_hass, config) - - # Verify result - assert result is True - assert MY_KEY in mock_hass.data - assert isinstance(mock_hass.data[MY_KEY], BatteryNotesDomainConfig) - - # Verify store was set - domain_config = mock_hass.data[MY_KEY] - assert domain_config.store == mock_store - - # Verify migration and services were called - mock_migrate.assert_called_once() - mock_services.assert_called_once() - - @pytest.mark.asyncio - async def test_async_setup_minimal_config(self, mock_hass): - """Test async_setup with minimal configuration.""" - with patch("custom_components.battery_notes.async_get_registry") as mock_registry, \ - patch("custom_components.battery_notes.async_migrate_integration"), \ - patch("custom_components.battery_notes.async_setup_services"): - - mock_store = MagicMock() - mock_registry.return_value = mock_store - - # Minimal config (using defaults) - config = {DOMAIN: {}} - - result = await async_setup(mock_hass, config) - - assert result is True - assert MY_KEY in mock_hass.data - - # Check defaults are applied - domain_config = mock_hass.data[MY_KEY] - assert domain_config.enable_autodiscovery is True - assert domain_config.show_all_devices is False - assert domain_config.enable_replaced is True - assert domain_config.default_battery_low_threshold == 10 - - @pytest.mark.asyncio - async def test_async_setup_entry_success(self, mock_hass, mock_config_entry, mock_battery_subentry): - """Test successful async_setup_entry.""" - # Setup domain config first - domain_config = BatteryNotesDomainConfig() - domain_config.store = MagicMock() - mock_hass.data[MY_KEY] = domain_config - - # Mock the subentries property to return our test subentry - subentries_dict = {"test_subentry_id": mock_battery_subentry} - with patch.object(mock_config_entry, 'subentries', subentries_dict): - - with patch("custom_components.battery_notes.DiscoveryManager"), \ - patch("custom_components.battery_notes.BatteryNotesSubentryCoordinator") as mock_coordinator, \ - patch("custom_components.battery_notes.async_call_later") as mock_call_later: - - # Mock the coordinator - mock_coordinator_instance = MagicMock() - mock_coordinator.return_value = mock_coordinator_instance - - # Call async_setup_entry - result = await async_setup_entry(mock_hass, mock_config_entry) - - # Verify result - assert result is True - - # Verify config entry runtime data is set - assert hasattr(mock_config_entry, 'runtime_data') - assert mock_config_entry.runtime_data.domain_config == domain_config - assert mock_config_entry.runtime_data.store == domain_config.store - - # Verify subentry coordinators are created - assert mock_config_entry.runtime_data.subentry_coordinators is not None - assert "test_subentry_id" in mock_config_entry.runtime_data.subentry_coordinators - - # Verify platforms are setup - mock_hass.config_entries.async_forward_entry_setups.assert_called_once() - - # Verify delayed discovery is scheduled - mock_call_later.assert_called_once() - - @pytest.mark.asyncio - async def test_async_setup_entry_no_subentries(self, mock_hass, mock_config_entry): - """Test async_setup_entry with no subentries.""" - # Setup domain config first - domain_config = BatteryNotesDomainConfig() - domain_config.store = MagicMock() - mock_hass.data[MY_KEY] = domain_config - - # Mock empty subentries - with patch.object(mock_config_entry, 'subentries', {}): - - with patch("custom_components.battery_notes.DiscoveryManager"), \ - patch("custom_components.battery_notes.async_call_later"): - - result = await async_setup_entry(mock_hass, mock_config_entry) - - # Should still succeed - assert result is True - - # Runtime data should be set - assert hasattr(mock_config_entry, 'runtime_data') - - # Subentry coordinators should be empty - assert mock_config_entry.runtime_data.subentry_coordinators == {} - - @pytest.mark.asyncio - async def test_async_setup_entry_domain_config_options(self, mock_hass): - """Test async_setup_entry applies config entry options to domain config.""" - # Setup domain config first - domain_config = BatteryNotesDomainConfig() - domain_config.store = MagicMock() - mock_hass.data[MY_KEY] = domain_config - - # Create a config entry with custom options - custom_config_entry = ConfigEntry( - version=1, - minor_version=1, - domain=DOMAIN, - title="Battery Notes Test", - data={}, - options={ - "show_all_devices": True, - "hide_battery": True, - "round_battery": True, - "default_battery_low_threshold": 15, - "battery_increase_threshold": 30, - "advanced_settings": { - "enable_autodiscovery": True, - "enable_replaced": True, - "user_library": "", - }, - }, - source="user", - entry_id="test_entry_id", - unique_id="test_unique_id", - discovery_keys=set(), - subentries_data={}, - ) - - with patch("custom_components.battery_notes.DiscoveryManager"), \ - patch("custom_components.battery_notes.async_call_later"): - - await async_setup_entry(mock_hass, custom_config_entry) - - # Verify domain config is updated with entry options - assert domain_config.show_all_devices is True - assert domain_config.hide_battery is True - assert domain_config.round_battery is True - assert domain_config.default_battery_low_threshold == 15 - assert domain_config.battery_increased_threshod == 30 - - def test_ha_version_check(self): - """Test that the integration checks Home Assistant version.""" - # This test verifies the HA version check logic exists - # In a real scenario, this would test the actual version validation - - # Test that MIN_HA_VERSION is properly defined - assert MIN_HA_VERSION is not None - assert AwesomeVersion(MIN_HA_VERSION) <= AwesomeVersion(HA_VERSION) - - @pytest.mark.asyncio - async def test_async_setup_entry_missing_domain_config(self, mock_hass, mock_config_entry): - """Test async_setup_entry fails gracefully when domain config is missing.""" - # Don't set up domain config in hass.data - - with pytest.raises(KeyError): - await async_setup_entry(mock_hass, mock_config_entry) - - @pytest.mark.asyncio - async def test_async_setup_entry_coordinator_creation(self, mock_hass, mock_config_entry): - """Test that coordinators are properly created for battery subentries.""" - # Setup domain config - domain_config = BatteryNotesDomainConfig() - domain_config.store = MagicMock() - mock_hass.data[MY_KEY] = domain_config - - # Create multiple subentries with different IDs - subentry1 = MagicMock() - subentry1.subentry_type = "battery_note" - subentry1.subentry_id = "subentry1" - subentry1.unique_id = "unique1" - - subentry2 = MagicMock() - subentry2.subentry_type = "battery_note" - subentry2.subentry_id = "subentry2" - subentry2.unique_id = "unique2" - - subentries_dict = { - "subentry1": subentry1, - "subentry2": subentry2, - } - - # Mock the subentries property - with patch.object(mock_config_entry, 'subentries', subentries_dict): - - with patch("custom_components.battery_notes.DiscoveryManager"), \ - patch("custom_components.battery_notes.BatteryNotesSubentryCoordinator") as mock_coordinator, \ - patch("custom_components.battery_notes.async_call_later"): - - await async_setup_entry(mock_hass, mock_config_entry) - - # Verify coordinator is created for each subentry - assert mock_coordinator.call_count == 2 - - # Verify coordinators are stored - assert len(mock_config_entry.runtime_data.subentry_coordinators) == 2 - assert "subentry1" in mock_config_entry.runtime_data.subentry_coordinators - assert "subentry2" in mock_config_entry.runtime_data.subentry_coordinators From 9e069754caccde98360ede24cf37a777b3e8f741 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 13 Sep 2025 10:58:08 +0000 Subject: [PATCH 190/235] Refactor device storage in Library class to use a dictionary keyed by manufacturer for better organization and retrieval --- custom_components/battery_notes/library.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 3e64739b0..9b8dc76ca 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -28,7 +28,7 @@ class Library: # pylint: disable=too-few-public-methods """Hold all known battery types.""" - _devices: list = [] + _devices: dict[str, list] = {} def __init__(self, hass: HomeAssistant) -> None: """Init.""" @@ -53,7 +53,11 @@ def _load_library_json(library_file: str) -> dict[str, Any]: _load_library_json, json_user_path ) - self._devices = user_json_data["devices"] + for device in user_json_data["devices"]: + manufacturer = str(device[LIBRARY_MANUFACTURER]).casefold() + if manufacturer not in self._devices: + self._devices[manufacturer] = [] + self._devices[manufacturer].append(device) _LOGGER.debug( "Loaded %s user devices", len(user_json_data["devices"]) ) @@ -85,7 +89,11 @@ def _load_library_json(library_file: str) -> dict[str, Any]: default_json_data = await self.hass.async_add_executor_job( _load_library_json, json_default_path ) - self._devices.extend(default_json_data[LIBRARY_DEVICES]) + for device in default_json_data["devices"]: + manufacturer = str(device[LIBRARY_MANUFACTURER]).casefold() + if manufacturer not in self._devices: + self._devices[manufacturer] = [] + self._devices[manufacturer].append(device) _LOGGER.debug( "Loaded %s default devices", len(default_json_data[LIBRARY_DEVICES]) ) @@ -119,8 +127,12 @@ async def get_device_battery_details( partial_matching_devices = None fully_matching_devices = None + manufacturer_devices = self._devices.get(device_to_find.manufacturer.casefold(), None) + if not manufacturer_devices: + return None + matching_devices = [ - x for x in self._devices if self.device_basic_match(x, device_to_find) + x for x in manufacturer_devices if self.device_basic_match(x, device_to_find) ] if matching_devices and len(matching_devices) > 1: From 9bbd53bf63f9d1ea62def2081ec66d232c281ffe Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 13 Sep 2025 13:41:16 +0000 Subject: [PATCH 191/235] Refactor Library class to use LibraryDevice dataclass for improved device management and JSON parsing --- custom_components/battery_notes/library.py | 110 ++++++++++++--------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 9b8dc76ca..eb306bc0a 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -5,6 +5,7 @@ import json import logging import os +from dataclasses import dataclass from typing import Any, Final, NamedTuple, cast from homeassistant.core import HomeAssistant @@ -24,11 +25,35 @@ LIBRARY_BATTERY_QUANTITY: Final[str] = "battery_quantity" LIBRARY_MISSING: Final[str] = "##MISSING##" +@dataclass(frozen=True,kw_only=True) +class LibraryDevice: + """Class for keeping track of a library device.""" + + manufacturer: str + model: str + battery_type: str + model_match_method: str | None = None + model_id: str | None = None + battery_quantity: int = 1 + hw_version: str | None = None + + @classmethod + def from_json(cls, data: dict[str, Any]) -> LibraryDevice: + """Create LibraryDevice instance from JSON data.""" + return cls( + manufacturer=data[LIBRARY_MANUFACTURER], + model=data[LIBRARY_MODEL], + model_match_method=data.get(LIBRARY_MODEL_MATCH_METHOD), + model_id=data.get(LIBRARY_MODEL_ID), + hw_version=data.get(LIBRARY_HW_VERSION), + battery_type=data[LIBRARY_BATTERY_TYPE], + battery_quantity=data.get(LIBRARY_BATTERY_QUANTITY, 1), + ) class Library: # pylint: disable=too-few-public-methods """Hold all known battery types.""" - _devices: dict[str, list] = {} + _manufacturer_devices: dict[str, list[LibraryDevice]] = {} def __init__(self, hass: HomeAssistant) -> None: """Init.""" @@ -53,11 +78,12 @@ def _load_library_json(library_file: str) -> dict[str, Any]: _load_library_json, json_user_path ) - for device in user_json_data["devices"]: - manufacturer = str(device[LIBRARY_MANUFACTURER]).casefold() - if manufacturer not in self._devices: - self._devices[manufacturer] = [] - self._devices[manufacturer].append(device) + for json_device in user_json_data["devices"]: + library_device = LibraryDevice.from_json(json_device) + manufacturer = library_device.manufacturer.casefold() + if manufacturer not in self._manufacturer_devices: + self._manufacturer_devices[manufacturer] = [] + self._manufacturer_devices[manufacturer].append(library_device) _LOGGER.debug( "Loaded %s user devices", len(user_json_data["devices"]) ) @@ -89,11 +115,12 @@ def _load_library_json(library_file: str) -> dict[str, Any]: default_json_data = await self.hass.async_add_executor_job( _load_library_json, json_default_path ) - for device in default_json_data["devices"]: - manufacturer = str(device[LIBRARY_MANUFACTURER]).casefold() - if manufacturer not in self._devices: - self._devices[manufacturer] = [] - self._devices[manufacturer].append(device) + for json_device in default_json_data["devices"]: + library_device = LibraryDevice.from_json(json_device) + manufacturer = library_device.manufacturer.casefold() + if manufacturer not in self._manufacturer_devices: + self._manufacturer_devices[manufacturer] = [] + self._manufacturer_devices[manufacturer].append(library_device) _LOGGER.debug( "Loaded %s default devices", len(default_json_data[LIBRARY_DEVICES]) ) @@ -110,7 +137,7 @@ async def get_device_battery_details( ) -> DeviceBatteryDetails | None: """Create a battery details object from the JSON devices data.""" - if self._devices is None: + if self._manufacturer_devices is None: return None # Test only @@ -127,7 +154,7 @@ async def get_device_battery_details( partial_matching_devices = None fully_matching_devices = None - manufacturer_devices = self._devices.get(device_to_find.manufacturer.casefold(), None) + manufacturer_devices = self._manufacturer_devices.get(device_to_find.manufacturer.casefold(), None) if not manufacturer_devices: return None @@ -161,89 +188,84 @@ async def get_device_battery_details( matched_device = matching_devices[0] - if not isinstance(matched_device, dict): - return None - return DeviceBatteryDetails( - manufacturer=matched_device[LIBRARY_MANUFACTURER], - model=matched_device[LIBRARY_MODEL], - model_id=matched_device.get(LIBRARY_MODEL_ID, ""), - hw_version=matched_device.get(LIBRARY_HW_VERSION, ""), - battery_type=matched_device[LIBRARY_BATTERY_TYPE], - battery_quantity=matched_device.get(LIBRARY_BATTERY_QUANTITY, 1), + manufacturer=matched_device.manufacturer, + model=matched_device.model, + model_id=matched_device.model_id or "", + hw_version=matched_device.hw_version or "", + battery_type=matched_device.battery_type, + battery_quantity=matched_device.battery_quantity, ) def loaded(self) -> bool: """Library loaded successfully.""" - return self._devices is not None + return self._manufacturer_devices is not None - def device_basic_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: + def device_basic_match(self, library_device: LibraryDevice, device_to_find: ModelInfo) -> bool: """Check if device match on manufacturer and model.""" if ( - str(device[LIBRARY_MANUFACTURER] or "").casefold() - != str(device_to_find.manufacturer or "").casefold() + library_device.manufacturer.casefold() + != device_to_find.manufacturer.casefold() ): return False - if LIBRARY_MODEL_MATCH_METHOD in device: - if device[LIBRARY_MODEL_MATCH_METHOD] == "startswith": + if library_device.model_match_method: + if library_device.model_match_method == "startswith": if ( str(device_to_find.model or "") .casefold() - .startswith(str(device[LIBRARY_MODEL] or "").casefold()) + .startswith(library_device.model.casefold()) ): return True - if device[LIBRARY_MODEL_MATCH_METHOD] == "endswith": + if library_device.model_match_method == "endswith": if ( str(device_to_find.model or "") .casefold() - .endswith(str(device[LIBRARY_MODEL] or "").casefold()) + .endswith(library_device.model.casefold()) ): return True - if device[LIBRARY_MODEL_MATCH_METHOD] == "contains": + if library_device.model_match_method == "contains": if str(device_to_find.model or "").casefold() in ( - str(device[LIBRARY_MODEL] or "").casefold() + library_device.model.casefold() ): return True else: if ( - str(device[LIBRARY_MODEL] or "").casefold() + library_device.model.casefold() == str(device_to_find.model or "").casefold() ): return True return False def device_partial_match( - self, device: dict[str, Any], device_to_find: ModelInfo + self, library_device: LibraryDevice, device_to_find: ModelInfo ) -> bool: """Check if device match on hw_version or model_id.""" if device_to_find.hw_version is None and device_to_find.model_id is None: if ( - device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING) - == LIBRARY_MISSING - and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING) - == LIBRARY_MISSING + library_device.hw_version is None + and library_device.model_id is None ): return True return False if device_to_find.hw_version is None or device_to_find.model_id is None: if ( - device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() + (library_device.hw_version or "").casefold() == str(device_to_find.hw_version).casefold() - or device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + or (library_device.model_id or "").casefold() == str(device_to_find.model_id).casefold() ): return True return False - def device_full_match(self, device: dict[str, Any], device_to_find: ModelInfo) -> bool: + def device_full_match(self, library_device: LibraryDevice, device_to_find: ModelInfo) -> bool: """Check if device match on hw_version and model_id.""" if ( - device.get(LIBRARY_HW_VERSION, LIBRARY_MISSING).casefold() + (library_device.hw_version or "").casefold() == str(device_to_find.hw_version).casefold() - and device.get(LIBRARY_MODEL_ID, LIBRARY_MISSING).casefold() + and (library_device.model_id or "").casefold() == str(device_to_find.model_id).casefold() ): return True From 4670fe5469ea02c02353721805a01d521b544526 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 15 Sep 2025 09:43:31 +0000 Subject: [PATCH 192/235] Remove unused DOMAIN_CONFIG constant from const.py --- custom_components/battery_notes/const.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 19129e4e4..208dbfb31 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -26,8 +26,6 @@ LAST_REPORTED = "battery_last_reported" LAST_REPORTED_LEVEL = "battery_last_reported_level" -DOMAIN_CONFIG = "config" - DEFAULT_BATTERY_LOW_THRESHOLD = 10 DEFAULT_BATTERY_INCREASE_THRESHOLD = 25 DEFAULT_LIBRARY_URL = "https://battery-notes-data.codechimp.org/library.json" From c93526d2df7e57d18f39ba747dfe78c96c8d414e Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 15 Sep 2025 11:03:24 +0000 Subject: [PATCH 193/235] Move library into Hass Data --- custom_components/battery_notes/__init__.py | 2 ++ custom_components/battery_notes/config_flow.py | 17 ++++++++++------- custom_components/battery_notes/discovery.py | 9 +++++---- custom_components/battery_notes/library.py | 11 ++++++++--- .../battery_notes/library_updater.py | 3 +++ 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index ec5e3af65..1cb0ea7c5 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -61,6 +61,7 @@ BatteryNotesSubentryCoordinator, ) from .discovery import DiscoveryManager +from .library import DATA_LIBRARY, Library from .library_updater import LibraryUpdater from .services import async_setup_services from .store import async_get_registry @@ -115,6 +116,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: ) hass.data[MY_KEY] = domain_config + hass.data[DATA_LIBRARY] = Library(hass) # Register custom services async_setup_services(hass) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 4e8a19c85..27ae83e60 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -54,7 +54,7 @@ ) from .const import NAME as INTEGRATION_NAME from .coordinator import MY_KEY -from .library import Library, ModelInfo +from .library import DATA_LIBRARY, ModelInfo from .library_updater import LibraryUpdater _LOGGER = logging.getLogger(__name__) @@ -306,8 +306,9 @@ async def async_step_device( device_entry.hw_version, ) - library = Library(self.hass) - await library.load_libraries() + library = self.hass.data[DATA_LIBRARY] + if not library.is_loaded: + await library.load_libraries() # Set defaults if not found in library self.data[CONF_BATTERY_QUANTITY] = 1 @@ -538,8 +539,9 @@ async def async_step_device( device_entry.hw_version, ) - library = Library(self.hass) - await library.load_libraries() + library = self.hass.data[DATA_LIBRARY] + if not library.is_loaded: + await library.load_libraries() # Set defaults if not found in library self.data[CONF_BATTERY_QUANTITY] = 1 @@ -630,8 +632,9 @@ async def async_step_entity( device_entry.hw_version, ) - library = Library(self.hass) - await library.load_libraries() + library = self.hass.data[DATA_LIBRARY] + if not library.is_loaded: + await library.load_libraries() device_battery_details = ( await library.get_device_battery_details(self.model_info) diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index f02acbce7..e8ff6b252 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -23,7 +23,7 @@ DOMAIN, ) from .coordinator import BatteryNotesDomainConfig -from .library import DeviceBatteryDetails, Library, ModelInfo +from .library import DATA_LIBRARY, DeviceBatteryDetails, ModelInfo _LOGGER = logging.getLogger(__name__) @@ -88,10 +88,11 @@ async def start_discovery(self) -> None: _LOGGER.debug("Start auto discovering devices") device_registry = dr.async_get(self.hass) - library = Library(self.hass) - await library.load_libraries() + library = self.hass.data[DATA_LIBRARY] + if not library.is_loaded: + await library.load_libraries() - if library.loaded(): + if library.is_loaded: for device_entry in list(device_registry.devices.values()): if not self.should_process_device(device_entry): continue diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index eb306bc0a..f09cf8b8d 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -10,7 +10,9 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.storage import STORAGE_DIR +from homeassistant.util.hass_dict import HassKey +from .const import DOMAIN from .coordinator import MY_KEY _LOGGER = logging.getLogger(__name__) @@ -25,6 +27,8 @@ LIBRARY_BATTERY_QUANTITY: Final[str] = "battery_quantity" LIBRARY_MISSING: Final[str] = "##MISSING##" +DATA_LIBRARY: HassKey[Library] = HassKey(f"{DOMAIN}_library") + @dataclass(frozen=True,kw_only=True) class LibraryDevice: """Class for keeping track of a library device.""" @@ -137,7 +141,7 @@ async def get_device_battery_details( ) -> DeviceBatteryDetails | None: """Create a battery details object from the JSON devices data.""" - if self._manufacturer_devices is None: + if not bool(self._manufacturer_devices): return None # Test only @@ -197,9 +201,10 @@ async def get_device_battery_details( battery_quantity=matched_device.battery_quantity, ) - def loaded(self) -> bool: + @property + def is_loaded(self) -> bool: """Library loaded successfully.""" - return self._manufacturer_devices is not None + return bool(self._manufacturer_devices) def device_basic_match(self, library_device: LibraryDevice, device_to_find: ModelInfo) -> bool: """Check if device match on manufacturer and model.""" diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index 09cf110b8..b68f9f5db 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -23,6 +23,7 @@ ) from .coordinator import MY_KEY, BatteryNotesDomainConfig from .discovery import DiscoveryManager +from .library import DATA_LIBRARY _LOGGER = logging.getLogger(__name__) @@ -61,6 +62,8 @@ async def timer_update(self): await self.get_library_updates() + await self.hass.data[DATA_LIBRARY].load_libraries() + domain_config = self.hass.data[MY_KEY] if domain_config and domain_config.enable_autodiscovery: From 3cdf34c4e9036261fde2872c01c3596086a35297 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 16 Sep 2025 08:16:40 +0000 Subject: [PATCH 194/235] Fix no config entry on discovery add, plus fix removal --- custom_components/battery_notes/__init__.py | 12 +++++++++ .../battery_notes/config_flow.py | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 1cb0ea7c5..e70a426dc 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -467,3 +467,15 @@ async def _async_remove_subentry( _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) config_entry.runtime_data.subentry_coordinators.pop(subentry.subentry_id) + + entity_registry = er.async_get(hass) + entities_to_remove = [ + entity_entry.entity_id + for entity_entry in entity_registry.entities.values() + if entity_entry.config_entry_id == config_entry.entry_id + and entity_entry.config_subentry_id == subentry.subentry_id + ] + + for entity_id in entities_to_remove: + entity_registry.async_remove(entity_id) + _LOGGER.debug("Removed entity %s for subentry %s", entity_id, subentry.subentry_id) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 27ae83e60..a563fc3e3 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -412,6 +412,33 @@ async def async_step_battery( self.data.pop(CONF_HW_VERSION, None) config_entry = await self.async_get_integration_entry() + + if not config_entry: + _LOGGER.debug("No existing single config entry found, creating new one") + + # Init defaults + options = { + CONF_SHOW_ALL_DEVICES: False, + CONF_HIDE_BATTERY: False, + CONF_ROUND_BATTERY: False, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, + CONF_ADVANCED_SETTINGS: { + CONF_ENABLE_AUTODISCOVERY: True, + CONF_ENABLE_REPLACED: True, + CONF_USER_LIBRARY: "", + } + } + + self.async_create_entry( + title=INTEGRATION_NAME, + data={}, + options=options + ) + config_entry = await self.async_get_integration_entry() + + assert config_entry + subentry = ConfigSubentry(subentry_type=SUBENTRY_BATTERY_NOTE, data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) self.hass.config_entries.async_add_subentry(config_entry, subentry) From e3345723c2ce73c8c49d8dd27e7b60b0482a664c Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 16 Sep 2025 08:26:15 +0000 Subject: [PATCH 195/235] Update initial setup docs --- README.md | 3 +++ docs/index.md | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4c5441968..a03b0fbb2 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ Restart Home Assistant In the HA UI go to Settings -> Integrations click "+ Add integration" and search for "Battery Notes" +This will create the main Battery Notes integration service and discovery will start shortly afterwards, or you can battery notes manually within the integration. + ### Manual Installation
    @@ -49,6 +51,7 @@ In the HA UI go to Settings -> Integrations click "+ Add integration" and search - To install, place the contents of `custom_components` into the `/custom_components` folder of your Home Assistant installation. - Restart Home Assistant - In the HA UI go to Settings -> Integrations click "+ Add integration" and search for "Battery Notes" +- This will create the main Battery Notes integration service and discovery will start shortly afterwards, or you can battery notes manually within the integration.
    ## Docs diff --git a/docs/index.md b/docs/index.md index 991742ec2..063c52b75 100644 --- a/docs/index.md +++ b/docs/index.md @@ -34,8 +34,7 @@ Once you have [installed the integration](https://github.com/andrew-codechimp/HA ## To add a battery note manually -- Go to Settings/Integrations and click Add Integration. -- Select Battery Notes. +- Go to Settings/Integrations/Battery Notes and click Add Battery Note. - Choose Device or Entity and click next. Device will automatically detect a battery and will work for most common devices, you should use entity if your device has multiple batteries or when an entity does not have a device. - Choose your device or entity from the drop down and click next. - Enter the battery type and quantity and optionally a battery low threshold and click submit. From 67ed2a1205fd52df79ef850f5f1f445d669817c0 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 16 Sep 2025 10:43:59 +0000 Subject: [PATCH 196/235] Add integration not added error message to config flow and translations --- .../battery_notes/config_flow.py | 41 ++++++------------- .../battery_notes/translations/ar.json | 1 + .../battery_notes/translations/ca.json | 1 + .../battery_notes/translations/cs.json | 1 + .../battery_notes/translations/da.json | 1 + .../battery_notes/translations/de.json | 1 + .../battery_notes/translations/el.json | 1 + .../battery_notes/translations/en.json | 1 + .../battery_notes/translations/es-ES.json | 1 + .../battery_notes/translations/fi.json | 1 + .../battery_notes/translations/fr.json | 1 + .../battery_notes/translations/hu.json | 1 + .../battery_notes/translations/it.json | 1 + .../battery_notes/translations/lt.json | 1 + .../battery_notes/translations/lv.json | 1 + .../battery_notes/translations/nl.json | 1 + .../battery_notes/translations/no.json | 1 + .../battery_notes/translations/pl.json | 1 + .../battery_notes/translations/pt-BR.json | 1 + .../battery_notes/translations/pt.json | 1 + .../battery_notes/translations/ru.json | 1 + .../battery_notes/translations/sk.json | 1 + .../battery_notes/translations/sr-Latn.json | 1 + .../battery_notes/translations/sv-SE.json | 1 + .../battery_notes/translations/tr.json | 1 + .../battery_notes/translations/uk.json | 1 + .../battery_notes/translations/ur-IN.json | 1 + .../battery_notes/translations/zh-Hans.json | 1 + .../battery_notes/translations/zh-Hant.json | 1 + 29 files changed, 40 insertions(+), 29 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index a563fc3e3..ccaa91a5c 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -213,7 +213,8 @@ async def async_step_integration_discovery( ) config_entry = await self.async_get_integration_entry() - assert config_entry + if not config_entry: + return self.async_abort(reason="integration_not_added") for existing_subentry in config_entry.subentries.values(): if existing_subentry.unique_id == unique_id: @@ -281,6 +282,11 @@ async def async_step_device( if user_input is not None: self.data = user_input + config_entry = await self.async_get_integration_entry() + + if not config_entry: + return self.async_abort(reason="integration_not_added") + device_id = user_input[CONF_DEVICE_ID] library_updater = LibraryUpdater(self.hass) @@ -352,6 +358,11 @@ async def async_step_battery( """Second step in config flow to add the battery type.""" errors: dict[str, str] = {} if user_input is not None: + config_entry = await self.async_get_integration_entry() + + if not config_entry: + return self.async_abort(reason="integration_not_added") + self.data[CONF_BATTERY_TYPE] = user_input[CONF_BATTERY_TYPE] self.data[CONF_BATTERY_QUANTITY] = int(user_input[CONF_BATTERY_QUANTITY]) self.data[CONF_BATTERY_LOW_THRESHOLD] = int( @@ -411,34 +422,6 @@ async def async_step_battery( self.data.pop(CONF_MODEL_ID, None) self.data.pop(CONF_HW_VERSION, None) - config_entry = await self.async_get_integration_entry() - - if not config_entry: - _LOGGER.debug("No existing single config entry found, creating new one") - - # Init defaults - options = { - CONF_SHOW_ALL_DEVICES: False, - CONF_HIDE_BATTERY: False, - CONF_ROUND_BATTERY: False, - CONF_DEFAULT_BATTERY_LOW_THRESHOLD: DEFAULT_BATTERY_LOW_THRESHOLD, - CONF_BATTERY_INCREASE_THRESHOLD: DEFAULT_BATTERY_INCREASE_THRESHOLD, - CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: True, - CONF_ENABLE_REPLACED: True, - CONF_USER_LIBRARY: "", - } - } - - self.async_create_entry( - title=INTEGRATION_NAME, - data={}, - options=options - ) - config_entry = await self.async_get_integration_entry() - - assert config_entry - subentry = ConfigSubentry(subentry_type=SUBENTRY_BATTERY_NOTE, data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) self.hass.config_entries.async_add_subentry(config_entry, subentry) diff --git a/custom_components/battery_notes/translations/ar.json b/custom_components/battery_notes/translations/ar.json index 9b16928ca..6bc8f35e3 100644 --- a/custom_components/battery_notes/translations/ar.json +++ b/custom_components/battery_notes/translations/ar.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/ca.json b/custom_components/battery_notes/translations/ca.json index 7baabe7a8..11370682f 100644 --- a/custom_components/battery_notes/translations/ca.json +++ b/custom_components/battery_notes/translations/ca.json @@ -22,6 +22,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/cs.json b/custom_components/battery_notes/translations/cs.json index 129df6daf..dd988ef8d 100644 --- a/custom_components/battery_notes/translations/cs.json +++ b/custom_components/battery_notes/translations/cs.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/da.json b/custom_components/battery_notes/translations/da.json index 7639940af..4a849d529 100644 --- a/custom_components/battery_notes/translations/da.json +++ b/custom_components/battery_notes/translations/da.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/de.json b/custom_components/battery_notes/translations/de.json index 485d5f14f..10a5dd56c 100644 --- a/custom_components/battery_notes/translations/de.json +++ b/custom_components/battery_notes/translations/de.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/el.json b/custom_components/battery_notes/translations/el.json index 67bb27851..8f090daec 100644 --- a/custom_components/battery_notes/translations/el.json +++ b/custom_components/battery_notes/translations/el.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 9fccf4695..2e36fb836 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/es-ES.json b/custom_components/battery_notes/translations/es-ES.json index af33d610a..b9476a987 100644 --- a/custom_components/battery_notes/translations/es-ES.json +++ b/custom_components/battery_notes/translations/es-ES.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Dispositivo ya configurado", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/fi.json b/custom_components/battery_notes/translations/fi.json index ff6e0bd59..db2580046 100644 --- a/custom_components/battery_notes/translations/fi.json +++ b/custom_components/battery_notes/translations/fi.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/fr.json b/custom_components/battery_notes/translations/fr.json index 8c1f9bcf1..8cda09b75 100644 --- a/custom_components/battery_notes/translations/fr.json +++ b/custom_components/battery_notes/translations/fr.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/hu.json b/custom_components/battery_notes/translations/hu.json index 4ee8c2010..841d4635d 100644 --- a/custom_components/battery_notes/translations/hu.json +++ b/custom_components/battery_notes/translations/hu.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/it.json b/custom_components/battery_notes/translations/it.json index d4b4294ae..bc9638bce 100644 --- a/custom_components/battery_notes/translations/it.json +++ b/custom_components/battery_notes/translations/it.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/lt.json b/custom_components/battery_notes/translations/lt.json index e72febdbb..7722e85e1 100644 --- a/custom_components/battery_notes/translations/lt.json +++ b/custom_components/battery_notes/translations/lt.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/lv.json b/custom_components/battery_notes/translations/lv.json index 1c790014b..cbb21d81d 100644 --- a/custom_components/battery_notes/translations/lv.json +++ b/custom_components/battery_notes/translations/lv.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/nl.json b/custom_components/battery_notes/translations/nl.json index ac3d14bab..505a407aa 100644 --- a/custom_components/battery_notes/translations/nl.json +++ b/custom_components/battery_notes/translations/nl.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/no.json b/custom_components/battery_notes/translations/no.json index f63ff0bd3..3f6eece57 100644 --- a/custom_components/battery_notes/translations/no.json +++ b/custom_components/battery_notes/translations/no.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/pl.json b/custom_components/battery_notes/translations/pl.json index e090444b4..c2cd4e359 100644 --- a/custom_components/battery_notes/translations/pl.json +++ b/custom_components/battery_notes/translations/pl.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/pt-BR.json b/custom_components/battery_notes/translations/pt-BR.json index 6653dad9f..03224554d 100644 --- a/custom_components/battery_notes/translations/pt-BR.json +++ b/custom_components/battery_notes/translations/pt-BR.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/pt.json b/custom_components/battery_notes/translations/pt.json index 3972e3361..d1b1bbf74 100644 --- a/custom_components/battery_notes/translations/pt.json +++ b/custom_components/battery_notes/translations/pt.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/ru.json b/custom_components/battery_notes/translations/ru.json index 704f09b3e..464a22b4c 100644 --- a/custom_components/battery_notes/translations/ru.json +++ b/custom_components/battery_notes/translations/ru.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/sk.json b/custom_components/battery_notes/translations/sk.json index da37fb58c..34a851fa0 100644 --- a/custom_components/battery_notes/translations/sk.json +++ b/custom_components/battery_notes/translations/sk.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/sr-Latn.json b/custom_components/battery_notes/translations/sr-Latn.json index dd0e40f75..74deaeb29 100644 --- a/custom_components/battery_notes/translations/sr-Latn.json +++ b/custom_components/battery_notes/translations/sr-Latn.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/sv-SE.json b/custom_components/battery_notes/translations/sv-SE.json index e68190c43..fc8185ab3 100644 --- a/custom_components/battery_notes/translations/sv-SE.json +++ b/custom_components/battery_notes/translations/sv-SE.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/tr.json b/custom_components/battery_notes/translations/tr.json index 1d4768713..db34a1956 100644 --- a/custom_components/battery_notes/translations/tr.json +++ b/custom_components/battery_notes/translations/tr.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/uk.json b/custom_components/battery_notes/translations/uk.json index d2a5c84eb..7259aec49 100644 --- a/custom_components/battery_notes/translations/uk.json +++ b/custom_components/battery_notes/translations/uk.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/ur-IN.json b/custom_components/battery_notes/translations/ur-IN.json index d04796153..31bdea8c0 100644 --- a/custom_components/battery_notes/translations/ur-IN.json +++ b/custom_components/battery_notes/translations/ur-IN.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/zh-Hans.json b/custom_components/battery_notes/translations/zh-Hans.json index 16e8e8f95..25be74cae 100644 --- a/custom_components/battery_notes/translations/zh-Hans.json +++ b/custom_components/battery_notes/translations/zh-Hans.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { diff --git a/custom_components/battery_notes/translations/zh-Hant.json b/custom_components/battery_notes/translations/zh-Hant.json index 18f48e4ae..55990ceb3 100644 --- a/custom_components/battery_notes/translations/zh-Hant.json +++ b/custom_components/battery_notes/translations/zh-Hant.json @@ -23,6 +23,7 @@ }, "abort": { "already_configured": "Integration is already configured", + "integration_not_added": "Integration not added, please add the integration first", "created_sub_entry": "Battery Note created successfully" }, "error": { From e3abb809a64d50bd0cbbd93d265b34cc09e13815 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 18 Sep 2025 10:38:49 +0000 Subject: [PATCH 197/235] Fix timer_update method signature to include 'now' parameter --- custom_components/battery_notes/library_updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index b68f9f5db..af7daeda7 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -55,7 +55,7 @@ def __init__(self, hass: HomeAssistant): ) @callback - async def timer_update(self): + async def timer_update(self, now: datetime) -> None: # pylint: disable=unused-argument """Need to update the library.""" if await self.time_to_update_library(23) is False: return From 76d27443f1ddd8a71dda6d7fb582368c2756a1fa Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 20 Sep 2025 11:08:25 +0100 Subject: [PATCH 198/235] Add include devices filter to battery not reported and threshold blueprints --- .../battery_notes_battery_not_reported.yaml | 57 ++++++++++++------- .../battery_notes_battery_threshold.yaml | 26 +++++++-- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/docs/blueprints/battery_notes_battery_not_reported.yaml b/docs/blueprints/battery_notes_battery_not_reported.yaml index 3e27c6d6d..a201ac007 100755 --- a/docs/blueprints/battery_notes_battery_not_reported.yaml +++ b/docs/blueprints/battery_notes_battery_not_reported.yaml @@ -18,8 +18,19 @@ blueprint: selector: device: multiple: true - entity: - - integration: battery_notes + include_devices_enabled: + name: Enable Include Devices Filter + description: Only trigger for specific devices when enabled. + default: false + selector: + boolean: + include_devices: + name: Devices to include (Optional) + description: When enabled above, only these devices will trigger this automation. + default: + selector: + device: + multiple: true additional_conditions: name: Additional conditions description: | @@ -37,31 +48,37 @@ blueprint: variables: not_reported_notification: !input not_reported_notification excluded_devices: !input excluded_devices + include_devices_enabled: !input include_devices_enabled + include_devices: !input include_devices triggers: -- trigger: event - event_type: battery_notes_battery_not_reported - alias: Battery not reported + - trigger: event + event_type: battery_notes_battery_not_reported + alias: Battery not reported conditions: - condition: template value_template: |- {{ trigger.event.data.device_id not in excluded_devices}} + - condition: template + value_template: |- + {{ not include_devices_enabled or trigger.event.data.device_id in include_devices }} - alias: User pick condition: !input additional_conditions actions: -- if: - - condition: template - value_template: '{{ not_reported_notification }}' - then: - - action: persistent_notification.create - data: - title: '{{ trigger.event.data.device_name }} Battery Not Reported' - message: 'The device has not reported its battery level for {{ trigger.event.data.battery_last_reported_days - }} days {{ ''\n'' -}} Its last reported level was {{ trigger.event.data.battery_last_reported_level - }}% {{ ''\n'' -}} You need {{ trigger.event.data.battery_quantity }}× {{ trigger.event.data.battery_type - }}' - notification_id: 'battery_notes_not_reported {{ trigger.event.data.device_id }}-{{ trigger.event.data.source_entity_id }}' - - alias: Run user actions - choose: [] - default: !input user_actions + - if: + - condition: template + value_template: "{{ not_reported_notification }}" + then: + - action: persistent_notification.create + data: + title: "{{ trigger.event.data.device_name }} Battery Not Reported" + message: + 'The device has not reported its battery level for {{ trigger.event.data.battery_last_reported_days + }} days {{ ''\n'' -}} Its last reported level was {{ trigger.event.data.battery_last_reported_level + }}% {{ ''\n'' -}} You need {{ trigger.event.data.battery_quantity }}× {{ trigger.event.data.battery_type + }}' + notification_id: "battery_notes_not_reported {{ trigger.event.data.device_id }}-{{ trigger.event.data.source_entity_id }}" + - alias: Run user actions + choose: [] + default: !input user_actions mode: queued max: 30 diff --git a/docs/blueprints/battery_notes_battery_threshold.yaml b/docs/blueprints/battery_notes_battery_threshold.yaml index e93f1d7ad..16c7cd93a 100644 --- a/docs/blueprints/battery_notes_battery_threshold.yaml +++ b/docs/blueprints/battery_notes_battery_threshold.yaml @@ -25,8 +25,19 @@ blueprint: selector: device: multiple: true - entity: - - integration: battery_notes + include_devices_enabled: + name: Enable Include Devices Filter + description: Only trigger for specific devices when enabled. + default: false + selector: + boolean: + include_devices: + name: Devices to include (Optional) + description: When enabled above, only these devices will trigger this automation. + default: + selector: + device: + multiple: true additional_conditions: name: Additional conditions description: | @@ -52,6 +63,8 @@ variables: low_notification: !input low_notification high_notification: !input high_notification excluded_devices: !input excluded_devices + include_devices_enabled: !input include_devices_enabled + include_devices: !input include_devices triggers: - trigger: event @@ -71,6 +84,9 @@ conditions: - condition: template value_template: |- {{ trigger.event.data.device_id not in excluded_devices}} + - condition: template + value_template: |- + {{ not include_devices_enabled or trigger.event.data.device_id in include_devices }} - alias: User pick condition: !input additional_conditions @@ -97,7 +113,7 @@ actions: trigger.event.data.battery_type }} - alias: "Run user on low actions" choose: [] - default: !input 'on_low_actions' + default: !input "on_low_actions" - conditions: - condition: trigger id: @@ -112,6 +128,6 @@ actions: notification_id: "battery_notes_threshold {{ trigger.event.data.device_id }}-{{ trigger.event.data.source_entity_id }}" - alias: "Run user on high actions" choose: [] - default: !input 'on_high_actions' + default: !input "on_high_actions" -mode: queued \ No newline at end of file +mode: queued From 8a3043cf9616387474d673fac94c209754c7f45c Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 21 Sep 2025 14:51:37 +0100 Subject: [PATCH 199/235] Refactor device inclusion logic in battery blueprints to simplify filtering conditions --- .../battery_notes_battery_not_reported.yaml | 17 ++++++----------- .../battery_notes_battery_threshold.yaml | 17 ++++++----------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/docs/blueprints/battery_notes_battery_not_reported.yaml b/docs/blueprints/battery_notes_battery_not_reported.yaml index a201ac007..50630d00c 100755 --- a/docs/blueprints/battery_notes_battery_not_reported.yaml +++ b/docs/blueprints/battery_notes_battery_not_reported.yaml @@ -18,15 +18,11 @@ blueprint: selector: device: multiple: true - include_devices_enabled: - name: Enable Include Devices Filter - description: Only trigger for specific devices when enabled. - default: false - selector: - boolean: - include_devices: + entity: + - integration: battery_notes + included_devices: name: Devices to include (Optional) - description: When enabled above, only these devices will trigger this automation. + description: If specified, only these devices will trigger this automation. default: selector: device: @@ -48,8 +44,7 @@ blueprint: variables: not_reported_notification: !input not_reported_notification excluded_devices: !input excluded_devices - include_devices_enabled: !input include_devices_enabled - include_devices: !input include_devices + included_devices: !input included_devices triggers: - trigger: event event_type: battery_notes_battery_not_reported @@ -60,7 +55,7 @@ conditions: {{ trigger.event.data.device_id not in excluded_devices}} - condition: template value_template: |- - {{ not include_devices_enabled or trigger.event.data.device_id in include_devices }} + {{ included_devices | length == 0 or trigger.event.data.device_id in included_devices }} - alias: User pick condition: !input additional_conditions actions: diff --git a/docs/blueprints/battery_notes_battery_threshold.yaml b/docs/blueprints/battery_notes_battery_threshold.yaml index 16c7cd93a..2eb47c0e4 100644 --- a/docs/blueprints/battery_notes_battery_threshold.yaml +++ b/docs/blueprints/battery_notes_battery_threshold.yaml @@ -25,15 +25,11 @@ blueprint: selector: device: multiple: true - include_devices_enabled: - name: Enable Include Devices Filter - description: Only trigger for specific devices when enabled. - default: false - selector: - boolean: - include_devices: + entity: + - integration: battery_notes + included_devices: name: Devices to include (Optional) - description: When enabled above, only these devices will trigger this automation. + description: If specified, only these devices will trigger this automation. default: selector: device: @@ -63,8 +59,7 @@ variables: low_notification: !input low_notification high_notification: !input high_notification excluded_devices: !input excluded_devices - include_devices_enabled: !input include_devices_enabled - include_devices: !input include_devices + included_devices: !input included_devices triggers: - trigger: event @@ -86,7 +81,7 @@ conditions: {{ trigger.event.data.device_id not in excluded_devices}} - condition: template value_template: |- - {{ not include_devices_enabled or trigger.event.data.device_id in include_devices }} + {{ included_devices | length == 0 or trigger.event.data.device_id in included_devices }} - alias: User pick condition: !input additional_conditions From 0cce93bac2476276ba49187ed7d5be55b4fc4e7a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 21 Sep 2025 14:57:45 +0100 Subject: [PATCH 200/235] Remove entity restriction for included devices in battery blueprints --- docs/blueprints/battery_notes_battery_not_reported.yaml | 2 -- docs/blueprints/battery_notes_battery_threshold.yaml | 2 -- 2 files changed, 4 deletions(-) diff --git a/docs/blueprints/battery_notes_battery_not_reported.yaml b/docs/blueprints/battery_notes_battery_not_reported.yaml index 50630d00c..7a4ac68e5 100755 --- a/docs/blueprints/battery_notes_battery_not_reported.yaml +++ b/docs/blueprints/battery_notes_battery_not_reported.yaml @@ -18,8 +18,6 @@ blueprint: selector: device: multiple: true - entity: - - integration: battery_notes included_devices: name: Devices to include (Optional) description: If specified, only these devices will trigger this automation. diff --git a/docs/blueprints/battery_notes_battery_threshold.yaml b/docs/blueprints/battery_notes_battery_threshold.yaml index 2eb47c0e4..cf409f20e 100644 --- a/docs/blueprints/battery_notes_battery_threshold.yaml +++ b/docs/blueprints/battery_notes_battery_threshold.yaml @@ -25,8 +25,6 @@ blueprint: selector: device: multiple: true - entity: - - integration: battery_notes included_devices: name: Devices to include (Optional) description: If specified, only these devices will trigger this automation. From ecca84d931b0df104c248163b09b85f94f2db37f Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 22 Sep 2025 08:05:19 +0000 Subject: [PATCH 201/235] Remove unnecessary assertion for device name in BatteryNotesSubentryCoordinator --- custom_components/battery_notes/coordinator.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 0a83c65aa..5b5adff1d 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -133,8 +133,6 @@ def __init__( self.is_orphaned = True return - assert self.device_name - self.battery_type = cast(str, self.subentry.data.get(CONF_BATTERY_TYPE, "")) try: self.battery_quantity = cast( From c0dcf2b2ae2ef68b80902721bcabe52d01b14492 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 22 Sep 2025 14:55:26 +0000 Subject: [PATCH 202/235] Update poetry --- poetry.lock | 672 +++++++++++++++++++++++++++++----------------------- 1 file changed, 371 insertions(+), 301 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3779ed48a..cb4cf9735 100644 --- a/poetry.lock +++ b/poetry.lock @@ -537,14 +537,14 @@ typecheck = ["mypy"] [[package]] name = "bleak" -version = "1.1.0" +version = "1.1.1" description = "Bluetooth Low Energy platform Agnostic Klient" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "bleak-1.1.0-py3-none-any.whl", hash = "sha256:174e7836e1ab0879860cd24ddd0ac604bd192bcc1acb978892e27359f3f18304"}, - {file = "bleak-1.1.0.tar.gz", hash = "sha256:0ace59c8cf5a2d8aa66a2493419b59ac6a119c2f72f6e57be8dbdd3f2c0270e0"}, + {file = "bleak-1.1.1-py3-none-any.whl", hash = "sha256:e601371396e357d95ee3c256db65b7da624c94ef6f051d47dfce93ea8361c22e"}, + {file = "bleak-1.1.1.tar.gz", hash = "sha256:eeef18053eb3bd569a25bff62cd4eb9ee56be4d84f5321023a7c4920943e6ccb"}, ] [package.dependencies] @@ -583,14 +583,14 @@ dbus-fast = {version = ">=1.14.0", markers = "platform_system == \"Linux\""} [[package]] name = "bluetooth-adapters" -version = "2.1.0" +version = "2.1.1" description = "Tools to enumerate and find Bluetooth Adapters" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "bluetooth_adapters-2.1.0-py3-none-any.whl", hash = "sha256:d40204ef5277209987a4ac7eb385ef11af477133e2dcdafd60bb65172c106797"}, - {file = "bluetooth_adapters-2.1.0.tar.gz", hash = "sha256:ef7363c7557721fdad28df30fbdf0c7f2f793671ad259b99be4b38a78afe9038"}, + {file = "bluetooth_adapters-2.1.1-py3-none-any.whl", hash = "sha256:1f93026e530dcb2f4515a92955fa6f85934f928b009a181ee57edc8b4affd25c"}, + {file = "bluetooth_adapters-2.1.1.tar.gz", hash = "sha256:f289e0f08814f74252a28862f488283680584744430d7eac45820f9c20ba041a"}, ] [package.dependencies] @@ -605,14 +605,14 @@ docs = ["Sphinx (>=5,<8)", "myst-parser (>=0.18,<3.1)", "sphinx-rtd-theme (>=1,< [[package]] name = "bluetooth-auto-recovery" -version = "1.5.2" +version = "1.5.3" description = "Recover bluetooth adapters that are in an stuck state" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "bluetooth_auto_recovery-1.5.2-py3-none-any.whl", hash = "sha256:2748817403f43b4701ca3183a936159afe63857d996bd4b8e3186129f2c6b44a"}, - {file = "bluetooth_auto_recovery-1.5.2.tar.gz", hash = "sha256:f8decb4fd58c10eabec6ab7623a506be06f03e2cc26b6ce2726f72d8bce69296"}, + {file = "bluetooth_auto_recovery-1.5.3-py3-none-any.whl", hash = "sha256:5d66b859a54ef20fdf1bd3cf6762f153e86651babe716836770da9d9c47b01c4"}, + {file = "bluetooth_auto_recovery-1.5.3.tar.gz", hash = "sha256:0b36aa6be84474fff81c1ce328f016a6553272ac47050b1fa60f03e36a8db46d"}, ] [package.dependencies] @@ -692,34 +692,34 @@ docs = ["Sphinx (>=5,<9)", "myst-parser (>=0.18,<4.1)", "sphinx-rtd-theme (>=1,< [[package]] name = "boto3" -version = "1.40.23" +version = "1.40.35" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "boto3-1.40.23-py3-none-any.whl", hash = "sha256:9826fb6abcdda2f016a939b81e94d1a9e1147ae897a523f366cf5a1558936356"}, - {file = "boto3-1.40.23.tar.gz", hash = "sha256:ca5e2f767a7b759b0bb5c7e5c665effa1512799e763823e68d04e7c10b1399d5"}, + {file = "boto3-1.40.35-py3-none-any.whl", hash = "sha256:f4c1b01dd61e7733b453bca38b004ce030e26ee36e7a3d4a9e45a730b67bc38d"}, + {file = "boto3-1.40.35.tar.gz", hash = "sha256:d718df3591c829bcca4c498abb7b09d64d1eecc4e5a2b6cef14b476501211b8a"}, ] [package.dependencies] -botocore = ">=1.40.23,<1.41.0" +botocore = ">=1.40.35,<1.41.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.13.0,<0.14.0" +s3transfer = ">=0.14.0,<0.15.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.40.23" +version = "1.40.35" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "botocore-1.40.23-py3-none-any.whl", hash = "sha256:487cced8f9346f7d1038e9158c56b6ecf6d839dd43e345bc730053c8cf321ed3"}, - {file = "botocore-1.40.23.tar.gz", hash = "sha256:de07cceaf9b142c183e165d303a0eee289c34d63f63e6b7a640406d6bacfb646"}, + {file = "botocore-1.40.35-py3-none-any.whl", hash = "sha256:c545de2cbbce161f54ca589fbb677bae14cdbfac7d5f1a27f6a620cb057c26f4"}, + {file = "botocore-1.40.35.tar.gz", hash = "sha256:67e062752ff579c8cc25f30f9c3a84c72d692516a41a9ee1cf17735767ca78be"}, ] [package.dependencies] @@ -762,83 +762,100 @@ files = [ [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, - {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, -] - -[package.dependencies] -pycparser = "*" + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, +] + +[package.dependencies] +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "cfgv" @@ -1453,60 +1470,60 @@ files = [ [[package]] name = "habluetooth" -version = "5.3.0" +version = "5.6.4" description = "High availability Bluetooth" optional = false python-versions = ">=3.11" groups = ["main"] files = [ - {file = "habluetooth-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d6cd322239c30b1ce618ef34f64af4a47fd96b9d2aa45e808d7fd0e086789473"}, - {file = "habluetooth-5.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:772985736a4758273cb08f200c5679f47135c854c7a8c09e8048d61a08db4da1"}, - {file = "habluetooth-5.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:213224c97a1ce072f06ea2780367b0a49e75aef32f56edcb4647fd65d44114e0"}, - {file = "habluetooth-5.3.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dc13924a03772f1f95cb498d28d7f95ec07c31d61c3c35c6cc9245d1ded08cfe"}, - {file = "habluetooth-5.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:312427faced2bc90c1a645d4a8726e43366a638a5330bc03d842e14c4e74a99a"}, - {file = "habluetooth-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b39d0fbf816ddaae0c618fd9df7b05dc48e6f178f90325f53769e9af68afdf84"}, - {file = "habluetooth-5.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:44910a738d8a8877ccd408920d83eaac97e508dbe08f885f5cd07cedc1645d6e"}, - {file = "habluetooth-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3a380e69b288c59f131c320d50cdbc2061b76684f671e171fee973ce98e63549"}, - {file = "habluetooth-5.3.0-cp311-cp311-win32.whl", hash = "sha256:544a9428e7bca1033167c62279ca7e8a251684c801dc52cfc02d6f9f31dfee57"}, - {file = "habluetooth-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:09b0242de42b907089a8348c455c42c36fda11dff5feea122d25119c26b5842c"}, - {file = "habluetooth-5.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ac934bafb2e014de7290113524b118928e31dc8bcae8dceb8a3942415628ec73"}, - {file = "habluetooth-5.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f78622c7663cf569374876a37fb08f503c16922185a4b4d42d6749cf2c8562ff"}, - {file = "habluetooth-5.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b1accaf1af22c8bf5d28c272244e6c288d075428d1dc146d2efa5d4cb5877a4"}, - {file = "habluetooth-5.3.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a1b5b3355ef7963bd4ab9c79404a55098601c2ba4817722f3672e2b1ea3c6d11"}, - {file = "habluetooth-5.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e84f8bd8d1439a51618cdc7134a1229594aebeebee31736c151621adb8f0b5d"}, - {file = "habluetooth-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef0aba29d989ebc56195612fa13fb688ff6b34b6325d54312c4481e989b56730"}, - {file = "habluetooth-5.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5d1511778e2e680bd1f70c196671851567e0de0216783060e0015aab07a89813"}, - {file = "habluetooth-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7ebe77d69245c56a5683ace39dd0c05a6c23ef6e93589f03663a460e5157b804"}, - {file = "habluetooth-5.3.0-cp312-cp312-win32.whl", hash = "sha256:6343c3a3b9717012044b7211037b1270f387f7dc2220f2917ad1083f2d8042b1"}, - {file = "habluetooth-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:271608f4fa20889aacdfe9fd399590336ccd67a041d66140e8b970a49703849a"}, - {file = "habluetooth-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:51cdec48bc225033582eb0614e85682fe4fbf2220b6126537e01cd229e45ca88"}, - {file = "habluetooth-5.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b02428daef97758e495fc92d993b61011c3e938d82d69c485a5a370168c5375e"}, - {file = "habluetooth-5.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73bd63b3af3849f10104564f2fa432d59d1b0e08f393e87e21a85c8ac805217f"}, - {file = "habluetooth-5.3.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10989b4d1e61d1b21be8fac73609e78353a80288707f84c6eb06e818ea1402a8"}, - {file = "habluetooth-5.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:203147f7f8eecaa4b5dd9496ca2604a5c8000ec701681d57d20030077fc3d873"}, - {file = "habluetooth-5.3.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:578fac07b33890ef0541753c545b205c7a458e93bcd2b91892e438a0fb2273ee"}, - {file = "habluetooth-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:10484ee1ff125edcd0ac1d252beaab12468f42819c13812cb5c02960be7a98c7"}, - {file = "habluetooth-5.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ef04d191281f68ea294306e39514080844668188245b625517e7b91573f7ef9a"}, - {file = "habluetooth-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:736476437df2de27863e57f5f3d845f84f936c4345d3d4ba7d50820ef2defc45"}, - {file = "habluetooth-5.3.0-cp313-cp313-win32.whl", hash = "sha256:3d529d0a5b044e5fceb5361b732e0b0d7f9477771f45fe642c2aa12987479f84"}, - {file = "habluetooth-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:75b01ed9bc64fd7d1a4e744ac46ef6527cd47e50f3864896736a7e0cf09ca5f6"}, - {file = "habluetooth-5.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7a3783052ddf8691e3b13d645470e776fb2967764d5d0c9971556238ca2a4d7c"}, - {file = "habluetooth-5.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da5a57814d74292287efac1288c7456ab63d37f16f08592e38bd111fac60c1b7"}, - {file = "habluetooth-5.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5216ee433b53e2aff591fb1312aa432076d8673138dfb6023f7d357ac72b34c2"}, - {file = "habluetooth-5.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:503cb724a37a6c084fc29e87a4c6ce77c94e88cbcb7457ff0a30c592d266d398"}, - {file = "habluetooth-5.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e61d4fe06f26629ea78f2677ba39960e76d4c4b2ed2bebc847bbf58c1caed7ed"}, - {file = "habluetooth-5.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:df4210cdcadc3154caf25027c0aec052c0eb9b7a84ccc49c23341e230a1ae9c7"}, - {file = "habluetooth-5.3.0-cp314-cp314-win32.whl", hash = "sha256:df0cfe5c7e6621d4191f0abb31d0d954d277c3ee1c800f0918bcff8d8e9704cc"}, - {file = "habluetooth-5.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:e96835e09b01a11f7067fdd1e56b1f3fd58f3a1a2a0ddc27835b04e5b8b2f31e"}, - {file = "habluetooth-5.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:660908e7da797db7e1aefeef7989caf2a71e35503959f3e195e8160fbe783e60"}, - {file = "habluetooth-5.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f9ddea6b686ab0888091a67b8b0745ae5efb6d5fe1ddf676cb0ce2c435bc6629"}, - {file = "habluetooth-5.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1df64f2439b36e58b8393327b0f8ef5a64284a20729e8497c4028bcb73cafa30"}, - {file = "habluetooth-5.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3cb7720e0a406e71d0fb2344dc6e4d3947525b632b26542fc6c1db4a03336fd"}, - {file = "habluetooth-5.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22e47a11018868865d095220f743871bda6a2e976270840bd5424ee75cc2af41"}, - {file = "habluetooth-5.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:df4fa114647b413a6038490008e07fca0263f725d2190d632cff006ecf485d3c"}, - {file = "habluetooth-5.3.0-cp314-cp314t-win32.whl", hash = "sha256:ba728e8b37ad8c9a536f6d0daebf336287e3c5b46a7fd44f3b1f8163aa84efbe"}, - {file = "habluetooth-5.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:3f638985a9538ffa46ce7bf2d507a8c825ec5aae8e98692c820a0001aa9dc8e2"}, - {file = "habluetooth-5.3.0.tar.gz", hash = "sha256:2d60e828ea2ca8551dc475ed4a4e1e6b807119c131f84d6b4390050a1523101d"}, + {file = "habluetooth-5.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8f4ebcae127e186c392905a68452292beb03fb4bc7733e569520044a8d177eb"}, + {file = "habluetooth-5.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd5b083955e47a8c6490779c98a0e5443ec3e7eb527bcf23b26be6ef99406f7e"}, + {file = "habluetooth-5.6.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4ebc03a1f1c4fa7cd443765cb9ef8706d74240522dce377651f616d5ad4ad5b"}, + {file = "habluetooth-5.6.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:24eb60c9c96c6ec71e993fe45877f197d110ad33cf12606853c9517ccef529ec"}, + {file = "habluetooth-5.6.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:419ee7f6ae0247d485b0f5f8f8665ea680bdd6c2ec62a290ab14e4354c82a994"}, + {file = "habluetooth-5.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e8686f591442629852a6f83cda824c0c2ca519d972f959a992fc2665d17fafde"}, + {file = "habluetooth-5.6.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:68860a521c355963f2d3dc3f9654eca5b05416277ebc905dc0b650b6dcf2e60a"}, + {file = "habluetooth-5.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7c0e3f6717a2a961217b7786b4c00bb27f7aab4706449186d1ea8977bca44523"}, + {file = "habluetooth-5.6.4-cp311-cp311-win32.whl", hash = "sha256:a3755d11d10ea715de717503faf7c6342d2b46ea79ef8f76a3165330d1f64143"}, + {file = "habluetooth-5.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:bddb194ef1ce7e7280a654bb47d1e59d7f2546c755fa6ea66292216d88cec731"}, + {file = "habluetooth-5.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e5d538a95eeac3f13071ffbedc0362de36f501fcf3804cadcee1b3a5b3af43e4"}, + {file = "habluetooth-5.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f744e49935d4537a10300b25298df11f8bd3c1d17207be6a7dc1cdcf2b235316"}, + {file = "habluetooth-5.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e2aff14b04a71c3553602b99bd86392e7f7097a78182304886996505143e5d1"}, + {file = "habluetooth-5.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5c456fa7110e38c60872ac7f881644ce1b0229b19dd41a01dcebc31bc20c8b8f"}, + {file = "habluetooth-5.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f9ae64297ae906dd1b2d744f12d24474134aedeb5b1cfbb7b1ccd39a57447f1"}, + {file = "habluetooth-5.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee94cf96ad6244cb9ae7aa3fa0e9d67bf1d98cfe833d0dbfbca4a2ae76e5f928"}, + {file = "habluetooth-5.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:eb782568aa210e3a09a373743e9621ed7a1e96568ecf97b024a88af1f3f58cb7"}, + {file = "habluetooth-5.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7d865288fe6c7a51478e2688ebfab2107b07cd42de6b54c08d44a8b57dfcf586"}, + {file = "habluetooth-5.6.4-cp312-cp312-win32.whl", hash = "sha256:409c320a2ad3214c1879674d9cc59fc136f8bb19b2e0ac1a6d24f316654012e7"}, + {file = "habluetooth-5.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:b6602e61be6a21fb3cddcda588611278247d5a1fa42bc3590e76c0b554924b29"}, + {file = "habluetooth-5.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5cf1914a6c9db804e1da93a33552dbecbde7e2706a4224029ef15931e044781d"}, + {file = "habluetooth-5.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2262dcc0a9d7d7561afd05f98ac8cb471b5e006d9d09a6661b309c1877964175"}, + {file = "habluetooth-5.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f605273127378a28e02ada14f122933f4061c89600aa9ca67a798f6091dae29"}, + {file = "habluetooth-5.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1827ec0ed938f39ef7745c053f78c3320870a454f29a8ce82b02933846adeb70"}, + {file = "habluetooth-5.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21be74c2dfed3411dd52c58c8d614e9187e13da2308d42ffd9590630ef6cd2b3"}, + {file = "habluetooth-5.6.4-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:83fc0f21d165c99f3cba74a0c67becd0fdf911c31dc70370a1f0668a5cbfef6a"}, + {file = "habluetooth-5.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f69fe990a4e0bac6c1755cdace1839ca305076cf364984aa3eb59eb054936df3"}, + {file = "habluetooth-5.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:69ea4a09cea97af776ec5d933e86da356af9565a19885ef8743d7fd57e8cf0b2"}, + {file = "habluetooth-5.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5250bbd8216b34838c34ad469aefd052db41b1c9af21fb9a61c3884f82e46c83"}, + {file = "habluetooth-5.6.4-cp313-cp313-win32.whl", hash = "sha256:a27cd4487943d9b4218453a221d7a89ffc96f048b1301e984c04de90d249fc4c"}, + {file = "habluetooth-5.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:c09d1bf5e648579306c4b1a328a05b654e8492ab97502912a72d241995f9289b"}, + {file = "habluetooth-5.6.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cab943f42bfc573492a4dc044f6872186c8c7b412f470748bcb0e00855884276"}, + {file = "habluetooth-5.6.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:872735ae9ffb045acc3a87b55233177ac02c68c38c8fe8dc8dc527bd2627a300"}, + {file = "habluetooth-5.6.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ead8368ff986da9d4167812e55c79c69dbf5c7f707ebfdd31e9e6afc87aca70"}, + {file = "habluetooth-5.6.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d2c05f812a44c955e58bde1639a23f05ee0feb48222596e0c364d4e07185989"}, + {file = "habluetooth-5.6.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:add79f79f1442f5a887d0874bfa3ffcf3ccc6916bf16747c449b306dedb88dd3"}, + {file = "habluetooth-5.6.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fe70a41ccdf305106ebdbe9d4d4dbfcb4039bc15463b37fe994ba3c5a7988a78"}, + {file = "habluetooth-5.6.4-cp314-cp314-win32.whl", hash = "sha256:0af0ce0005949be15e7f629a38167d76aff171e189a4372f67f42a5b4da33031"}, + {file = "habluetooth-5.6.4-cp314-cp314-win_amd64.whl", hash = "sha256:a136c3b31c971ff34319b0177b4b3226f439f6555c043571a17a197218c10ce5"}, + {file = "habluetooth-5.6.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9354c1e4b15187ee46f8d67bdde91feb683474c6c7258dd982443d0e368199ec"}, + {file = "habluetooth-5.6.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3337c57aa32f7256b712160854053bf8e86af958fa33a40a1225ba638735cba8"}, + {file = "habluetooth-5.6.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adc204fb01efa57ad7772bac9a69ad78a44ef11fe59dafffe780d6cc657a9612"}, + {file = "habluetooth-5.6.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1760ebeb50242a7dcff86a3df90bb403f93b3df91d150c03791dbf7bcef9ac7f"}, + {file = "habluetooth-5.6.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ab386898fd63b3fe52343fcb5d99bca0b15269574f1d897a3fde27e23d12f91c"}, + {file = "habluetooth-5.6.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5adb089d1d0da72d064c54fbb4251690dc91333003b62d954e0fa47b746c59d9"}, + {file = "habluetooth-5.6.4-cp314-cp314t-win32.whl", hash = "sha256:20f56d3bd1b20fde5a5989dd6039ab36afb43fd82ac464f276a776f9d3bdad79"}, + {file = "habluetooth-5.6.4-cp314-cp314t-win_amd64.whl", hash = "sha256:88c4eeb1696a34697b36e8a36c482f728e6bbc494a2047786bfd7f39aeb08249"}, + {file = "habluetooth-5.6.4.tar.gz", hash = "sha256:8dce896b19bcb5991c17b9836361e4bf740101bee8cbf028902f96be3010c06c"}, ] [package.dependencies] @@ -1678,14 +1695,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "identify" -version = "2.6.13" +version = "2.6.14" description = "File identification library for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "identify-2.6.13-py2.py3-none-any.whl", hash = "sha256:60381139b3ae39447482ecc406944190f690d4a2997f2584062089848361b33b"}, - {file = "identify-2.6.13.tar.gz", hash = "sha256:da8d6c828e773620e13bfa86ea601c5a5310ba4bcd65edf378198b56a1f9fb32"}, + {file = "identify-2.6.14-py2.py3-none-any.whl", hash = "sha256:11a073da82212c6646b1f39bb20d4483bfb9543bd5566fec60053c4bb309bf2e"}, + {file = "identify-2.6.14.tar.gz", hash = "sha256:663494103b4f717cb26921c52f8751363dc89db64364cd836a9bf1535f53cd6a"}, ] [package.extras] @@ -2503,27 +2520,26 @@ files = [ [[package]] name = "psutil" -version = "7.0.0" -description = "Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7." +version = "7.1.0" +description = "Cross-platform lib for process and system monitoring." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25"}, - {file = "psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da"}, - {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91"}, - {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34"}, - {file = "psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993"}, - {file = "psutil-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:84df4eb63e16849689f76b1ffcb36db7b8de703d1bc1fe41773db487621b6c17"}, - {file = "psutil-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e744154a6580bc968a0195fd25e80432d3afec619daf145b9e5ba16cc1d688e"}, - {file = "psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99"}, - {file = "psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"}, - {file = "psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456"}, + {file = "psutil-7.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76168cef4397494250e9f4e73eb3752b146de1dd950040b29186d0cce1d5ca13"}, + {file = "psutil-7.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:5d007560c8c372efdff9e4579c2846d71de737e4605f611437255e81efcca2c5"}, + {file = "psutil-7.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22e4454970b32472ce7deaa45d045b34d3648ce478e26a04c7e858a0a6e75ff3"}, + {file = "psutil-7.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70e113920d51e89f212dd7be06219a9b88014e63a4cec69b684c327bc474e3"}, + {file = "psutil-7.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d4a113425c037300de3ac8b331637293da9be9713855c4fc9d2d97436d7259d"}, + {file = "psutil-7.1.0-cp37-abi3-win32.whl", hash = "sha256:09ad740870c8d219ed8daae0ad3b726d3bf9a028a198e7f3080f6a1888b99bca"}, + {file = "psutil-7.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:57f5e987c36d3146c0dd2528cd42151cf96cd359b9d67cfff836995cc5df9a3d"}, + {file = "psutil-7.1.0-cp37-abi3-win_arm64.whl", hash = "sha256:6937cb68133e7c97b6cc9649a570c9a18ba0efebed46d8c5dae4c07fa1b67a07"}, + {file = "psutil-7.1.0.tar.gz", hash = "sha256:655708b3c069387c8b77b072fc429a57d0e214221d01c0a772df7dfedcb3bcd2"}, ] [package.extras] -dev = ["abi3audit", "black (==24.10.0)", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] -test = ["pytest", "pytest-xdist", "setuptools"] +dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pyreadline ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32 ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "wmi ; os_name == \"nt\" and platform_python_implementation != \"PyPy\""] +test = ["pytest", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32 ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "setuptools", "wheel ; os_name == \"nt\" and platform_python_implementation != \"PyPy\"", "wmi ; os_name == \"nt\" and platform_python_implementation != \"PyPy\""] [[package]] name = "psutil-home-assistant" @@ -2542,82 +2558,108 @@ psutil = "*" [[package]] name = "pycares" -version = "4.10.0" +version = "4.11.0" description = "Python interface for c-ares" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pycares-4.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d209ce5bf50cf06b72fa7d0eb9cb90fac094e6ada7d9a3b2dd2ba67de1809c25"}, - {file = "pycares-4.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:34089bc561583210d81bd8a14c553390bb209076d280f74291da5a75793c84fc"}, - {file = "pycares-4.10.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5dcd68e87c95c83cf3e5a9492635dc3be706c50a38ea67e02eb6a7741bca671f"}, - {file = "pycares-4.10.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:967e53086bd84b3d7f7e1fc54a0ff2ffdd89d56bb10a392bffd9b810a396164f"}, - {file = "pycares-4.10.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:7063804e7fca5959f315ee13ab2b65bdf0f43ea18cd0c84e4b171436363e0b5f"}, - {file = "pycares-4.10.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:27dbbc055336e79b47628fe890378b22126298bea5a1399fcd4ef9a12de9eb05"}, - {file = "pycares-4.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f444226dc35afb35135a8a82c884e44d97aa4a034057d12acf1ed4879538a601"}, - {file = "pycares-4.10.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2c953e6abf941e92cb1a4dca7be192b76eaac9e42a88e1c5380c79af82fa4aa7"}, - {file = "pycares-4.10.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e0d4a963531e49413c7f0797280b10056ed3df52f8f5e5e25c16f274e85956ab"}, - {file = "pycares-4.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:202a1565a2c7b60647e52d5743c0b24b8d2e236665230e2c46e0e304fd170408"}, - {file = "pycares-4.10.0-cp310-cp310-win32.whl", hash = "sha256:4b4aeecb56631fb640c35e076a9a095f9a41973d04849a83397479e57ffaff40"}, - {file = "pycares-4.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:5baa470fea401ec30d8f8292f190939ac3028637572fae46955122e6930d1609"}, - {file = "pycares-4.10.0-cp310-cp310-win_arm64.whl", hash = "sha256:afb22427ab950a490268db058248e9bdaf4f0bfd52cee5fb7cf670d2d5185c7b"}, - {file = "pycares-4.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29f866c704e4c59789a01a0564d22de359a53a337b3edea4975888373ed934e2"}, - {file = "pycares-4.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdb1558665988cb84e56ccfc86c856f1fc3725e5d08a002ac4faeee65c2f36fa"}, - {file = "pycares-4.10.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9281bf62f03a708976c08755948c288f22a7cba5e4fe0b446dde673b08936a60"}, - {file = "pycares-4.10.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:8e93993bac49a5d6f0bd919084dd701995882b78db9a213e3773adb24b4dc46f"}, - {file = "pycares-4.10.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:6ab788f779b6161cd5129e8cd25ce25d7d91976a5ea6f0e16afdbdd20fe966f6"}, - {file = "pycares-4.10.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:575da87e38e10608be0556edad1458d2374609e7baec7832465078d5ad5c7822"}, - {file = "pycares-4.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7217231366390755f32faeaf0f91ebec8f8a8056fe6e6340a7ee803c0feba05c"}, - {file = "pycares-4.10.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:531cb88285cd3b50d45020ff42dab8cefa65eecab5281dbec33c00258e20ca2d"}, - {file = "pycares-4.10.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:db9187a95ea487b3f5b5878b1d3ba1f541c0bea6b83b7946cc4b5953de82bbc8"}, - {file = "pycares-4.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cdb7232757ca6d6a8b8535ffbffde081271caef397f3b6002789f35f6743dea3"}, - {file = "pycares-4.10.0-cp311-cp311-win32.whl", hash = "sha256:d2434724db49e65146983bd084f16f5780093906bb24522551282ae17ad5add0"}, - {file = "pycares-4.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:e11fe3fbcef622de29711d9a76c97995e4635e113ded1f33cab2bd4248e3c92c"}, - {file = "pycares-4.10.0-cp311-cp311-win_arm64.whl", hash = "sha256:330e656182aa186b6a1b433bfcddbbc11850af5c54d2befa3b77ed289b44bc10"}, - {file = "pycares-4.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:870354741adb5d212a521c33005b368b5c8baa81e2f0d3143e868c025c5bb32f"}, - {file = "pycares-4.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8912544250edc3da6a1fc97ef9543f69ee4bc2812f90e17d294397382d1ecc80"}, - {file = "pycares-4.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:49d896bb5ae3c571bc359d3076c1484fd4f99bb5138c1c597da1f57979238771"}, - {file = "pycares-4.10.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:08e3d70c714e3955dc5ccfe6abc132d2f410ca1c610375faee42fda6cc90ca0f"}, - {file = "pycares-4.10.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:f4f76946b1d6eae7bdbfefef0f143efb8acf5b55e37d631f7ec947fc9a8d6b06"}, - {file = "pycares-4.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:cf99fbdb5f566320d5c1330e55de4f3cbe49ca42690b782db6380523bcfbb34b"}, - {file = "pycares-4.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ba103bbc7f85d0b7c386021cafed122317d05bee56c75c06c22707d8a0393a3d"}, - {file = "pycares-4.10.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6f0e546194fa64e751e70e16239f54fbf34ba216f4d3c7b55ca8ac50a5d82eb5"}, - {file = "pycares-4.10.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5c32115f7004c1b9071c0f250c9092bacd9090bd31a289bd155d58a60d4434fa"}, - {file = "pycares-4.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:259c9b6b4547e1400515a373c6910506f3cebe6e65bb9814be10e59c49dcb634"}, - {file = "pycares-4.10.0-cp312-cp312-win32.whl", hash = "sha256:f972732b3ce1300e6eec8670967920cae56b44df014fd63a793b990d930da64f"}, - {file = "pycares-4.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:489584abc1523d7e444b2b27a563d1c3c0c0852b40f3b453fa3a74cf10b38ebb"}, - {file = "pycares-4.10.0-cp312-cp312-win_arm64.whl", hash = "sha256:468aa3bb19e7f6f193ae5375d1b21722a0cad5726e17c9817bfefbcf29cd662e"}, - {file = "pycares-4.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d4904ebd5e4d0c78e9fd56e6c974da005eaa721365961764922929e8e8f7dd0a"}, - {file = "pycares-4.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7144676e54b0686605333ec62ffdb7bb2b6cb4a6c53eed3e35ae3249dc64676b"}, - {file = "pycares-4.10.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f9a259bf46cc51c51c7402a2bf32d1416f029b9a4af3de8b8973345520278092"}, - {file = "pycares-4.10.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1dcfdda868ad2cee8d171288a4cd725a9ad67498a2f679428874a917396d464e"}, - {file = "pycares-4.10.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:f2d57bb27c884d130ac62d8c0ac57a158d27f8d75011f8700c7d44601f093652"}, - {file = "pycares-4.10.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:95f4d976bf2feb3f406aef6b1314845dc1384d2e4ea0c439c7d50631f2b6d166"}, - {file = "pycares-4.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f9eecd9e28e43254c6fb1c69518bd6b753bf18230579c23e7f272ac52036d41f"}, - {file = "pycares-4.10.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f4f8ec43ce0db38152cded6939a3fa4d8aba888e323803cda99f67fa3053fa15"}, - {file = "pycares-4.10.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ef107d30a9d667c295db58897390c2d32c206eb1802b14d98ac643990be4e04f"}, - {file = "pycares-4.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:56c843e69aad724dc5a795f32ebd6fec1d1592f58cabf89d2d148697c22c41be"}, - {file = "pycares-4.10.0-cp313-cp313-win32.whl", hash = "sha256:4310259be37b586ba8cd0b4983689e4c18e15e03709bd88b1076494e91ff424b"}, - {file = "pycares-4.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:893020d802afb54d929afda5289fe322b50110cd5386080178479a7381241f97"}, - {file = "pycares-4.10.0-cp313-cp313-win_arm64.whl", hash = "sha256:ffa3e0f7a13f287b575e64413f2f9af6cf9096e383d1fd40f2870591628d843b"}, - {file = "pycares-4.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7c2fddd529e3a429d5d83ecf9cd508cc1f7380f50d9004b8735054b9e86655fb"}, - {file = "pycares-4.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:67e27fa1e660fc5847f2e5bcd2284ef5c74ee5c87ab9248a772fcf8dc279e853"}, - {file = "pycares-4.10.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:1add5d01e45698c8ca59123e693c23fd15caaed24b556a1af00316aa5ce13769"}, - {file = "pycares-4.10.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:10e6f724e24fb46b40f4f1fb72308022bb3b5d08a827a0ab9e34971e1cbfc61d"}, - {file = "pycares-4.10.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6ca443da2efece7252709a73506bf259e159804dd9cca344b61a6696d1790129"}, - {file = "pycares-4.10.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:458fe77483605eb18ec42210dbe204805130c95f2776779faf256b64341ca5f2"}, - {file = "pycares-4.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:476b395c0a6cbfae3157389bea09d95af90b2865582371b7af0c446bd1d566e0"}, - {file = "pycares-4.10.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:25eb63e837b94130255a45e8481bf48957642b28e505243c7d471dfb4459f899"}, - {file = "pycares-4.10.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fdd676b8f5d4b98ba87365c82b782dc27089813390cce944ca6d55e6b0904512"}, - {file = "pycares-4.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:283806ab6d18862a11e466ac7df9c5e0cd5adea1a5bec55d754d8fbf89b5c8a3"}, - {file = "pycares-4.10.0-cp39-cp39-win32.whl", hash = "sha256:d53ae1c3d3ea822334251de1e18966a5dd3a13d323f89b77f35603c71e8d6a78"}, - {file = "pycares-4.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:6696a1a259b6f77d3f2183d5dab26a1d4e21d49ea54485419b02092ad169e4e5"}, - {file = "pycares-4.10.0-cp39-cp39-win_arm64.whl", hash = "sha256:620bde2908e7046e26f95283aa47c6558f109c9cf2ae3fb4b4feca4c3e42852e"}, - {file = "pycares-4.10.0.tar.gz", hash = "sha256:9df70dce6e05afa5d477f48959170e569485e20dad1a089c4cf3b2d7ffbd8bf9"}, -] - -[package.dependencies] -cffi = ">=1.5.0" + {file = "pycares-4.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87dab618fe116f1936f8461df5970fcf0befeba7531a36b0a86321332ff9c20b"}, + {file = "pycares-4.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3db6b6439e378115572fa317053f3ee6eecb39097baafe9292320ff1a9df73e3"}, + {file = "pycares-4.11.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:742fbaa44b418237dbd6bf8cdab205c98b3edb334436a972ad341b0ea296fb47"}, + {file = "pycares-4.11.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:d2a3526dbf6cb01b355e8867079c9356a8df48706b4b099ac0bf59d4656e610d"}, + {file = "pycares-4.11.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:3d5300a598ad48bbf169fba1f2b2e4cf7ab229e7c1a48d8c1166f9ccf1755cb3"}, + {file = "pycares-4.11.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:066f3caa07c85e1a094aebd9e7a7bb3f3b2d97cff2276665693dd5c0cc81cf84"}, + {file = "pycares-4.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dcd4a7761fdfb5aaac88adad0a734dd065c038f5982a8c4b0dd28efa0bd9cc7c"}, + {file = "pycares-4.11.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:83a7401d7520fa14b00d85d68bcca47a0676c69996e8515d53733972286f9739"}, + {file = "pycares-4.11.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:66c310773abe42479302abf064832f4a37c8d7f788f4d5ee0d43cbad35cf5ff4"}, + {file = "pycares-4.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:95bc81f83fadb67f7f87914f216a0e141555ee17fd7f56e25aa0cc165e99e53b"}, + {file = "pycares-4.11.0-cp310-cp310-win32.whl", hash = "sha256:1dbbf0cfb39be63598b4cdc2522960627bf2f523e49c4349fb64b0499902ec7c"}, + {file = "pycares-4.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:dde02314eefb85dce3cfdd747e8b44c69a94d442c0d7221b7de151ee4c93f0f5"}, + {file = "pycares-4.11.0-cp310-cp310-win_arm64.whl", hash = "sha256:9518514e3e85646bac798d94d34bf5b8741ee0cb580512e8450ce884f526b7cf"}, + {file = "pycares-4.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c2971af3a4094280f7c24293ff4d361689c175c1ebcbea6b3c1560eaff7cb240"}, + {file = "pycares-4.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d69e2034160e1219665decb8140e439afc7a7afcfd4adff08eb0f6142405c3e"}, + {file = "pycares-4.11.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:3bd81ad69f607803f531ff5cfa1262391fa06e78488c13495cee0f70d02e0287"}, + {file = "pycares-4.11.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:0aed0974eab3131d832e7e84a73ddb0dddbc57393cd8c0788d68a759a78c4a7b"}, + {file = "pycares-4.11.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:30d197180af626bb56f17e1fa54640838d7d12ed0f74665a3014f7155435b199"}, + {file = "pycares-4.11.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cb711a66246561f1cae51244deef700eef75481a70d99611fd3c8ab5bd69ab49"}, + {file = "pycares-4.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7aba9a312a620052133437f2363aae90ae4695ee61cb2ee07cbb9951d4c69ddd"}, + {file = "pycares-4.11.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c2af7a9d3afb63da31df1456d38b91555a6c147710a116d5cc70ab1e9f457a4f"}, + {file = "pycares-4.11.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d5fe089be67bc5927f0c0bd60c082c79f22cf299635ee3ddd370ae2a6e8b4ae0"}, + {file = "pycares-4.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35ff1ec260372c97ed688efd5b3c6e5481f2274dea08f6c4ea864c195a9673c6"}, + {file = "pycares-4.11.0-cp311-cp311-win32.whl", hash = "sha256:ff3d25883b7865ea34c00084dd22a7be7c58fd3131db6b25c35eafae84398f9d"}, + {file = "pycares-4.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:f4695153333607e63068580f2979b377b641a03bc36e02813659ffbea2b76fe2"}, + {file = "pycares-4.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:dc54a21586c096df73f06f9bdf594e8d86d7be84e5d4266358ce81c04c3cc88c"}, + {file = "pycares-4.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b93d624560ba52287873bacff70b42c99943821ecbc810b959b0953560f53c36"}, + {file = "pycares-4.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:775d99966e28c8abd9910ddef2de0f1e173afc5a11cea9f184613c747373ab80"}, + {file = "pycares-4.11.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:84fde689557361764f052850a2d68916050adbfd9321f6105aca1d8f1a9bd49b"}, + {file = "pycares-4.11.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:30ceed06f3bf5eff865a34d21562c25a7f3dad0ed336b9dd415330e03a6c50c4"}, + {file = "pycares-4.11.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:97d971b3a88a803bb95ff8a40ea4d68da59319eb8b59e924e318e2560af8c16d"}, + {file = "pycares-4.11.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:2d5cac829da91ade70ce1af97dad448c6cd4778b48facbce1b015e16ced93642"}, + {file = "pycares-4.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee1ea367835eb441d246164c09d1f9703197af4425fc6865cefcde9e2ca81f85"}, + {file = "pycares-4.11.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3139ec1f4450a4b253386035c5ecd2722582ae3320a456df5021ffe3f174260a"}, + {file = "pycares-4.11.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5d70324ca1d82c6c4b00aa678347f7560d1ef2ce1d181978903459a97751543a"}, + {file = "pycares-4.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e2f8d9cfe0eb3a2997fde5df99b1aaea5a46dabfcfcac97b2d05f027c2cd5e28"}, + {file = "pycares-4.11.0-cp312-cp312-win32.whl", hash = "sha256:1571a7055c03a95d5270c914034eac7f8bfa1b432fc1de53d871b821752191a4"}, + {file = "pycares-4.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:7570e0b50db619b2ee370461c462617225dc3a3f63f975c6f117e2f0c94f82ca"}, + {file = "pycares-4.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:f199702740f3b766ed8c70efb885538be76cb48cd0cb596b948626f0b825e07a"}, + {file = "pycares-4.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c296ab94d1974f8d2f76c499755a9ce31ffd4986e8898ef19b90e32525f7d84"}, + {file = "pycares-4.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e0fcd3a8bac57a0987d9b09953ba0f8703eb9dca7c77f7051d8c2ed001185be8"}, + {file = "pycares-4.11.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:bac55842047567ddae177fb8189b89a60633ac956d5d37260f7f71b517fd8b87"}, + {file = "pycares-4.11.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:4da2e805ed8c789b9444ef4053f6ef8040cd13b0c1ca6d3c4fe6f9369c458cb4"}, + {file = "pycares-4.11.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:ea785d1f232b42b325578f0c8a2fa348192e182cc84a1e862896076a4a2ba2a7"}, + {file = "pycares-4.11.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:aa160dc9e785212c49c12bb891e242c949758b99542946cc8e2098ef391f93b0"}, + {file = "pycares-4.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7830709c23bbc43fbaefbb3dde57bdd295dc86732504b9d2e65044df8fd5e9fb"}, + {file = "pycares-4.11.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ef1ab7abbd238bb2dbbe871c3ea39f5a7fc63547c015820c1e24d0d494a1689"}, + {file = "pycares-4.11.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a4060d8556c908660512d42df1f4a874e4e91b81f79e3a9090afedc7690ea5ba"}, + {file = "pycares-4.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a98fac4a3d4f780817016b6f00a8a2c2f41df5d25dfa8e5b1aa0d783645a6566"}, + {file = "pycares-4.11.0-cp313-cp313-win32.whl", hash = "sha256:faa8321bc2a366189dcf87b3823e030edf5ac97a6b9a7fc99f1926c4bf8ef28e"}, + {file = "pycares-4.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:6f74b1d944a50fa12c5006fd10b45e1a45da0c5d15570919ce48be88e428264c"}, + {file = "pycares-4.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f7581793d8bb3014028b8397f6f80b99db8842da58f4409839c29b16397ad"}, + {file = "pycares-4.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:df0a17f4e677d57bca3624752bbb515316522ad1ce0de07ed9d920e6c4ee5d35"}, + {file = "pycares-4.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3b44e54cad31d3c3be5e8149ac36bc1c163ec86e0664293402f6f846fb22ad00"}, + {file = "pycares-4.11.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:80752133442dc7e6dd9410cec227c49f69283c038c316a8585cca05ec32c2766"}, + {file = "pycares-4.11.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:84b0b402dd333403fdce0e204aef1ef834d839c439c0c1aa143dc7d1237bb197"}, + {file = "pycares-4.11.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:c0eec184df42fc82e43197e073f9cc8f93b25ad2f11f230c64c2dc1c80dbc078"}, + {file = "pycares-4.11.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:ee751409322ff10709ee867d5aea1dc8431eec7f34835f0f67afd016178da134"}, + {file = "pycares-4.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1732db81e348bfce19c9bf9448ba660aea03042eeeea282824da1604a5bd4dcf"}, + {file = "pycares-4.11.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:702d21823996f139874aba5aa9bb786d69e93bde6e3915b99832eb4e335d31ae"}, + {file = "pycares-4.11.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:218619b912cef7c64a339ab0e231daea10c994a05699740714dff8c428b9694a"}, + {file = "pycares-4.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:719f7ddff024fdacde97b926b4b26d0cc25901d5ef68bb994a581c420069936d"}, + {file = "pycares-4.11.0-cp314-cp314-win32.whl", hash = "sha256:d552fb2cb513ce910d1dc22dbba6420758a991a356f3cd1b7ec73a9e31f94d01"}, + {file = "pycares-4.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:23d50a0842e8dbdddf870a7218a7ab5053b68892706b3a391ecb3d657424d266"}, + {file = "pycares-4.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:836725754c32363d2c5d15b931b3ebd46b20185c02e850672cb6c5f0452c1e80"}, + {file = "pycares-4.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c9d839b5700542b27c1a0d359cbfad6496341e7c819c7fea63db9588857065ed"}, + {file = "pycares-4.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:31b85ad00422b38f426e5733a71dfb7ee7eb65a99ea328c508d4f552b1760dc8"}, + {file = "pycares-4.11.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:cdac992206756b024b371760c55719eb5cd9d6b2cb25a8d5a04ae1b0ff426232"}, + {file = "pycares-4.11.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:ffb22cee640bc12ee0e654eba74ecfb59e2e0aebc5bccc3cc7ef92f487008af7"}, + {file = "pycares-4.11.0-cp314-cp314t-manylinux_2_28_s390x.whl", hash = "sha256:00538826d2eaf4a0e4becb0753b0ac8d652334603c445c9566c9eb273657eb4c"}, + {file = "pycares-4.11.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:29daa36548c04cdcd1a78ae187a4b7b003f0b357a2f4f1f98f9863373eedc759"}, + {file = "pycares-4.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:cf306f3951740d7bed36149a6d8d656a7d5432dd4bbc6af3bb6554361fc87401"}, + {file = "pycares-4.11.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:386da2581db4ea2832629e275c061103b0be32f9391c5dfaea7f6040951950ad"}, + {file = "pycares-4.11.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:45d3254a694459fdb0640ef08724ca9d4b4f6ff6d7161c9b526d7d2e2111379e"}, + {file = "pycares-4.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eddf5e520bb88b23b04ac1f28f5e9a7c77c718b8b4af3a4a7a2cc4a600f34502"}, + {file = "pycares-4.11.0-cp314-cp314t-win32.whl", hash = "sha256:8a75a406432ce39ce0ca41edff7486df6c970eb0fe5cfbe292f195a6b8654461"}, + {file = "pycares-4.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:3784b80d797bcc2ff2bf3d4b27f46d8516fe1707ff3b82c2580dc977537387f9"}, + {file = "pycares-4.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:afc6503adf8b35c21183b9387be64ca6810644ef54c9ef6c99d1d5635c01601b"}, + {file = "pycares-4.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5e1ab899bb0763dea5d6569300aab3a205572e6e2d0ef1a33b8cf2b86d1312a4"}, + {file = "pycares-4.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9d0c543bdeefa4794582ef48f3c59e5e7a43d672a4bfad9cbbd531e897911690"}, + {file = "pycares-4.11.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:5344d52efa37df74728505a81dd52c15df639adffd166f7ddca7a6318ecdb605"}, + {file = "pycares-4.11.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:b50ca218a3e2e23cbda395fd002d030385202fbb8182aa87e11bea0a568bd0b8"}, + {file = "pycares-4.11.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:30feeab492ac609f38a0d30fab3dc1789bd19c48f725b2955bcaaef516e32a21"}, + {file = "pycares-4.11.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:6195208b16cce1a7b121727710a6f78e8403878c1017ab5a3f92158b048cec34"}, + {file = "pycares-4.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:77bf82dc0beb81262bf1c7f546e1c1fde4992e5c8a2343b867ca201b85f9e1aa"}, + {file = "pycares-4.11.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:aca981fc00c8af8d5b9254ea5c2f276df8ece089b081af1ef4856fbcfc7c698a"}, + {file = "pycares-4.11.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:96e07d5a8b733d753e37d1f7138e7321d2316bb3f0f663ab4e3d500fabc82807"}, + {file = "pycares-4.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9a00408105901ede92e318eecb46d0e661d7d093d0a9b1224c71b5dd94f79e83"}, + {file = "pycares-4.11.0-cp39-cp39-win32.whl", hash = "sha256:910ce19a549f493fb55cfd1d7d70960706a03de6bfc896c1429fc5d6216df77e"}, + {file = "pycares-4.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:6f751f5a0e4913b2787f237c2c69c11a53f599269012feaa9fb86d7cef3aec26"}, + {file = "pycares-4.11.0-cp39-cp39-win_arm64.whl", hash = "sha256:f6c602c5e3615abbf43dbdf3c6c64c65e76e5aa23cb74e18466b55d4a2095468"}, + {file = "pycares-4.11.0.tar.gz", hash = "sha256:c863d9003ca0ce7df26429007859afd2a621d3276ed9fef154a9123db9252557"}, +] + +[package.dependencies] +cffi = {version = ">=1.5.0", markers = "python_version < \"3.14\""} [package.extras] idna = ["idna (>=2.1)"] @@ -2642,14 +2684,15 @@ requests = ">=2.22.0" [[package]] name = "pycparser" -version = "2.22" +version = "2.23" description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["main"] +markers = "implementation_name != \"PyPy\"" files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, + {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, + {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, ] [[package]] @@ -3086,100 +3129,103 @@ jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] [[package]] name = "ruamel-yaml-clib" -version = "0.2.12" +version = "0.2.13" description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" optional = false python-versions = ">=3.9" groups = ["dev"] markers = "platform_python_implementation == \"CPython\"" files = [ - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, - {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, - {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, - {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, - {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bc5f1e1c28e966d61d2519f2a3d451ba989f9ea0f2307de7bc45baa526de9e45"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a0e060aace4c24dcaf71023bbd7d42674e3b230f7e7b97317baf1e953e5b519"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, - {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, - {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:a67efad34e15232f03333d4a7cc96b1db8ecb676439b6a3db10d49ffbd3a8606"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:ce8be9ce9c967a9952e92d9280d18de9ae331284645b50dc32f71ef207ef00e1"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e16f9611130aa3695aaff32d956e49b45cef902aa15cf9de18ebf919d6acc153"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a6afcf136a474703e9c7fa62fab76870775c98a4f59f599fdd24348dca3a229"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70328e9afcb83deb689547989e6b79fc8f094964b8b754b44a70ba7e68e523fe"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fc2c45c0b5b7845278148f18a4039b6d8fde3f7266dd00986684453a57d3444a"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fa3c15cefc29ed3f7ad6ac370bd46d8e431d1fa0ba03eb54912e8c5d826e458e"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-win32.whl", hash = "sha256:e9117696191427cd2c5028878b89012e01cee51b2ae8f5dd440a79d6ba4a1011"}, + {file = "ruamel.yaml.clib-0.2.13-cp310-cp310-win_amd64.whl", hash = "sha256:4ba827c038348ebde594788b66a4741ce9606b979b684e3bc1e7d1c11d6ac817"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:825a7483da63b9448fdad9778269a5d02e5f64040aa8326fec071e830c2fc49c"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:54707e2200b9e1c34a62af09edd3ea3469a722951365311398458abe36ff45d6"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:958b1fc6334cd745db7099a69da4f60503cfbbc05ce1412b1d06c5922cd8314b"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d50c415df5ba918c483a2486a90dd5a3e6df634fca688f71d266e15a618d643f"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bbdb57e57a5bb3510bfb43496bab44857546c56c7f04bb7bfd0b248388d41c2e"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df8ef03eb60fc2e1c0570612363091898b97a7b3181422e1b34c3ee22d7e0a9e"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89168de27694f7903a1317381525efdf7ea2c377b5b1eeeb927940870a7e8945"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-win32.whl", hash = "sha256:8cdb4c720137bb7834cf2c09753d5f3468023eebb7f6ad2604ddf920328753dd"}, + {file = "ruamel.yaml.clib-0.2.13-cp311-cp311-win_amd64.whl", hash = "sha256:670d8a9c5b22af152863236b7a7fec471aafefc5e89b637b8f98d280cb92a0ce"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:810500056a0e294131042eca6687a786e82aad817e8e0bc5ce059d2f95b67fef"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:f8e44b1b583f93a8f4d00e5285d9ea8ccd9524cdd4c54788db2880a11f21287d"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d1ab027be86f7d5ccc9b777a22194fd3850012df413f216bf1608768b4daa2f"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55f01d82d7d96213f0963609876ae841c81e217985c668100c5fb95cc9a564b3"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:031c7cdd5751cda19ddf90e42756ec2ee72a30791c2f65f5f800f9ee929862f0"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ba745411caabc994963729663a7c2d09398795c36dc4b5672ca4fdc445ab6544"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fb90267cc3748858236b9cedb580191be1d0d218f6cde64e954fa759d90fb08d"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-win32.whl", hash = "sha256:5188c3212c10fcd14a6de8ce787c0713a49fc5972054703f790cfd9f1d27a90b"}, + {file = "ruamel.yaml.clib-0.2.13-cp312-cp312-win_amd64.whl", hash = "sha256:518b13f9fe601a559a759f3d21cdb2590cb85611934a7c0f09c09dc1a869ec83"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:b3dae045e57780a6ec39a018220d82931d6cb3e6e8b326a9a804597ffa6f8520"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:f6d476bc7bb9b25d54133f95d0766aaf1662689f6c26e9e08d28a45609a634f2"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5622265f2b64f6933a29a5d8e33385a0c3ef47f509354602d0c28f5d7d126fe3"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2ba05d2dbe39435915aa20d53336d55fd0fa6c25eb1c580d60fc1f753e40a41"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a5a43fc6f95c58c1a65cbb7b68b31f9721362e10c5276d3f8db4ccde8e9acb04"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5ce7178bd66cffe4eb4ce40c2ff525f42ccfa6e2e31eeea27293fe5bd0ae2d93"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:490c5dfaf9f218f335f2f6f7ba52f7ce5460e94d67a42c8dd0096deae7684d23"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-win32.whl", hash = "sha256:b5e32adbb14ffdb1130c699128070766e5cf781b3b05dd87049c16bb94395212"}, + {file = "ruamel.yaml.clib-0.2.13-cp313-cp313-win_amd64.whl", hash = "sha256:826ce141d368f10a99a4fc6fab332ba4203f63da25828853d7957e76d13f7d41"}, + {file = "ruamel.yaml.clib-0.2.13-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:817a3d8dbbefc337e9081d9bddd54ee6ef5d5351cccb5240d731d604c1d86d29"}, + {file = "ruamel.yaml.clib-0.2.13-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:b29e3a746dd774a49ec6412529dc6a7338efe0828230b7c5da2aef3ee6eb7cbc"}, + {file = "ruamel.yaml.clib-0.2.13-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bae8383e02ef5a7c6b44a594746dcdb0994b8bdf4317d2fba3bbafe8262dfa9d"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:2270edaf057306be7351197aa30846a936b699bb5f0ad003e69d6055b09b8cd5"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c86a68e443a30281e8228c5e0b612ffc639918b2c62dd9c77a29356ba8a9a891"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e9d71e1a0b7655dc82168b55f6399067990804065546d39d45973a0c15fe777"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e26eda047e90595c4086d2ad79170f26838097de1fb6b5efe91ca5de45065ab4"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44ad995de7c8397d81459ab9cd5e64b0c2f72b9812368bbf6c57969288d030ad"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20b475065c89ef2399f4cde03a1969d376b48257d1e4c1d9a6bb077a0f518f30"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cc9512ca10d2158daa30b4f918916e2bd9ee6391291209a2b2ede37ccfefbb81"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-win32.whl", hash = "sha256:8a8ba6b52f06d33a3ed010b1529ef9a44097ca896ef896967d7ebcdb4d642624"}, + {file = "ruamel.yaml.clib-0.2.13-cp39-cp39-win_amd64.whl", hash = "sha256:e440a8f7e59455b1c2960f0e4d5b51657ca7884cc033d80ac6f27cc1c9921938"}, + {file = "ruamel.yaml.clib-0.2.13.tar.gz", hash = "sha256:8d4f8d7853053a5a19171a0f515f1e14f503bd3e772c4da6bafe7d0893d4f299"}, ] [[package]] name = "ruff" -version = "0.12.10" +version = "0.13.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.12.10-py3-none-linux_armv6l.whl", hash = "sha256:8b593cb0fb55cc8692dac7b06deb29afda78c721c7ccfed22db941201b7b8f7b"}, - {file = "ruff-0.12.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ebb7333a45d56efc7c110a46a69a1b32365d5c5161e7244aaf3aa20ce62399c1"}, - {file = "ruff-0.12.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d59e58586829f8e4a9920788f6efba97a13d1fa320b047814e8afede381c6839"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:822d9677b560f1fdeab69b89d1f444bf5459da4aa04e06e766cf0121771ab844"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b4a64f4062a50c75019c61c7017ff598cb444984b638511f48539d3a1c98db"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6f4064c69d2542029b2a61d39920c85240c39837599d7f2e32e80d36401d6e"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:059e863ea3a9ade41407ad71c1de2badfbe01539117f38f763ba42a1206f7559"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bef6161e297c68908b7218fa6e0e93e99a286e5ed9653d4be71e687dff101cf"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f1345fbf8fb0531cd722285b5f15af49b2932742fc96b633e883da8d841896b"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f68433c4fbc63efbfa3ba5db31727db229fa4e61000f452c540474b03de52a9"}, - {file = "ruff-0.12.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:141ce3d88803c625257b8a6debf4a0473eb6eed9643a6189b68838b43e78165a"}, - {file = "ruff-0.12.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f3fc21178cd44c98142ae7590f42ddcb587b8e09a3b849cbc84edb62ee95de60"}, - {file = "ruff-0.12.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7d1a4e0bdfafcd2e3e235ecf50bf0176f74dd37902f241588ae1f6c827a36c56"}, - {file = "ruff-0.12.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e67d96827854f50b9e3e8327b031647e7bcc090dbe7bb11101a81a3a2cbf1cc9"}, - {file = "ruff-0.12.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ae479e1a18b439c59138f066ae79cc0f3ee250712a873d00dbafadaad9481e5b"}, - {file = "ruff-0.12.10-py3-none-win32.whl", hash = "sha256:9de785e95dc2f09846c5e6e1d3a3d32ecd0b283a979898ad427a9be7be22b266"}, - {file = "ruff-0.12.10-py3-none-win_amd64.whl", hash = "sha256:7837eca8787f076f67aba2ca559cefd9c5cbc3a9852fd66186f4201b87c1563e"}, - {file = "ruff-0.12.10-py3-none-win_arm64.whl", hash = "sha256:cc138cc06ed9d4bfa9d667a65af7172b47840e1a98b02ce7011c391e54635ffc"}, - {file = "ruff-0.12.10.tar.gz", hash = "sha256:189ab65149d11ea69a2d775343adf5f49bb2426fc4780f65ee33b423ad2e47f9"}, + {file = "ruff-0.13.0-py3-none-linux_armv6l.whl", hash = "sha256:137f3d65d58ee828ae136a12d1dc33d992773d8f7644bc6b82714570f31b2004"}, + {file = "ruff-0.13.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:21ae48151b66e71fd111b7d79f9ad358814ed58c339631450c66a4be33cc28b9"}, + {file = "ruff-0.13.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:64de45f4ca5441209e41742d527944635a05a6e7c05798904f39c85bafa819e3"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2c653ae9b9d46e0ef62fc6fbf5b979bda20a0b1d2b22f8f7eb0cde9f4963b8"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cec632534332062bc9eb5884a267b689085a1afea9801bf94e3ba7498a2d207"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd628101d9f7d122e120ac7c17e0a0f468b19bc925501dbe03c1cb7f5415b24"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afe37db8e1466acb173bb2a39ca92df00570e0fd7c94c72d87b51b21bb63efea"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f96a8d90bb258d7d3358b372905fe7333aaacf6c39e2408b9f8ba181f4b6ef2"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b5e3d883e4f924c5298e3f2ee0f3085819c14f68d1e5b6715597681433f153"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03447f3d18479df3d24917a92d768a89f873a7181a064858ea90a804a7538991"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fbc6b1934eb1c0033da427c805e27d164bb713f8e273a024a7e86176d7f462cf"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8ab6a3e03665d39d4a25ee199d207a488724f022db0e1fe4002968abdb8001b"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2a5c62f8ccc6dd2fe259917482de7275cecc86141ee10432727c4816235bc41"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b7b85ca27aeeb1ab421bc787009831cffe6048faae08ad80867edab9f2760945"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:79ea0c44a3032af768cabfd9616e44c24303af49d633b43e3a5096e009ebe823"}, + {file = "ruff-0.13.0-py3-none-win32.whl", hash = "sha256:4e473e8f0e6a04e4113f2e1de12a5039579892329ecc49958424e5568ef4f768"}, + {file = "ruff-0.13.0-py3-none-win_amd64.whl", hash = "sha256:48e5c25c7a3713eea9ce755995767f4dcd1b0b9599b638b12946e892123d1efb"}, + {file = "ruff-0.13.0-py3-none-win_arm64.whl", hash = "sha256:ab80525317b1e1d38614addec8ac954f1b3e662de9d59114ecbf771d00cf613e"}, + {file = "ruff-0.13.0.tar.gz", hash = "sha256:5b4b1ee7eb35afae128ab94459b13b2baaed282b1fb0f472a73c82c996c8ae60"}, ] [[package]] name = "s3transfer" -version = "0.13.1" +version = "0.14.0" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "s3transfer-0.13.1-py3-none-any.whl", hash = "sha256:a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724"}, - {file = "s3transfer-0.13.1.tar.gz", hash = "sha256:c3fdba22ba1bd367922f27ec8032d6a1cf5f10c934fb5d68cf60fd5a23d936cf"}, + {file = "s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456"}, + {file = "s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125"}, ] [package.dependencies] @@ -3632,6 +3678,9 @@ files = [ {file = "winrt_runtime-3.2.1-cp313-cp313-win32.whl", hash = "sha256:44e2733bc709b76c554aee6c7fe079443b8306b2e661e82eecfebe8b9d71e4d1"}, {file = "winrt_runtime-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:3c1fdcaeedeb2920dc3b9039db64089a6093cad2be56a3e64acc938849245a6d"}, {file = "winrt_runtime-3.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:28f3dab083412625ff4d2b46e81246932e6bebddf67bea7f05e01712f54e6159"}, + {file = "winrt_runtime-3.2.1-cp314-cp314-win32.whl", hash = "sha256:9b6298375468ac2f6815d0c008a059fc16508c8f587e824c7936ed9216480dad"}, + {file = "winrt_runtime-3.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:e36e587ab5fd681ee472cd9a5995743f75107a1a84d749c64f7e490bc86bc814"}, + {file = "winrt_runtime-3.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:35d6241a2ebd5598e4788e69768b8890ee1eee401a819865767a1fbdd3e9a650"}, {file = "winrt_runtime-3.2.1-cp39-cp39-win32.whl", hash = "sha256:07c0cb4a53a4448c2cb7597b62ae8c94343c289eeebd8f83f946eb2c817bde01"}, {file = "winrt_runtime-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:1856325ca3354b45e0789cf279be9a882134085d34214946db76110d98391efa"}, {file = "winrt_runtime-3.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:cf237858de1d62e4c9b132c66b52028a7a3e8534e8ab90b0e29a68f24f7be39d"}, @@ -3662,6 +3711,9 @@ files = [ {file = "winrt_windows_devices_bluetooth-3.2.1-cp313-cp313-win32.whl", hash = "sha256:12b0a16fb36ce0b42243ca81f22a6b53fbb344ed7ea07a6eeec294604f0505e4"}, {file = "winrt_windows_devices_bluetooth-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:6703dfbe444ee22426738830fb305c96a728ea9ccce905acfdf811d81045fdb3"}, {file = "winrt_windows_devices_bluetooth-3.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:2cf8a0bfc9103e32dc7237af15f84be06c791f37711984abdca761f6318bbdb2"}, + {file = "winrt_windows_devices_bluetooth-3.2.1-cp314-cp314-win32.whl", hash = "sha256:de36ded53ca3ba12fc6dd4deb14b779acc391447726543815df4800348aad63a"}, + {file = "winrt_windows_devices_bluetooth-3.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:3295d932cc93259d5ccb23a41e3a3af4c78ce5d6a6223b2b7638985f604fa34c"}, + {file = "winrt_windows_devices_bluetooth-3.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:1f61c178766a1bbce0669f44790c6161ff4669404c477b4aedaa576348f9e102"}, {file = "winrt_windows_devices_bluetooth-3.2.1-cp39-cp39-win32.whl", hash = "sha256:32fc355bfdc5d6b3b1875df16eaf12f9b9fc0445e01177833c27d9a4fc0d50b6"}, {file = "winrt_windows_devices_bluetooth-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b886ef1fc0ed49163ae6c2422dd5cb8dd4709da7972af26c8627e211872818d0"}, {file = "winrt_windows_devices_bluetooth-3.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:8643afa53f9fb8fe3b05967227f86f0c8e1d7b822289e60a848c6368acc977d2"}, @@ -3695,6 +3747,9 @@ files = [ {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp313-cp313-win32.whl", hash = "sha256:4122348ea525a914e85615647a0b54ae8b2f42f92cdbf89c5a12eea53ef6ed90"}, {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:b66410c04b8dae634a7e4b615c3b7f8adda9c7d4d6902bcad5b253da1a684943"}, {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:07af19b1d252ddb9dd3eb2965118bc2b7cabff4dda6e499341b765e5038ca61d"}, + {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp314-cp314-win32.whl", hash = "sha256:2985565c265b3f9eab625361b0e40e88c94b03d89f5171f36146f2e88b3ee214"}, + {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:d102f3fac64fde32332e370969dfbc6f37b405d8cc055d9da30d14d07449a3c2"}, + {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:ffeb5e946cd42c32c6999a62e240d6730c653cdfb7b49c7839afba375e20a62a"}, {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp39-cp39-win32.whl", hash = "sha256:6c4747d2e5b0e2ef24e9b84a848cf8fc50fb5b268a2086b5ee8680206d1e0197"}, {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:18d4c5d8b80ee2d29cc13c2fc1353fdb3c0f620c8083701c9b9ecf5e6c503c8d"}, {file = "winrt_windows_devices_bluetooth_advertisement-3.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:75dd856611d847299078d56aee60e319df52975b931c992cd1d32ad5143fe772"}, @@ -3728,6 +3783,9 @@ files = [ {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp313-cp313-win32.whl", hash = "sha256:b1879c8dcf46bd2110b9ad4b0b185f4e2a5f95170d014539203a5fee2b2115f0"}, {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d8d89f01e9b6931fb48217847caac3227a0aeb38a5b7782af71c2e7b262ec30"}, {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:4e71207bb89798016b1795bb15daf78afe45529f2939b3b9e78894cfe650b383"}, + {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp314-cp314-win32.whl", hash = "sha256:d5f83739ca370f0baf52b0400aebd6240ab80150081fbfba60fd6e7b2e7b4c5f"}, + {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:13786a5853a933de140d456cd818696e1121c7c296ae7b7af262fc5d2cffb851"}, + {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:5140682da2860f6a55eb6faf9e980724dc457c2e4b4b35a10e1cebd8fc97d892"}, {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp39-cp39-win32.whl", hash = "sha256:963339a0161f9970b577a6193924be783978d11693da48b41a025f61b3c5562a"}, {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:d43615c5dfa939dd30fe80dc0649434a13cc7cf0294ad0d7283d5a9f48c6ce86"}, {file = "winrt_windows_devices_bluetooth_genericattributeprofile-3.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:8e70fa970997e2e67a8a4172bc00b0b2a79b5ff5bb2668f79cf10b3fd63d3974"}, @@ -3761,6 +3819,9 @@ files = [ {file = "winrt_windows_devices_enumeration-3.2.1-cp313-cp313-win32.whl", hash = "sha256:14a71cdcc84f624c209cbb846ed6bd9767a9a9437b2bf26b48ac9a91599da6e9"}, {file = "winrt_windows_devices_enumeration-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:6ca40d334734829e178ad46375275c4f7b5d6d2d4fc2e8879690452cbfb36015"}, {file = "winrt_windows_devices_enumeration-3.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:2d14d187f43e4409c7814b7d1693c03a270e77489b710d92fcbbaeca5de260d4"}, + {file = "winrt_windows_devices_enumeration-3.2.1-cp314-cp314-win32.whl", hash = "sha256:e087364273ed7c717cd0191fed4be9def6fdf229fe9b536a4b8d0228f7814106"}, + {file = "winrt_windows_devices_enumeration-3.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:0da1ddb8285d97a6775c36265d7157acf1bbcb88bcc9a7ce9a4549906c822472"}, + {file = "winrt_windows_devices_enumeration-3.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:09bf07e74e897e97a49a9275d0a647819254ddb74142806bbbcf4777ed240a22"}, {file = "winrt_windows_devices_enumeration-3.2.1-cp39-cp39-win32.whl", hash = "sha256:986e8d651b769a0e60d2834834bdd3f6959f6a88caa0c9acb917797e6b43a588"}, {file = "winrt_windows_devices_enumeration-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10da7d403ac4afd385fe13bd5808c9a5dd616a8ef31ca5c64cea3f87673661c1"}, {file = "winrt_windows_devices_enumeration-3.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:679e471d21ac22cb50de1bf4dfc4c0c3f5da9f3e3fbc7f08dcacfe9de9d6dd58"}, @@ -3794,6 +3855,9 @@ files = [ {file = "winrt_windows_foundation-3.2.1-cp313-cp313-win32.whl", hash = "sha256:3998dc58ed50ecbdbabace1cdef3a12920b725e32a5806d648ad3f4829d5ba46"}, {file = "winrt_windows_foundation-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:6e98617c1e46665c7a56ce3f5d28e252798416d1ebfee3201267a644a4e3c479"}, {file = "winrt_windows_foundation-3.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:2a8c1204db5c352f6a563130a5a41d25b887aff7897bb677d4ff0b660315aad4"}, + {file = "winrt_windows_foundation-3.2.1-cp314-cp314-win32.whl", hash = "sha256:35e973ab3c77c2a943e139302256c040e017fd6ff1a75911c102964603bba1da"}, + {file = "winrt_windows_foundation-3.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:a22a7ebcec0d262e60119cff728f32962a02df60471ded8b2735a655eccc0ef5"}, + {file = "winrt_windows_foundation-3.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:3be7fbae829b98a6a946db4fbaf356b11db1fbcbb5d4f37e7a73ac6b25de8b87"}, {file = "winrt_windows_foundation-3.2.1-cp39-cp39-win32.whl", hash = "sha256:14d5191725301498e4feb744d91f5b46ce317bf3d28370efda407d5c87f4423b"}, {file = "winrt_windows_foundation-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:de5e4f61d253a91ba05019dbf4338c43f962bdad935721ced5e7997933994af5"}, {file = "winrt_windows_foundation-3.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:ebbf6e8168398c9ed0c72c8bdde95a406b9fbb9a23e3705d4f0fe28e5a209705"}, @@ -3827,6 +3891,9 @@ files = [ {file = "winrt_windows_foundation_collections-3.2.1-cp313-cp313-win32.whl", hash = "sha256:4267a711b63476d36d39227883aeb3fb19ac92b88a9fc9973e66fbce1fd4aed9"}, {file = "winrt_windows_foundation_collections-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:5e12a6e75036ee90484c33e204b85fb6785fcc9e7c8066ad65097301f48cdd10"}, {file = "winrt_windows_foundation_collections-3.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:34b556255562f1b36d07fba933c2bcd9f0db167fa96727a6cbb4717b152ad7a2"}, + {file = "winrt_windows_foundation_collections-3.2.1-cp314-cp314-win32.whl", hash = "sha256:33188ed2d63e844c8adfbb82d1d3d461d64aaf78d225ce9c5930421b413c45ab"}, + {file = "winrt_windows_foundation_collections-3.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:d4cfece7e9c0ead2941e55a1da82f20d2b9c8003bb7a8853bb7f999b539f80a4"}, + {file = "winrt_windows_foundation_collections-3.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:3884146fea13727510458f6a14040b7632d5d90127028b9bfd503c6c655d0c01"}, {file = "winrt_windows_foundation_collections-3.2.1-cp39-cp39-win32.whl", hash = "sha256:20610f098b84c87765018cbc71471092197881f3b92e5d06158fad3bfcea2563"}, {file = "winrt_windows_foundation_collections-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:e9739775320ac4c0238e1775d94a54e886d621f9995977e65d4feb8b3778c111"}, {file = "winrt_windows_foundation_collections-3.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:e4c6bddb1359d5014ceb45fe2ecd838d4afeb1184f2ea202c2d21037af0d08a3"}, @@ -3860,6 +3927,9 @@ files = [ {file = "winrt_windows_storage_streams-3.2.1-cp313-cp313-win32.whl", hash = "sha256:401bb44371720dc43bd1e78662615a2124372e7d5d9d65dfa8f77877bbcb8163"}, {file = "winrt_windows_storage_streams-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:202c5875606398b8bfaa2a290831458bb55f2196a39c1d4e5fa88a03d65ef915"}, {file = "winrt_windows_storage_streams-3.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:ca3c5ec0aab60895006bf61053a1aca6418bc7f9a27a34791ba3443b789d230d"}, + {file = "winrt_windows_storage_streams-3.2.1-cp314-cp314-win32.whl", hash = "sha256:5cd0dbad86fcc860366f6515fce97177b7eaa7069da261057be4813819ba37ee"}, + {file = "winrt_windows_storage_streams-3.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:3c5bf41d725369b9986e6d64bad7079372b95c329897d684f955d7028c7f27a0"}, + {file = "winrt_windows_storage_streams-3.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:293e09825559d0929bbe5de01e1e115f7a6283d8996ab55652e5af365f032987"}, {file = "winrt_windows_storage_streams-3.2.1-cp39-cp39-win32.whl", hash = "sha256:1c630cfdece58fcf82e4ed86c826326123529836d6d4d855ae8e9ceeff67b627"}, {file = "winrt_windows_storage_streams-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:d7ff22434a4829d616a04b068a191ac79e008f6c27541bb178c1f6f1fe7a1657"}, {file = "winrt_windows_storage_streams-3.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:fa90244191108f85f6f7afb43a11d365aca4e0722fe8adc62fb4d2c678d0993d"}, @@ -4087,4 +4157,4 @@ ifaddr = ">=0.1.7" [metadata] lock-version = "2.1" python-versions = ">=3.13.2,<3.14" -content-hash = "320c249da4e05da8d4004506c42422ab8a94e381d5bd0713d0b192987373b4a5" +content-hash = "9cf342e0994cb5924a4c3be39e592f81277ddb0a8c7f47a3f73d04cb8cd00d50" From 9b9b7d971fa4b9b4c98ddb4a518b7d3e535668d7 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 23 Sep 2025 13:36:37 +0100 Subject: [PATCH 203/235] Add device inclusion filter to battery notes blueprints --- .../battery_notes_battery_not_reported.yaml | 15 +++++++++++---- .../battery_notes_battery_threshold.yaml | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/blueprints/battery_notes_battery_not_reported.yaml b/docs/blueprints/battery_notes_battery_not_reported.yaml index 7a4ac68e5..a201ac007 100755 --- a/docs/blueprints/battery_notes_battery_not_reported.yaml +++ b/docs/blueprints/battery_notes_battery_not_reported.yaml @@ -18,9 +18,15 @@ blueprint: selector: device: multiple: true - included_devices: + include_devices_enabled: + name: Enable Include Devices Filter + description: Only trigger for specific devices when enabled. + default: false + selector: + boolean: + include_devices: name: Devices to include (Optional) - description: If specified, only these devices will trigger this automation. + description: When enabled above, only these devices will trigger this automation. default: selector: device: @@ -42,7 +48,8 @@ blueprint: variables: not_reported_notification: !input not_reported_notification excluded_devices: !input excluded_devices - included_devices: !input included_devices + include_devices_enabled: !input include_devices_enabled + include_devices: !input include_devices triggers: - trigger: event event_type: battery_notes_battery_not_reported @@ -53,7 +60,7 @@ conditions: {{ trigger.event.data.device_id not in excluded_devices}} - condition: template value_template: |- - {{ included_devices | length == 0 or trigger.event.data.device_id in included_devices }} + {{ not include_devices_enabled or trigger.event.data.device_id in include_devices }} - alias: User pick condition: !input additional_conditions actions: diff --git a/docs/blueprints/battery_notes_battery_threshold.yaml b/docs/blueprints/battery_notes_battery_threshold.yaml index cf409f20e..16c7cd93a 100644 --- a/docs/blueprints/battery_notes_battery_threshold.yaml +++ b/docs/blueprints/battery_notes_battery_threshold.yaml @@ -25,9 +25,15 @@ blueprint: selector: device: multiple: true - included_devices: + include_devices_enabled: + name: Enable Include Devices Filter + description: Only trigger for specific devices when enabled. + default: false + selector: + boolean: + include_devices: name: Devices to include (Optional) - description: If specified, only these devices will trigger this automation. + description: When enabled above, only these devices will trigger this automation. default: selector: device: @@ -57,7 +63,8 @@ variables: low_notification: !input low_notification high_notification: !input high_notification excluded_devices: !input excluded_devices - included_devices: !input included_devices + include_devices_enabled: !input include_devices_enabled + include_devices: !input include_devices triggers: - trigger: event @@ -79,7 +86,7 @@ conditions: {{ trigger.event.data.device_id not in excluded_devices}} - condition: template value_template: |- - {{ included_devices | length == 0 or trigger.event.data.device_id in included_devices }} + {{ not include_devices_enabled or trigger.event.data.device_id in include_devices }} - alias: User pick condition: !input additional_conditions From bc0340f42fe697dfa835a5e0221708b4be5488b2 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 2 Oct 2025 15:16:52 +0000 Subject: [PATCH 204/235] Fix battery low rename --- custom_components/battery_notes/binary_sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index c3a7a421b..f213ea3c7 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -742,11 +742,11 @@ async def _entity_rename_listener( self.coordinator.wrapped_battery = new_wrapped_battery # Create a listener for the newly named battery entity - if self.coordinator.wrapped_battery: + if self.coordinator.wrapped_battery_low: self.async_on_remove( async_track_state_change_event( self.hass, - [self.coordinator.wrapped_battery.entity_id], + [self.coordinator.wrapped_battery_low.entity_id], self.async_state_changed_listener, ) ) From 2a91dd3e446ed5b96abbb9277eb2741ab23d8be6 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 19 Oct 2025 12:00:32 +0000 Subject: [PATCH 205/235] Add documentation URL placeholder to configuration steps - Updated config_flow.py to include a documentation URL placeholder in the user configuration step. - Modified translation files for multiple languages to replace hardcoded documentation links with a placeholder for the documentation URL. --- custom_components/battery_notes/config_flow.py | 8 +++++++- custom_components/battery_notes/translations/ar.json | 4 ++-- custom_components/battery_notes/translations/ca.json | 4 ++-- custom_components/battery_notes/translations/cs.json | 4 ++-- custom_components/battery_notes/translations/da.json | 4 ++-- custom_components/battery_notes/translations/de.json | 4 ++-- custom_components/battery_notes/translations/el.json | 4 ++-- custom_components/battery_notes/translations/en.json | 4 ++-- custom_components/battery_notes/translations/es-ES.json | 4 ++-- custom_components/battery_notes/translations/fi.json | 4 ++-- custom_components/battery_notes/translations/fr.json | 4 ++-- custom_components/battery_notes/translations/hu.json | 4 ++-- custom_components/battery_notes/translations/it.json | 4 ++-- custom_components/battery_notes/translations/lt.json | 4 ++-- custom_components/battery_notes/translations/lv.json | 4 ++-- custom_components/battery_notes/translations/nl.json | 4 ++-- custom_components/battery_notes/translations/no.json | 4 ++-- custom_components/battery_notes/translations/pl.json | 4 ++-- custom_components/battery_notes/translations/pt-BR.json | 4 ++-- custom_components/battery_notes/translations/pt.json | 2 +- custom_components/battery_notes/translations/ru.json | 4 ++-- custom_components/battery_notes/translations/sk.json | 4 ++-- custom_components/battery_notes/translations/sr-Latn.json | 4 ++-- custom_components/battery_notes/translations/sv-SE.json | 4 ++-- custom_components/battery_notes/translations/tr.json | 4 ++-- custom_components/battery_notes/translations/uk.json | 4 ++-- custom_components/battery_notes/translations/ur-IN.json | 4 ++-- custom_components/battery_notes/translations/zh-Hans.json | 4 ++-- custom_components/battery_notes/translations/zh-Hant.json | 4 ++-- 29 files changed, 62 insertions(+), 56 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index ccaa91a5c..f12a3a3d7 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -59,6 +59,8 @@ _LOGGER = logging.getLogger(__name__) +DOCUMENTATION_URL = "https://andrew-codechimp.github.io/HA-Battery-Notes/" + CONFIG_VERSION = 3 OPTIONS_SCHEMA = vol.Schema( @@ -268,6 +270,7 @@ async def async_step_user( self._set_confirm_only() return self.async_show_form( step_id="user", + description_placeholders={"documentation_url": DOCUMENTATION_URL}, ) @@ -511,7 +514,10 @@ async def async_step_user( ) -> SubentryFlowResult: """Add a subentry.""" - return self.async_show_menu(step_id="user", menu_options=["device", "entity"]) + return self.async_show_menu(step_id="user", + menu_options=["device", "entity"], + description_placeholders={"documentation_url": DOCUMENTATION_URL}, + ) async def async_step_device( self, diff --git a/custom_components/battery_notes/translations/ar.json b/custom_components/battery_notes/translations/ar.json index 6bc8f35e3..30d003f24 100644 --- a/custom_components/battery_notes/translations/ar.json +++ b/custom_components/battery_notes/translations/ar.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "إذا كنت بحاجة إلى مساعدة في التكوين، يمكنك الاطلاع على هذا الرابط: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "إذا كنت بحاجة إلى مساعدة في التكوين، يمكنك الاطلاع على هذا الرابط: {documentation_url}", "data": { "association_type": "نوع الارتباط" }, diff --git a/custom_components/battery_notes/translations/ca.json b/custom_components/battery_notes/translations/ca.json index 11370682f..33a43bf6c 100644 --- a/custom_components/battery_notes/translations/ca.json +++ b/custom_components/battery_notes/translations/ca.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Si necessiteu ajuda amb la configuració, mireu aquí: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Si necessiteu ajuda amb la configuració, mireu aquí: {documentation_url}", "data": { "association_type": "Tipus d'associació" }, diff --git a/custom_components/battery_notes/translations/cs.json b/custom_components/battery_notes/translations/cs.json index dd988ef8d..a089a5563 100644 --- a/custom_components/battery_notes/translations/cs.json +++ b/custom_components/battery_notes/translations/cs.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Pokud potřebujete pomoc s konfigurací, podívejte se zde: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Pokud potřebujete pomoc s konfigurací, podívejte se zde: {documentation_url}", "data": { "association_type": "Typ přidružení" }, diff --git a/custom_components/battery_notes/translations/da.json b/custom_components/battery_notes/translations/da.json index 4a849d529..03edcfcac 100644 --- a/custom_components/battery_notes/translations/da.json +++ b/custom_components/battery_notes/translations/da.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Hvis du har brug for hjælp til konfigurationen, så kig her: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Hvis du har brug for hjælp til konfigurationen, så kig her: {documentation_url}", "data": { "association_type": "Association type" }, diff --git a/custom_components/battery_notes/translations/de.json b/custom_components/battery_notes/translations/de.json index 10a5dd56c..e60b8aa59 100644 --- a/custom_components/battery_notes/translations/de.json +++ b/custom_components/battery_notes/translations/de.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Hilfe zur Konfiguration findest du unter: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Hilfe zur Konfiguration findest du unter: {documentation_url}", "data": { "association_type": "Verbindungstyp" }, diff --git a/custom_components/battery_notes/translations/el.json b/custom_components/battery_notes/translations/el.json index 8f090daec..965fb5007 100644 --- a/custom_components/battery_notes/translations/el.json +++ b/custom_components/battery_notes/translations/el.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Αν χρειάζεστε βοήθεια με τις ρυθμίσεις παραμέτρων ρίξτε μια ματιά εδώ: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Αν χρειάζεστε βοήθεια με τις ρυθμίσεις παραμέτρων ρίξτε μια ματιά εδώ: {documentation_url}", "data": { "association_type": "Τύπος συσχετισμού" }, diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 2e36fb836..5a15991cc 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "If you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "If you need help with the configuration have a look here: {documentation_url}", "data": { "association_type": "Association type" }, diff --git a/custom_components/battery_notes/translations/es-ES.json b/custom_components/battery_notes/translations/es-ES.json index b9476a987..46ebc4c0c 100644 --- a/custom_components/battery_notes/translations/es-ES.json +++ b/custom_components/battery_notes/translations/es-ES.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Si necesitas ayuda con la configuración, echa un vistazo aquí: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Si necesitas ayuda con la configuración, echa un vistazo aquí: {documentation_url}", "data": { "association_type": "Tipo de asociación" }, diff --git a/custom_components/battery_notes/translations/fi.json b/custom_components/battery_notes/translations/fi.json index db2580046..74aaee7be 100644 --- a/custom_components/battery_notes/translations/fi.json +++ b/custom_components/battery_notes/translations/fi.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Jos tarvitset apua asetuksissa, katso täältä: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Jos tarvitset apua asetuksissa, katso täältä: {documentation_url}", "data": { "association_type": "Association type" }, diff --git a/custom_components/battery_notes/translations/fr.json b/custom_components/battery_notes/translations/fr.json index 8cda09b75..55a385288 100644 --- a/custom_components/battery_notes/translations/fr.json +++ b/custom_components/battery_notes/translations/fr.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Si vous avez besoin d'aide pour la configuration, regardez ici : https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Si vous avez besoin d'aide pour la configuration, regardez ici : {documentation_url}", "data": { "association_type": "Type d'association:" }, diff --git a/custom_components/battery_notes/translations/hu.json b/custom_components/battery_notes/translations/hu.json index 841d4635d..9a74369bd 100644 --- a/custom_components/battery_notes/translations/hu.json +++ b/custom_components/battery_notes/translations/hu.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Segítség a konfigurációhoz: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Segítség a konfigurációhoz: {documentation_url}", "data": { "association_type": "Társítás típusa" }, diff --git a/custom_components/battery_notes/translations/it.json b/custom_components/battery_notes/translations/it.json index bc9638bce..0cf57e326 100644 --- a/custom_components/battery_notes/translations/it.json +++ b/custom_components/battery_notes/translations/it.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Se hai bisogno di aiuto per la configurazione, dai un'occhiata qui: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Se hai bisogno di aiuto per la configurazione, dai un'occhiata qui: {documentation_url}", "data": { "association_type": "Tipo di associazione" }, diff --git a/custom_components/battery_notes/translations/lt.json b/custom_components/battery_notes/translations/lt.json index 7722e85e1..dba12e103 100644 --- a/custom_components/battery_notes/translations/lt.json +++ b/custom_components/battery_notes/translations/lt.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Daugiau pagalbos apie konfigūraciją rasite čia: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Daugiau pagalbos apie konfigūraciją rasite čia: {documentation_url}", "data": { "association_type": "Association type" }, diff --git a/custom_components/battery_notes/translations/lv.json b/custom_components/battery_notes/translations/lv.json index cbb21d81d..588e5d41b 100644 --- a/custom_components/battery_notes/translations/lv.json +++ b/custom_components/battery_notes/translations/lv.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Ja nepieciešama konfigurēšanas palīdzība, papildus informāciju var iegūt šeit: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Ja nepieciešama konfigurēšanas palīdzība, papildus informāciju var iegūt šeit: {documentation_url}", "data": { "association_type": "Asociācijas veids" }, diff --git a/custom_components/battery_notes/translations/nl.json b/custom_components/battery_notes/translations/nl.json index 505a407aa..76a1f12ff 100644 --- a/custom_components/battery_notes/translations/nl.json +++ b/custom_components/battery_notes/translations/nl.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Als u hulp nodig heeft bij de configuratie kunt u hier een kijkje nemen: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Als u hulp nodig heeft bij de configuratie kunt u hier een kijkje nemen: {documentation_url}", "data": { "association_type": "Associatietype" }, diff --git a/custom_components/battery_notes/translations/no.json b/custom_components/battery_notes/translations/no.json index 3f6eece57..1ceb54023 100644 --- a/custom_components/battery_notes/translations/no.json +++ b/custom_components/battery_notes/translations/no.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Hvis du trenger hjelp med konfigurasjonen, kan du se her: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Hvis du trenger hjelp med konfigurasjonen, kan du se her: {documentation_url}", "data": { "association_type": "Association type" }, diff --git a/custom_components/battery_notes/translations/pl.json b/custom_components/battery_notes/translations/pl.json index c2cd4e359..4686b76d1 100644 --- a/custom_components/battery_notes/translations/pl.json +++ b/custom_components/battery_notes/translations/pl.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Jeśli potrzebujesz pomocy w konfiguracji, zajrzyj tutaj: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Jeśli potrzebujesz pomocy w konfiguracji, zajrzyj tutaj: {documentation_url}", "data": { "association_type": "Rodzaj powiązania" }, diff --git a/custom_components/battery_notes/translations/pt-BR.json b/custom_components/battery_notes/translations/pt-BR.json index 03224554d..65408ced0 100644 --- a/custom_components/battery_notes/translations/pt-BR.json +++ b/custom_components/battery_notes/translations/pt-BR.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Se você precisar de ajuda com a configuração dê uma olhada aqui: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Se você precisar de ajuda com a configuração dê uma olhada aqui: {documentation_url}", "data": { "association_type": "Tipos de Associação" }, diff --git a/custom_components/battery_notes/translations/pt.json b/custom_components/battery_notes/translations/pt.json index d1b1bbf74..bc7167d03 100644 --- a/custom_components/battery_notes/translations/pt.json +++ b/custom_components/battery_notes/translations/pt.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { diff --git a/custom_components/battery_notes/translations/ru.json b/custom_components/battery_notes/translations/ru.json index 464a22b4c..3ab2553ab 100644 --- a/custom_components/battery_notes/translations/ru.json +++ b/custom_components/battery_notes/translations/ru.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Если вам нужна помощь с настройкой, посмотрите здесь: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Если вам нужна помощь с настройкой, посмотрите здесь: {documentation_url}", "data": { "association_type": "Тип связи" }, diff --git a/custom_components/battery_notes/translations/sk.json b/custom_components/battery_notes/translations/sk.json index 34a851fa0..f5b0152bb 100644 --- a/custom_components/battery_notes/translations/sk.json +++ b/custom_components/battery_notes/translations/sk.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Ak potrebujete pomoc s konfiguráciou, pozrite sa sem: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Ak potrebujete pomoc s konfiguráciou, pozrite sa sem: {documentation_url}", "data": { "association_type": "Typ asociácie" }, diff --git a/custom_components/battery_notes/translations/sr-Latn.json b/custom_components/battery_notes/translations/sr-Latn.json index 74deaeb29..7a06e9e8c 100644 --- a/custom_components/battery_notes/translations/sr-Latn.json +++ b/custom_components/battery_notes/translations/sr-Latn.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Ako vam treba pomoć oko konfiguracije, pogledajte ovde: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Ako vam treba pomoć oko konfiguracije, pogledajte ovde: {documentation_url}", "data": { "association_type": "Vrsta povezivanja" }, diff --git a/custom_components/battery_notes/translations/sv-SE.json b/custom_components/battery_notes/translations/sv-SE.json index fc8185ab3..441df59d8 100644 --- a/custom_components/battery_notes/translations/sv-SE.json +++ b/custom_components/battery_notes/translations/sv-SE.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Om du behöver hjälp med konfigurationen ta en titt här: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Om du behöver hjälp med konfigurationen ta en titt här: {documentation_url}", "data": { "association_type": "Associationstyp" }, diff --git a/custom_components/battery_notes/translations/tr.json b/custom_components/battery_notes/translations/tr.json index db34a1956..74ff776fc 100644 --- a/custom_components/battery_notes/translations/tr.json +++ b/custom_components/battery_notes/translations/tr.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Yapılandırma ile ilgili yardıma ihtiyacınız varsa buraya bir göz atın: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Yapılandırma ile ilgili yardıma ihtiyacınız varsa buraya bir göz atın: {documentation_url}", "data": { "association_type": "İlişkilendirme türü" }, diff --git a/custom_components/battery_notes/translations/uk.json b/custom_components/battery_notes/translations/uk.json index 7259aec49..e29029992 100644 --- a/custom_components/battery_notes/translations/uk.json +++ b/custom_components/battery_notes/translations/uk.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "Якщо вам потрібна допомога з конфігурацією, подивіться тут: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "Якщо вам потрібна допомога з конфігурацією, подивіться тут: {documentation_url}", "data": { "association_type": "Тип асоціацій" }, diff --git a/custom_components/battery_notes/translations/ur-IN.json b/custom_components/battery_notes/translations/ur-IN.json index 31bdea8c0..ff494064e 100644 --- a/custom_components/battery_notes/translations/ur-IN.json +++ b/custom_components/battery_notes/translations/ur-IN.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "اگر آپ کو ترتیب میں مدد کی ضرورت ہو تو یہاں ایک نظر ڈالیں: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "اگر آپ کو ترتیب میں مدد کی ضرورت ہو تو یہاں ایک نظر ڈالیں: {documentation_url}", "data": { "association_type": "Association type" }, diff --git a/custom_components/battery_notes/translations/zh-Hans.json b/custom_components/battery_notes/translations/zh-Hans.json index 25be74cae..1784f488c 100644 --- a/custom_components/battery_notes/translations/zh-Hans.json +++ b/custom_components/battery_notes/translations/zh-Hans.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "若在设定过程中有任何疑问,请参考: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "若在设定过程中有任何疑问,请参考: {documentation_url}", "data": { "association_type": "关联类型" }, diff --git a/custom_components/battery_notes/translations/zh-Hant.json b/custom_components/battery_notes/translations/zh-Hant.json index 55990ceb3..a6eb1363e 100644 --- a/custom_components/battery_notes/translations/zh-Hant.json +++ b/custom_components/battery_notes/translations/zh-Hant.json @@ -2,7 +2,7 @@ "config": { "step": { "user": { - "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "New Battery Notes will be discovered if they are in the library.\nTo add new Battery Notes manually go into the integration page, select Add Battery Note and follow the instructions.\nIf you need help with the configuration have a look here: {documentation_url}", "title": "Setup Battery Notes" }, "battery": { @@ -38,7 +38,7 @@ "entry_type": "Battery note", "step": { "user": { - "description": "若在設定過程中有任何疑問,請參考: https://andrew-codechimp.github.io/HA-Battery-Notes/", + "description": "若在設定過程中有任何疑問,請參考: {documentation_url}", "data": { "association_type": "關聯類型" }, From 468b0ae90036cb6154a2f99d40864b984841b2c1 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 20 Oct 2025 11:06:51 +0000 Subject: [PATCH 206/235] Add headers to library update --- custom_components/battery_notes/library_updater.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index af7daeda7..4cbb67457 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -12,6 +12,7 @@ import aiohttp import async_timeout +from homeassistant.const import CONTENT_TYPE_JSON from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession @@ -20,6 +21,7 @@ from .const import ( DEFAULT_LIBRARY_URL, + VERSION, ) from .coordinator import MY_KEY, BatteryNotesDomainConfig from .discovery import DiscoveryManager @@ -27,6 +29,11 @@ _LOGGER = logging.getLogger(__name__) +HEADERS = { + "User-Agent": f"BatteryNotes/{VERSION}", + "Content-Type": CONTENT_TYPE_JSON + } + class LibraryUpdaterClientError(Exception): """Exception to indicate a general API error.""" @@ -172,12 +179,13 @@ def __init__( async def async_get_data(self) -> Any: """Get data from the API.""" _LOGGER.debug("Updating library from %s", DEFAULT_LIBRARY_URL) - return await self._api_wrapper(method="get", url=DEFAULT_LIBRARY_URL) + return await self._api_wrapper(method="get", url=DEFAULT_LIBRARY_URL, headers=HEADERS) async def _api_wrapper( self, method: str, url: str, + headers: dict[str, str], ) -> Any: """Get information from the API.""" try: @@ -186,6 +194,7 @@ async def _api_wrapper( method=method, url=url, allow_redirects=True, + headers=headers, ) # response.raise_for_status() return await response.text() From 3becb570999df3742083f11c559383346e5fe6aa Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 22 Oct 2025 12:06:57 +0000 Subject: [PATCH 207/235] Add Accept-Encoding header to library updater --- custom_components/battery_notes/library_updater.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index 4cbb67457..7d6dc41b6 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -31,7 +31,8 @@ HEADERS = { "User-Agent": f"BatteryNotes/{VERSION}", - "Content-Type": CONTENT_TYPE_JSON + "Content-Type": CONTENT_TYPE_JSON, + "Accept-Encoding": "gzip", } class LibraryUpdaterClientError(Exception): From d34ae1db3c45835ecdc711fef40d31b614f1d22d Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 23 Oct 2025 09:15:29 +0000 Subject: [PATCH 208/235] Set confirm_only context for user confirmation step in config flow --- custom_components/battery_notes/config_flow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index f12a3a3d7..462f02b28 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -267,7 +267,8 @@ async def async_step_user( options=options ) - self._set_confirm_only() + self.context["confirm_only"] = True + return self.async_show_form( step_id="user", description_placeholders={"documentation_url": DOCUMENTATION_URL}, From bbbadf497f524574a91ae7efbbbb41772a9031e0 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 23 Oct 2025 10:30:56 +0100 Subject: [PATCH 209/235] Revert "Set confirm_only context for user confirmation step in config flow" This reverts commit d34ae1db3c45835ecdc711fef40d31b614f1d22d. --- custom_components/battery_notes/config_flow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 462f02b28..f12a3a3d7 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -267,8 +267,7 @@ async def async_step_user( options=options ) - self.context["confirm_only"] = True - + self._set_confirm_only() return self.async_show_form( step_id="user", description_placeholders={"documentation_url": DOCUMENTATION_URL}, From bd96acb24d78a8f357f8de57b6dc7e55fcd2a93a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 30 Oct 2025 09:08:01 +0000 Subject: [PATCH 210/235] Fix docstring and import ordering --- .../battery_notes/binary_sensor.py | 73 +++++++++---------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index f213ea3c7..5a8c6d1cf 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -3,82 +3,77 @@ from __future__ import annotations import logging -from collections.abc import Callable, Mapping -from dataclasses import dataclass from typing import Any +from dataclasses import dataclass +from collections.abc import Mapping, Callable import voluptuous as vol -from homeassistant.components.binary_sensor import ( - PLATFORM_SCHEMA, - BinarySensorDeviceClass, - BinarySensorEntity, - BinarySensorEntityDescription, -) -from homeassistant.const import ( - CONF_DEVICE_ID, - CONF_NAME, - STATE_UNAVAILABLE, - STATE_UNKNOWN, -) + from homeassistant.core import ( Event, HomeAssistant, callback, split_entity_id, ) -from homeassistant.exceptions import TemplateError -from homeassistant.helpers import ( - config_validation as cv, +from homeassistant.const import ( + CONF_NAME, + STATE_UNKNOWN, + CONF_DEVICE_ID, + STATE_UNAVAILABLE, ) from homeassistant.helpers import ( + template, device_registry as dr, -) -from homeassistant.helpers import ( entity_registry as er, + config_validation as cv, ) -from homeassistant.helpers import ( - template, -) -from homeassistant.helpers.entity import Entity, EntityCategory -from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.entity_registry import ( - EVENT_ENTITY_REGISTRY_UPDATED, -) +from homeassistant.exceptions import TemplateError from homeassistant.helpers.event import ( - EventStateChangedData, TrackTemplate, TrackTemplateResult, + EventStateChangedData, TrackTemplateResultInfo, - async_track_state_change_event, async_track_template_result, + async_track_state_change_event, ) -from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.start import async_at_start +from homeassistant.helpers.entity import Entity, EntityCategory from homeassistant.helpers.template import ( Template, TemplateStateFromEntityId, ) +from homeassistant.helpers.restore_state import RestoreEntity +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.helpers.entity_registry import ( + EVENT_ENTITY_REGISTRY_UPDATED, +) +from homeassistant.components.binary_sensor import ( + PLATFORM_SCHEMA, + BinarySensorEntity, + BinarySensorDeviceClass, + BinarySensorEntityDescription, +) -from .common import validate_is_float from .const import ( - ATTR_BATTERY_LAST_REPLACED, - ATTR_BATTERY_LOW_THRESHOLD, - ATTR_BATTERY_QUANTITY, - ATTR_BATTERY_TYPE, - ATTR_BATTERY_TYPE_AND_QUANTITY, + DOMAIN, ATTR_DEVICE_ID, ATTR_DEVICE_NAME, + ATTR_BATTERY_TYPE, + ATTR_BATTERY_QUANTITY, ATTR_SOURCE_ENTITY_ID, CONF_SOURCE_ENTITY_ID, - DOMAIN, SUBENTRY_BATTERY_NOTE, + ATTR_BATTERY_LAST_REPLACED, + ATTR_BATTERY_LOW_THRESHOLD, + ATTR_BATTERY_TYPE_AND_QUANTITY, ) +from .common import validate_is_float +from .entity import BatteryNotesEntity, BatteryNotesEntityDescription from .coordinator import ( MY_KEY, BatteryNotesConfigEntry, BatteryNotesSubentryCoordinator, ) -from .entity import BatteryNotesEntity, BatteryNotesEntityDescription _LOGGER = logging.getLogger(__name__) @@ -417,7 +412,7 @@ def add_template_attribute( attribute The name of the attribute to link to. This attribute must exist unless a custom on_update method is supplied. - template + tmpl The template to calculate. validator Validator function to parse the result and ensure it's valid. From 6c3ac65454a7677190726aa2749a59ab70a531e7 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 30 Oct 2025 09:18:20 +0000 Subject: [PATCH 211/235] Reorder imports --- custom_components/battery_notes/__init__.py | 73 +++++++++--------- custom_components/battery_notes/button.py | 26 +++---- custom_components/battery_notes/common.py | 2 +- .../battery_notes/config_flow.py | 57 +++++++------- custom_components/battery_notes/const.py | 3 +- .../battery_notes/coordinator.py | 75 ++++++++++--------- .../battery_notes/diagnostics.py | 6 +- custom_components/battery_notes/discovery.py | 20 ++--- custom_components/battery_notes/filters.py | 8 +- custom_components/battery_notes/library.py | 6 +- .../battery_notes/library_updater.py | 17 +++-- custom_components/battery_notes/repairs.py | 3 +- custom_components/battery_notes/sensor.py | 75 +++++++++---------- custom_components/battery_notes/services.py | 45 ++++++----- custom_components/battery_notes/store.py | 5 +- 15 files changed, 214 insertions(+), 207 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index e70a426dc..3c138db31 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -6,65 +6,70 @@ from __future__ import annotations -import logging import re -from datetime import datetime +import logging from types import MappingProxyType +from datetime import datetime import voluptuous as vol from awesomeversion.awesomeversion import AwesomeVersion -from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry -from homeassistant.const import CONF_DEVICE_ID -from homeassistant.const import __version__ as HA_VERSION # noqa: N812 + from homeassistant.core import HassJob, HomeAssistant, callback -from homeassistant.helpers import config_validation as cv -from homeassistant.helpers import device_registry as dr -from homeassistant.helpers import entity_registry as er -from homeassistant.helpers import helper_integration -from homeassistant.helpers import issue_registry as ir -from homeassistant.helpers.device import async_entity_id_to_device_id +from homeassistant.const import ( + CONF_DEVICE_ID, + __version__ as HA_VERSION, # noqa: N812 +) +from homeassistant.helpers import ( + issue_registry as ir, + device_registry as dr, + entity_registry as er, + config_validation as cv, + helper_integration, +) from homeassistant.helpers.event import async_call_later -from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue +from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry +from homeassistant.helpers.device import async_entity_id_to_device_id from homeassistant.helpers.typing import ConfigType +from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from .const import ( - CONF_ADVANCED_SETTINGS, - CONF_BATTERY_INCREASE_THRESHOLD, - CONF_BATTERY_QUANTITY, - CONF_BATTERY_TYPE, - CONF_DEFAULT_BATTERY_LOW_THRESHOLD, + NAME as INTEGRATION_NAME, + DOMAIN, + PLATFORMS, + CONF_MODEL, + CONF_MODEL_ID, + MIN_HA_VERSION, + CONF_HW_VERSION, CONF_DEVICE_NAME, - CONF_ENABLE_AUTODISCOVERY, - CONF_ENABLE_REPLACED, + CONF_BATTERY_TYPE, CONF_HIDE_BATTERY, - CONF_HW_VERSION, CONF_MANUFACTURER, - CONF_MODEL, - CONF_MODEL_ID, + CONF_USER_LIBRARY, CONF_ROUND_BATTERY, + CONF_ENABLE_REPLACED, + CONF_BATTERY_QUANTITY, CONF_SHOW_ALL_DEVICES, - CONF_USER_LIBRARY, - DEFAULT_BATTERY_INCREASE_THRESHOLD, - DEFAULT_BATTERY_LOW_THRESHOLD, - DOMAIN, ISSUE_DEPRECATED_YAML, - MIN_HA_VERSION, - PLATFORMS, SUBENTRY_BATTERY_NOTE, + CONF_ADVANCED_SETTINGS, + CONF_ENABLE_AUTODISCOVERY, + DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD, + DEFAULT_BATTERY_INCREASE_THRESHOLD, ) -from .const import NAME as INTEGRATION_NAME +from .store import async_get_registry +from .library import DATA_LIBRARY, Library +from .services import async_setup_services +from .discovery import DiscoveryManager from .coordinator import ( MY_KEY, - BatteryNotesConfigEntry, BatteryNotesData, + BatteryNotesConfigEntry, BatteryNotesDomainConfig, BatteryNotesSubentryCoordinator, ) -from .discovery import DiscoveryManager -from .library import DATA_LIBRARY, Library from .library_updater import LibraryUpdater -from .services import async_setup_services -from .store import async_get_registry _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 015ebc1ce..90c1b5ba1 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -5,37 +5,35 @@ import logging from dataclasses import dataclass -from homeassistant.components.button import ( - ButtonEntity, - ButtonEntityDescription, -) +from homeassistant.core import HomeAssistant, callback, split_entity_id from homeassistant.const import ( CONF_DEVICE_ID, ) -from homeassistant.core import HomeAssistant, callback, split_entity_id from homeassistant.helpers import ( device_registry as dr, -) -from homeassistant.helpers import ( entity_registry as er, ) from homeassistant.helpers.entity import EntityCategory +from homeassistant.components.button import ( + ButtonEntity, + ButtonEntityDescription, +) from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from .common import utcnow_no_timezone from .const import ( - ATTR_BATTERY_QUANTITY, - ATTR_BATTERY_TYPE, - ATTR_BATTERY_TYPE_AND_QUANTITY, + DOMAIN, ATTR_DEVICE_ID, ATTR_DEVICE_NAME, + ATTR_BATTERY_TYPE, + ATTR_BATTERY_QUANTITY, ATTR_SOURCE_ENTITY_ID, - DOMAIN, - EVENT_BATTERY_REPLACED, SUBENTRY_BATTERY_NOTE, + EVENT_BATTERY_REPLACED, + ATTR_BATTERY_TYPE_AND_QUANTITY, ) -from .coordinator import BatteryNotesConfigEntry, BatteryNotesSubentryCoordinator +from .common import utcnow_no_timezone from .entity import BatteryNotesEntity, BatteryNotesEntityDescription +from .coordinator import BatteryNotesConfigEntry, BatteryNotesSubentryCoordinator _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/battery_notes/common.py b/custom_components/battery_notes/common.py index 030bf240f..9c1047609 100644 --- a/custom_components/battery_notes/common.py +++ b/custom_components/battery_notes/common.py @@ -2,8 +2,8 @@ from datetime import datetime -from homeassistant.helpers.device_registry import DeviceEntry from homeassistant.util import dt as dt_util +from homeassistant.helpers.device_registry import DeviceEntry def validate_is_float(num): diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index f12a3a3d7..0712980c4 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -6,55 +6,56 @@ from types import MappingProxyType from typing import Any +import voluptuous as vol + import homeassistant.helpers.device_registry as dr import homeassistant.helpers.entity_registry as er -import voluptuous as vol from homeassistant import config_entries -from homeassistant.components.sensor.const import SensorDeviceClass +from homeassistant.core import callback, split_entity_id +from homeassistant.const import CONF_NAME, CONF_DEVICE_ID, Platform +from homeassistant.helpers import selector from homeassistant.config_entries import ( ConfigEntry, - ConfigFlowResult, + OptionsFlow, ConfigSubentry, + ConfigFlowResult, ConfigSubentryFlow, - OptionsFlow, SubentryFlowResult, ) -from homeassistant.const import CONF_DEVICE_ID, CONF_NAME, Platform -from homeassistant.core import callback, split_entity_id -from homeassistant.data_entry_flow import section -from homeassistant.helpers import selector from homeassistant.helpers.typing import DiscoveryInfoType +from homeassistant.data_entry_flow import section +from homeassistant.components.sensor.const import SensorDeviceClass -from .common import get_device_model_id from .const import ( - CONF_ADVANCED_SETTINGS, - CONF_BATTERY_INCREASE_THRESHOLD, - CONF_BATTERY_LOW_TEMPLATE, - CONF_BATTERY_LOW_THRESHOLD, - CONF_BATTERY_QUANTITY, - CONF_BATTERY_TYPE, - CONF_DEFAULT_BATTERY_LOW_THRESHOLD, + NAME as INTEGRATION_NAME, + DOMAIN, + CONF_MODEL, + CONF_MODEL_ID, + CONF_HW_VERSION, CONF_DEVICE_NAME, - CONF_ENABLE_AUTODISCOVERY, - CONF_ENABLE_REPLACED, - CONF_FILTER_OUTLIERS, + CONF_BATTERY_TYPE, CONF_HIDE_BATTERY, - CONF_HW_VERSION, CONF_MANUFACTURER, - CONF_MODEL, - CONF_MODEL_ID, + CONF_USER_LIBRARY, CONF_ROUND_BATTERY, + CONF_ENABLE_REPLACED, + CONF_FILTER_OUTLIERS, + CONF_BATTERY_QUANTITY, CONF_SHOW_ALL_DEVICES, CONF_SOURCE_ENTITY_ID, - CONF_USER_LIBRARY, - DEFAULT_BATTERY_INCREASE_THRESHOLD, - DEFAULT_BATTERY_LOW_THRESHOLD, - DOMAIN, SUBENTRY_BATTERY_NOTE, + CONF_ADVANCED_SETTINGS, + CONF_BATTERY_LOW_TEMPLATE, + CONF_ENABLE_AUTODISCOVERY, + CONF_BATTERY_LOW_THRESHOLD, + DEFAULT_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_INCREASE_THRESHOLD, + CONF_DEFAULT_BATTERY_LOW_THRESHOLD, + DEFAULT_BATTERY_INCREASE_THRESHOLD, ) -from .const import NAME as INTEGRATION_NAME -from .coordinator import MY_KEY +from .common import get_device_model_id from .library import DATA_LIBRARY, ModelInfo +from .coordinator import MY_KEY from .library_updater import LibraryUpdater _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/battery_notes/const.py b/custom_components/battery_notes/const.py index 208dbfb31..b066fdaad 100644 --- a/custom_components/battery_notes/const.py +++ b/custom_components/battery_notes/const.py @@ -1,11 +1,12 @@ """Constants for battery_notes.""" import json +from typing import Final from logging import Logger, getLogger from pathlib import Path -from typing import Final import voluptuous as vol + from homeassistant.const import Platform from homeassistant.helpers import config_validation as cv diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 5b5adff1d..571bc4883 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -3,61 +3,64 @@ from __future__ import annotations import logging -from dataclasses import dataclass -from datetime import datetime from typing import cast +from datetime import datetime +from dataclasses import dataclass -from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN -from homeassistant.components.binary_sensor import BinarySensorDeviceClass -from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN -from homeassistant.components.sensor import SensorDeviceClass -from homeassistant.config_entries import ConfigEntry, ConfigSubentry +from homeassistant.core import CALLBACK_TYPE, HomeAssistant from homeassistant.const import ( - CONF_DEVICE_ID, PERCENTAGE, - STATE_UNAVAILABLE, STATE_UNKNOWN, + CONF_DEVICE_ID, + STATE_UNAVAILABLE, ) -from homeassistant.core import CALLBACK_TYPE, HomeAssistant -from homeassistant.helpers import device_registry as dr -from homeassistant.helpers import entity_registry as er -from homeassistant.helpers import issue_registry as ir +from homeassistant.helpers import ( + issue_registry as ir, + device_registry as dr, + entity_registry as er, +) +from homeassistant.config_entries import ConfigEntry, ConfigSubentry +from homeassistant.util.hass_dict import HassKey +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN, SensorDeviceClass from homeassistant.helpers.entity_registry import RegistryEntry +from homeassistant.components.binary_sensor import ( + DOMAIN as BINARY_SENSOR_DOMAIN, + BinarySensorDeviceClass, +) from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from homeassistant.util.hass_dict import HassKey -from .common import utcnow_no_timezone, validate_is_float from .const import ( - ATTR_BATTERY_LAST_REPLACED, - ATTR_BATTERY_LEVEL, - ATTR_BATTERY_LOW, - ATTR_BATTERY_LOW_THRESHOLD, - ATTR_BATTERY_QUANTITY, - ATTR_BATTERY_THRESHOLD_REMINDER, - ATTR_BATTERY_TYPE, - ATTR_BATTERY_TYPE_AND_QUANTITY, + DOMAIN, + ATTR_REMOVE, + LAST_REPLACED, + LAST_REPORTED, ATTR_DEVICE_ID, + ATTR_BATTERY_LOW, ATTR_DEVICE_NAME, - ATTR_PREVIOUS_BATTERY_LEVEL, - ATTR_REMOVE, - ATTR_SOURCE_ENTITY_ID, - CONF_BATTERY_LOW_TEMPLATE, - CONF_BATTERY_LOW_THRESHOLD, - CONF_BATTERY_QUANTITY, + ATTR_BATTERY_TYPE, CONF_BATTERY_TYPE, + ATTR_BATTERY_LEVEL, + LAST_REPORTED_LEVEL, CONF_FILTER_OUTLIERS, + ATTR_BATTERY_QUANTITY, + ATTR_SOURCE_ENTITY_ID, + CONF_BATTERY_QUANTITY, CONF_SOURCE_ENTITY_ID, - DEFAULT_BATTERY_INCREASE_THRESHOLD, - DEFAULT_BATTERY_LOW_THRESHOLD, - DOMAIN, EVENT_BATTERY_INCREASED, EVENT_BATTERY_THRESHOLD, - LAST_REPLACED, - LAST_REPORTED, - LAST_REPORTED_LEVEL, + CONF_BATTERY_LOW_TEMPLATE, + ATTR_BATTERY_LAST_REPLACED, + ATTR_BATTERY_LOW_THRESHOLD, + CONF_BATTERY_LOW_THRESHOLD, + ATTR_PREVIOUS_BATTERY_LEVEL, + DEFAULT_BATTERY_LOW_THRESHOLD, + ATTR_BATTERY_TYPE_AND_QUANTITY, + ATTR_BATTERY_THRESHOLD_REMINDER, + DEFAULT_BATTERY_INCREASE_THRESHOLD, ) -from .filters import LowOutlierFilter from .store import BatteryNotesStorage +from .common import validate_is_float, utcnow_no_timezone +from .filters import LowOutlierFilter _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/battery_notes/diagnostics.py b/custom_components/battery_notes/diagnostics.py index 45e5ab87b..ab3e46b50 100644 --- a/custom_components/battery_notes/diagnostics.py +++ b/custom_components/battery_notes/diagnostics.py @@ -4,17 +4,15 @@ from typing import Any -from homeassistant.const import CONF_DEVICE_ID from homeassistant.core import HomeAssistant +from homeassistant.const import CONF_DEVICE_ID from homeassistant.helpers import ( device_registry as dr, -) -from homeassistant.helpers import ( entity_registry as er, ) -from .common import get_device_model_id from .const import CONF_SOURCE_ENTITY_ID +from .common import get_device_model_id from .coordinator import BatteryNotesConfigEntry diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index e8ff6b252..97d752e66 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -6,24 +6,24 @@ from typing import Any import homeassistant.helpers.device_registry as dr -from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_INTEGRATION_DISCOVERY -from homeassistant.const import CONF_DEVICE_ID from homeassistant.core import HomeAssistant, callback +from homeassistant.const import CONF_DEVICE_ID from homeassistant.helpers import discovery_flow +from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_INTEGRATION_DISCOVERY -from .common import get_device_model_id from .const import ( - CONF_BATTERY_QUANTITY, - CONF_BATTERY_TYPE, - CONF_DEVICE_NAME, - CONF_HW_VERSION, - CONF_MANUFACTURER, + DOMAIN, CONF_MODEL, CONF_MODEL_ID, - DOMAIN, + CONF_HW_VERSION, + CONF_DEVICE_NAME, + CONF_BATTERY_TYPE, + CONF_MANUFACTURER, + CONF_BATTERY_QUANTITY, ) +from .common import get_device_model_id +from .library import DATA_LIBRARY, ModelInfo, DeviceBatteryDetails from .coordinator import BatteryNotesDomainConfig -from .library import DATA_LIBRARY, DeviceBatteryDetails, ModelInfo _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/battery_notes/filters.py b/custom_components/battery_notes/filters.py index 77f56fe38..e13dc7809 100644 --- a/custom_components/battery_notes/filters.py +++ b/custom_components/battery_notes/filters.py @@ -2,13 +2,13 @@ import logging import statistics -from collections import Counter, deque -from datetime import timedelta -from numbers import Number from typing import cast +from numbers import Number +from datetime import timedelta +from collections import Counter, deque +from .const import WINDOW_SIZE_UNIT_TIME, WINDOW_SIZE_UNIT_NUMBER_EVENTS from .common import utcnow_no_timezone -from .const import WINDOW_SIZE_UNIT_NUMBER_EVENTS, WINDOW_SIZE_UNIT_TIME _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index f09cf8b8d..e212708c5 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -2,15 +2,15 @@ from __future__ import annotations +import os import json import logging -import os -from dataclasses import dataclass from typing import Any, Final, NamedTuple, cast +from dataclasses import dataclass from homeassistant.core import HomeAssistant -from homeassistant.helpers.storage import STORAGE_DIR from homeassistant.util.hass_dict import HassKey +from homeassistant.helpers.storage import STORAGE_DIR from .const import DOMAIN from .coordinator import MY_KEY diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index 7d6dc41b6..8298587a6 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -2,30 +2,31 @@ from __future__ import annotations -import json -import logging import os +import json import shutil import socket -from datetime import datetime, timedelta +import logging from typing import Any +from datetime import datetime, timedelta import aiohttp import async_timeout -from homeassistant.const import CONTENT_TYPE_JSON + from homeassistant.core import HomeAssistant, callback +from homeassistant.const import CONTENT_TYPE_JSON from homeassistant.exceptions import ConfigEntryNotReady -from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.event import async_track_utc_time_change from homeassistant.helpers.storage import STORAGE_DIR +from homeassistant.helpers.aiohttp_client import async_get_clientsession from .const import ( - DEFAULT_LIBRARY_URL, VERSION, + DEFAULT_LIBRARY_URL, ) -from .coordinator import MY_KEY, BatteryNotesDomainConfig -from .discovery import DiscoveryManager from .library import DATA_LIBRARY +from .discovery import DiscoveryManager +from .coordinator import MY_KEY, BatteryNotesDomainConfig _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/battery_notes/repairs.py b/custom_components/battery_notes/repairs.py index 8450ff5c2..b91da2613 100644 --- a/custom_components/battery_notes/repairs.py +++ b/custom_components/battery_notes/repairs.py @@ -5,10 +5,11 @@ from typing import cast import voluptuous as vol + from homeassistant import data_entry_flow -from homeassistant.components.repairs import RepairsFlow from homeassistant.core import HomeAssistant from homeassistant.helpers import issue_registry as ir +from homeassistant.components.repairs import RepairsFlow REQUIRED_KEYS = ("entry_id", "device_id", "source_entity_id") diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 2e7222d6a..7cd009c0e 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -3,39 +3,24 @@ from __future__ import annotations import logging -from collections.abc import Mapping -from dataclasses import dataclass -from datetime import datetime from typing import Any +from datetime import datetime +from dataclasses import dataclass +from collections.abc import Mapping import voluptuous as vol -from homeassistant.components.sensor import ( - PLATFORM_SCHEMA, - RestoreSensor, - SensorDeviceClass, - SensorEntity, - SensorEntityDescription, - SensorStateClass, -) -from homeassistant.config_entries import ConfigSubentry + +from homeassistant.core import Event, HomeAssistant, callback from homeassistant.const import ( - CONF_DEVICE_ID, CONF_NAME, PERCENTAGE, - STATE_UNAVAILABLE, STATE_UNKNOWN, -) -from homeassistant.core import Event, HomeAssistant, callback -from homeassistant.helpers import ( - config_validation as cv, + CONF_DEVICE_ID, + STATE_UNAVAILABLE, ) from homeassistant.helpers import ( entity_registry as er, -) -from homeassistant.helpers.entity import EntityCategory -from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.entity_registry import ( - EVENT_ENTITY_REGISTRY_UPDATED, + config_validation as cv, ) from homeassistant.helpers.event import ( EventStateChangedData, @@ -43,36 +28,50 @@ async_track_state_change_event, async_track_state_report_event, ) +from homeassistant.config_entries import ConfigSubentry +from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.typing import StateType +from homeassistant.components.sensor import ( + PLATFORM_SCHEMA, + SensorEntity, + RestoreSensor, + SensorStateClass, + SensorDeviceClass, + SensorEntityDescription, +) +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.helpers.entity_registry import ( + EVENT_ENTITY_REGISTRY_UPDATED, +) -from .common import utcnow_no_timezone, validate_is_float from .const import ( - ATTR_BATTERY_LAST_REPLACED, - ATTR_BATTERY_LAST_REPORTED, - ATTR_BATTERY_LAST_REPORTED_LEVEL, - ATTR_BATTERY_LOW, - ATTR_BATTERY_LOW_THRESHOLD, - ATTR_BATTERY_QUANTITY, - ATTR_BATTERY_TYPE, - ATTR_BATTERY_TYPE_AND_QUANTITY, + DOMAIN, ATTR_DEVICE_ID, + ATTR_BATTERY_LOW, ATTR_DEVICE_NAME, - ATTR_SOURCE_ENTITY_ID, - CONF_ADVANCED_SETTINGS, - CONF_BATTERY_QUANTITY, + ATTR_BATTERY_TYPE, CONF_BATTERY_TYPE, - CONF_ENABLE_REPLACED, CONF_ROUND_BATTERY, + CONF_ENABLE_REPLACED, + ATTR_BATTERY_QUANTITY, + ATTR_SOURCE_ENTITY_ID, + CONF_BATTERY_QUANTITY, CONF_SOURCE_ENTITY_ID, - DOMAIN, SUBENTRY_BATTERY_NOTE, + CONF_ADVANCED_SETTINGS, + ATTR_BATTERY_LAST_REPLACED, + ATTR_BATTERY_LAST_REPORTED, + ATTR_BATTERY_LOW_THRESHOLD, + ATTR_BATTERY_TYPE_AND_QUANTITY, + ATTR_BATTERY_LAST_REPORTED_LEVEL, ) +from .common import validate_is_float, utcnow_no_timezone +from .entity import BatteryNotesEntity, BatteryNotesEntityDescription from .coordinator import ( MY_KEY, BatteryNotesConfigEntry, BatteryNotesSubentryCoordinator, ) -from .entity import BatteryNotesEntity, BatteryNotesEntityDescription @dataclass(frozen=True, kw_only=True) diff --git a/custom_components/battery_notes/services.py b/custom_components/battery_notes/services.py index 223a9e036..71403d052 100644 --- a/custom_components/battery_notes/services.py +++ b/custom_components/battery_notes/services.py @@ -1,49 +1,48 @@ """Define services for the Battery Notes integration.""" import logging -from datetime import datetime from typing import cast +from datetime import datetime from homeassistant.core import ( - HomeAssistant, ServiceCall, + HomeAssistant, ServiceResponse, callback, ) -from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers import device_registry as dr -from homeassistant.helpers import entity_registry as er from homeassistant.util import dt as dt_util +from homeassistant.helpers import device_registry as dr, entity_registry as er +from homeassistant.exceptions import HomeAssistantError -from .common import utcnow_no_timezone from .const import ( - ATTR_BATTERY_LAST_REPLACED, - ATTR_BATTERY_LAST_REPORTED, - ATTR_BATTERY_LAST_REPORTED_DAYS, - ATTR_BATTERY_LAST_REPORTED_LEVEL, - ATTR_BATTERY_LEVEL, - ATTR_BATTERY_LOW, - ATTR_BATTERY_LOW_THRESHOLD, - ATTR_BATTERY_QUANTITY, - ATTR_BATTERY_THRESHOLD_REMINDER, - ATTR_BATTERY_TYPE, - ATTR_BATTERY_TYPE_AND_QUANTITY, + DOMAIN, ATTR_DEVICE_ID, + ATTR_BATTERY_LOW, ATTR_DEVICE_NAME, - ATTR_PREVIOUS_BATTERY_LEVEL, + ATTR_BATTERY_TYPE, + ATTR_BATTERY_LEVEL, + ATTR_BATTERY_QUANTITY, ATTR_SOURCE_ENTITY_ID, - DOMAIN, - EVENT_BATTERY_NOT_REPORTED, EVENT_BATTERY_REPLACED, EVENT_BATTERY_THRESHOLD, SERVICE_BATTERY_REPLACED, - SERVICE_BATTERY_REPLACED_SCHEMA, - SERVICE_CHECK_BATTERY_LAST_REPORTED, - SERVICE_CHECK_BATTERY_LAST_REPORTED_SCHEMA, SERVICE_CHECK_BATTERY_LOW, + ATTR_BATTERY_LAST_REPLACED, + ATTR_BATTERY_LAST_REPORTED, + ATTR_BATTERY_LOW_THRESHOLD, + EVENT_BATTERY_NOT_REPORTED, + ATTR_PREVIOUS_BATTERY_LEVEL, + ATTR_BATTERY_TYPE_AND_QUANTITY, + ATTR_BATTERY_LAST_REPORTED_DAYS, + ATTR_BATTERY_THRESHOLD_REMINDER, + SERVICE_BATTERY_REPLACED_SCHEMA, SERVICE_DATA_DATE_TIME_REPLACED, SERVICE_DATA_DAYS_LAST_REPORTED, + ATTR_BATTERY_LAST_REPORTED_LEVEL, + SERVICE_CHECK_BATTERY_LAST_REPORTED, + SERVICE_CHECK_BATTERY_LAST_REPORTED_SCHEMA, ) +from .common import utcnow_no_timezone from .coordinator import BatteryNotesConfigEntry _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/battery_notes/store.py b/custom_components/battery_notes/store.py index bb30d7969..30c62fb50 100644 --- a/custom_components/battery_notes/store.py +++ b/custom_components/battery_notes/store.py @@ -3,12 +3,13 @@ from __future__ import annotations import logging +from typing import Any, cast +from datetime import datetime from collections import OrderedDict from collections.abc import MutableMapping -from datetime import datetime -from typing import Any, cast import attr + from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.storage import Store From 24acfc4951921d81a37cde7e46813dee7be8b3c6 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 30 Oct 2025 09:20:48 +0000 Subject: [PATCH 212/235] Lint --- custom_components/battery_notes/config_flow.py | 2 +- custom_components/battery_notes/services.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 0712980c4..7806c0ae0 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -166,7 +166,7 @@ def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow: @classmethod @callback def async_get_supported_subentry_types( - cls, config_entry: ConfigEntry + cls, config_entry: ConfigEntry # noqa: ARG003 ) -> dict[str, type[ConfigSubentryFlow]]: """Return subentries supported by this integration.""" return { diff --git a/custom_components/battery_notes/services.py b/custom_components/battery_notes/services.py index 71403d052..2dc96fddc 100644 --- a/custom_components/battery_notes/services.py +++ b/custom_components/battery_notes/services.py @@ -70,7 +70,6 @@ def async_setup_services(hass: HomeAssistant) -> None: SERVICE_CHECK_BATTERY_LOW, _async_battery_low, ) - return None async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: From 82a771105ffc04d4be5708b76117e0e351ad662a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 30 Oct 2025 09:26:57 +0000 Subject: [PATCH 213/235] Formatting --- custom_components/battery_notes/__init__.py | 139 ++++++++++----- .../battery_notes/binary_sensor.py | 79 +++++---- custom_components/battery_notes/button.py | 15 +- custom_components/battery_notes/common.py | 2 + .../battery_notes/config_flow.py | 160 ++++++++++++------ .../battery_notes/coordinator.py | 101 +++++++---- custom_components/battery_notes/discovery.py | 17 +- custom_components/battery_notes/entity.py | 17 +- custom_components/battery_notes/filters.py | 15 +- custom_components/battery_notes/library.py | 82 +++++---- .../battery_notes/library_updater.py | 30 ++-- custom_components/battery_notes/repairs.py | 12 +- custom_components/battery_notes/sensor.py | 42 +++-- custom_components/battery_notes/services.py | 41 +++-- custom_components/battery_notes/store.py | 6 +- 15 files changed, 475 insertions(+), 283 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 3c138db31..c8203f2a5 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -100,6 +100,7 @@ extra=vol.ALLOW_EXTRA, ) + async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Integration setup.""" @@ -140,12 +141,22 @@ async def async_setup_entry( domain_config.show_all_devices = config_entry.options[CONF_SHOW_ALL_DEVICES] domain_config.hide_battery = config_entry.options[CONF_HIDE_BATTERY] domain_config.round_battery = config_entry.options[CONF_ROUND_BATTERY] - domain_config.default_battery_low_threshold = config_entry.options[CONF_DEFAULT_BATTERY_LOW_THRESHOLD] - domain_config.battery_increased_threshod = config_entry.options[CONF_BATTERY_INCREASE_THRESHOLD] + domain_config.default_battery_low_threshold = config_entry.options[ + CONF_DEFAULT_BATTERY_LOW_THRESHOLD + ] + domain_config.battery_increased_threshod = config_entry.options[ + CONF_BATTERY_INCREASE_THRESHOLD + ] - domain_config.enable_autodiscovery = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_ENABLE_AUTODISCOVERY] - domain_config.enable_replaced = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_ENABLE_REPLACED] - domain_config.user_library = config_entry.options[CONF_ADVANCED_SETTINGS][CONF_USER_LIBRARY] + domain_config.enable_autodiscovery = config_entry.options[CONF_ADVANCED_SETTINGS][ + CONF_ENABLE_AUTODISCOVERY + ] + domain_config.enable_replaced = config_entry.options[CONF_ADVANCED_SETTINGS][ + CONF_ENABLE_REPLACED + ] + domain_config.user_library = config_entry.options[CONF_ADVANCED_SETTINGS][ + CONF_USER_LIBRARY + ] config_entry.runtime_data = BatteryNotesData( domain_config=domain_config, @@ -158,19 +169,21 @@ async def async_setup_entry( config_entry.runtime_data.subentry_coordinators = {} for subentry in config_entry.subentries.values(): if subentry.subentry_type == SUBENTRY_BATTERY_NOTE: - coordinator = BatteryNotesSubentryCoordinator(hass, config_entry, subentry) - config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = coordinator + config_entry.runtime_data.subentry_coordinators[subentry.subentry_id] = ( + coordinator + ) assert subentry.unique_id await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) - config_entry.async_on_unload(config_entry.add_update_listener(_async_update_listener)) - + config_entry.async_on_unload( + config_entry.add_update_listener(_async_update_listener) + ) @callback - async def _async_delayed_discovery(now: datetime) -> None: #pylint: disable=unused-argument + async def _async_delayed_discovery(now: datetime) -> None: # pylint: disable=unused-argument """Update the library and do discovery.""" library_updater = LibraryUpdater(hass) await library_updater.copy_schema() @@ -185,7 +198,9 @@ async def _async_delayed_discovery(now: datetime) -> None: #pylint: disable=unus async_call_later( hass, DISCOVERY_DELAY, - HassJob(_async_delayed_discovery, "battery notes discovery", cancel_on_shutdown=True), + HassJob( + _async_delayed_discovery, "battery notes discovery", cancel_on_shutdown=True + ), ) return True @@ -206,7 +221,10 @@ async def async_remove_entry( for subentry in config_entry.subentries.values(): if subentry.subentry_id not in config_entry.subentries: - await _async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) + await _async_remove_subentry( + hass, config_entry, subentry, remove_store_entries=False + ) + async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> None: """Migrate integration entry structure.""" @@ -234,7 +252,9 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> key=lambda e: e.disabled_by is not None, ) - if not any(entry.version < 3 and entry.source != SOURCE_IGNORE for entry in entries): + if not any( + entry.version < 3 and entry.source != SOURCE_IGNORE for entry in entries + ): return for entry in entries: @@ -272,24 +292,36 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if not migrate_base_entry: if yaml_domain_config: - options={ - CONF_SHOW_ALL_DEVICES: yaml_domain_config.get(CONF_SHOW_ALL_DEVICES, False), + options = { + CONF_SHOW_ALL_DEVICES: yaml_domain_config.get( + CONF_SHOW_ALL_DEVICES, False + ), CONF_HIDE_BATTERY: yaml_domain_config.get(CONF_HIDE_BATTERY, False), - CONF_ROUND_BATTERY: yaml_domain_config.get(CONF_ROUND_BATTERY, False), + CONF_ROUND_BATTERY: yaml_domain_config.get( + CONF_ROUND_BATTERY, False + ), CONF_DEFAULT_BATTERY_LOW_THRESHOLD: yaml_domain_config.get( - CONF_DEFAULT_BATTERY_LOW_THRESHOLD, DEFAULT_BATTERY_LOW_THRESHOLD + CONF_DEFAULT_BATTERY_LOW_THRESHOLD, + DEFAULT_BATTERY_LOW_THRESHOLD, ), CONF_BATTERY_INCREASE_THRESHOLD: yaml_domain_config.get( - CONF_BATTERY_INCREASE_THRESHOLD, DEFAULT_BATTERY_INCREASE_THRESHOLD + CONF_BATTERY_INCREASE_THRESHOLD, + DEFAULT_BATTERY_INCREASE_THRESHOLD, ), CONF_ADVANCED_SETTINGS: { - CONF_ENABLE_AUTODISCOVERY: yaml_domain_config.get(CONF_ENABLE_AUTODISCOVERY, True), - CONF_ENABLE_REPLACED: yaml_domain_config.get(CONF_ENABLE_REPLACED, True), - CONF_USER_LIBRARY: yaml_domain_config.get(CONF_USER_LIBRARY, ""), + CONF_ENABLE_AUTODISCOVERY: yaml_domain_config.get( + CONF_ENABLE_AUTODISCOVERY, True + ), + CONF_ENABLE_REPLACED: yaml_domain_config.get( + CONF_ENABLE_REPLACED, True + ), + CONF_USER_LIBRARY: yaml_domain_config.get( + CONF_USER_LIBRARY, "" + ), }, } else: - options={ + options = { CONF_SHOW_ALL_DEVICES: False, CONF_HIDE_BATTERY: False, CONF_ROUND_BATTERY: False, @@ -324,19 +356,19 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> if "_" not in entity_entry.unique_id: new_unique_id = f"{subentry.unique_id}_battery_type" else: - new_unique_id = f"{subentry.unique_id}_{entity_entry.unique_id.split("_", 1)[1]}" + new_unique_id = f"{subentry.unique_id}_{entity_entry.unique_id.split('_', 1)[1]}" entity_disabled_by = entity_entry.disabled_by if entity_disabled_by: entity_disabled_by = er.RegistryEntryDisabler.USER entity_registry.async_update_entity( - entity_entry.entity_id, - config_entry_id=migrate_base_entry.entry_id, - config_subentry_id=subentry.subentry_id, - disabled_by=entity_disabled_by, - new_unique_id=new_unique_id, - ) + entity_entry.entity_id, + config_entry_id=migrate_base_entry.entry_id, + config_subentry_id=subentry.subentry_id, + disabled_by=entity_disabled_by, + new_unique_id=new_unique_id, + ) # Remove the config entry from the device source_device_id = subentry.data.get(CONF_DEVICE_ID, None) @@ -347,12 +379,14 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> source_entity_id = subentry.data.get("source_entity_id", None) if source_entity_id: - source_device_id = async_entity_id_to_device_id( - hass, source_entity_id - ) + source_device_id = async_entity_id_to_device_id(hass, source_entity_id) if source_device_id: - helper_integration.async_remove_helper_config_entry_from_source_device(hass=hass, helper_config_entry_id=entry.entry_id, source_device_id=source_device_id) + helper_integration.async_remove_helper_config_entry_from_source_device( + hass=hass, + helper_config_entry_id=entry.entry_id, + source_device_id=source_device_id, + ) # Remove the old config entry if entry.entry_id != migrate_base_entry.entry_id: @@ -369,7 +403,11 @@ async def async_migrate_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry ) -> bool: """Migrate old config.""" - _LOGGER.debug("Migrating configuration from version %s.%s", config_entry.version, config_entry.minor_version) + _LOGGER.debug( + "Migrating configuration from version %s.%s", + config_entry.version, + config_entry.minor_version, + ) if config_entry.version > 3: # This means the user has downgraded from a future version @@ -423,7 +461,9 @@ async def _async_update_listener( for subentry in config_entry.runtime_data.loaded_subentries.values(): if subentry.subentry_id not in config_entry.subentries: - await _async_remove_subentry(hass, config_entry, subentry, remove_store_entries=False) + await _async_remove_subentry( + hass, config_entry, subentry, remove_store_entries=False + ) # Update the config entry with the new sub entries config_entry.runtime_data.loaded_subentries = config_entry.subentries.copy() @@ -438,10 +478,16 @@ async def _async_remove_subentry( remove_store_entries: bool, ) -> None: """Remove a sub entry.""" - _LOGGER.debug("Removing sub entry %s from config entry %s", subentry.subentry_id, config_entry.entry_id) + _LOGGER.debug( + "Removing sub entry %s from config entry %s", + subentry.subentry_id, + config_entry.entry_id, + ) assert config_entry.runtime_data.subentry_coordinators - coordinator = config_entry.runtime_data.subentry_coordinators.get(subentry.subentry_id) + coordinator = config_entry.runtime_data.subentry_coordinators.get( + subentry.subentry_id + ) assert coordinator # Remove any issues raised @@ -460,16 +506,19 @@ async def _async_remove_subentry( # Unhide the battery if coordinator.wrapped_battery: entity_registry = er.async_get(hass) - if ( - wrapped_battery_entity_entry := entity_registry.async_get( - coordinator.wrapped_battery.entity_id - ) + if wrapped_battery_entity_entry := entity_registry.async_get( + coordinator.wrapped_battery.entity_id ): - if wrapped_battery_entity_entry.hidden_by == er.RegistryEntryHider.INTEGRATION: + if ( + wrapped_battery_entity_entry.hidden_by + == er.RegistryEntryHider.INTEGRATION + ): entity_registry.async_update_entity( coordinator.wrapped_battery.entity_id, hidden_by=None ) - _LOGGER.debug("Unhidden Original Battery for device%s", coordinator.device_id) + _LOGGER.debug( + "Unhidden Original Battery for device%s", coordinator.device_id + ) config_entry.runtime_data.subentry_coordinators.pop(subentry.subentry_id) @@ -483,4 +532,6 @@ async def _async_remove_subentry( for entity_id in entities_to_remove: entity_registry.async_remove(entity_id) - _LOGGER.debug("Removed entity %s for subentry %s", entity_id, subentry.subentry_id) + _LOGGER.debug( + "Removed entity %s for subentry %s", entity_id, subentry.subentry_id + ) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 5a8c6d1cf..839c62506 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -98,7 +98,9 @@ class BatteryNotesBinarySensorEntityDescription( @callback -def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry) -> str | None: +def async_add_to_device( + hass: HomeAssistant, entry: BatteryNotesConfigEntry +) -> str | None: """Add our config entry to the device.""" device_registry = dr.async_get(hass) @@ -146,7 +148,11 @@ async def async_setup_entry( entity_type="binary_sensor", ) - entities: list[BatteryNotesBatteryLowTemplateSensor | BatteryNotesBatteryLowSensor | BatteryNotesBatteryBinaryLowSensor] = [] + entities: list[ + BatteryNotesBatteryLowTemplateSensor + | BatteryNotesBatteryLowSensor + | BatteryNotesBatteryBinaryLowSensor + ] = [] if coordinator.battery_low_template is not None: entities.append( @@ -282,9 +288,7 @@ def handle_result( return -class BatteryNotesBatteryLowBaseSensor( - BatteryNotesEntity, BinarySensorEntity -): +class BatteryNotesBatteryLowBaseSensor(BatteryNotesEntity, BinarySensorEntity): """Low battery binary sensor base.""" entity_description: BatteryNotesBinarySensorEntityDescription @@ -297,7 +301,9 @@ def __init__( ): """Initialize the low battery binary sensor.""" - super().__init__(hass, entity_description=entity_description, coordinator=coordinator) + super().__init__( + hass, entity_description=entity_description, coordinator=coordinator + ) self.enable_replaced = hass.data[MY_KEY].enable_replaced @@ -358,7 +364,9 @@ def __init__( ) -> None: """Create a low battery binary sensor.""" - super().__init__(hass=hass, coordinator=coordinator, entity_description=entity_description) + super().__init__( + hass=hass, coordinator=coordinator, entity_description=entity_description + ) self._attr_unique_id = unique_id self._template_attrs: dict[Template, list[_TemplateAttribute]] = {} @@ -368,22 +376,18 @@ def __init__( self._attr_translation_placeholders = { "device_name": coordinator.device_name + " " } - self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" - ) + self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" elif coordinator.source_entity_id and coordinator.device_id: - _, source_object_id = split_entity_id( - coordinator.source_entity_id - ) + _, source_object_id = split_entity_id(coordinator.source_entity_id) self._attr_translation_placeholders = { "device_name": coordinator.source_entity_name + " " } - self.entity_id = f"binary_sensor.{source_object_id}_{entity_description.key}" - else: - self._attr_translation_placeholders = {"device_name": ""} self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" + f"binary_sensor.{source_object_id}_{entity_description.key}" ) + else: + self._attr_translation_placeholders = {"device_name": ""} + self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" self._template = tmpl self._state: bool | None = None @@ -552,28 +556,26 @@ def __init__( unique_id: str, ) -> None: """Create a low battery binary sensor.""" - super().__init__(hass=hass, coordinator=coordinator, entity_description=entity_description) + super().__init__( + hass=hass, coordinator=coordinator, entity_description=entity_description + ) if coordinator.source_entity_id and not coordinator.device_id: self._attr_translation_placeholders = { "device_name": coordinator.device_name + " " } - self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" - ) + self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" elif coordinator.source_entity_id and coordinator.device_id: - _, source_object_id = split_entity_id( - coordinator.source_entity_id - ) + _, source_object_id = split_entity_id(coordinator.source_entity_id) self._attr_translation_placeholders = { "device_name": coordinator.source_entity_name + " " } - self.entity_id = f"binary_sensor.{source_object_id}_{entity_description.key}" - else: - self._attr_translation_placeholders = {"device_name": ""} self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" + f"binary_sensor.{source_object_id}_{entity_description.key}" ) + else: + self._attr_translation_placeholders = {"device_name": ""} + self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" self._attr_unique_id = unique_id @@ -632,28 +634,26 @@ def __init__( unique_id: str, ) -> None: """Create a low battery binary sensor.""" - super().__init__(hass=hass, coordinator=coordinator, entity_description=entity_description) + super().__init__( + hass=hass, coordinator=coordinator, entity_description=entity_description + ) if coordinator.source_entity_id and not coordinator.device_id: self._attr_translation_placeholders = { "device_name": coordinator.device_name + " " } - self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" - ) + self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" elif coordinator.source_entity_id and coordinator.device_id: - _, source_object_id = split_entity_id( - coordinator.source_entity_id - ) + _, source_object_id = split_entity_id(coordinator.source_entity_id) self._attr_translation_placeholders = { "device_name": coordinator.source_entity_name + " " } - self.entity_id = f"binary_sensor.{source_object_id}_{entity_description.key}" - else: - self._attr_translation_placeholders = {"device_name": ""} self.entity_id = ( - f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" + f"binary_sensor.{source_object_id}_{entity_description.key}" ) + else: + self._attr_translation_placeholders = {"device_name": ""} + self.entity_id = f"binary_sensor.{coordinator.device_name.lower()}_{entity_description.key}" self._attr_unique_id = unique_id @@ -869,4 +869,3 @@ def _handle_coordinator_update(self) -> None: def is_on(self) -> bool | None: """Return true if sensor is on.""" return self._attr_is_on - diff --git a/custom_components/battery_notes/button.py b/custom_components/battery_notes/button.py index 90c1b5ba1..2020f37ce 100644 --- a/custom_components/battery_notes/button.py +++ b/custom_components/battery_notes/button.py @@ -49,7 +49,9 @@ class BatteryNotesButtonEntityDescription( @callback -def async_add_to_device(hass: HomeAssistant, entry: BatteryNotesConfigEntry) -> str | None: +def async_add_to_device( + hass: HomeAssistant, entry: BatteryNotesConfigEntry +) -> str | None: """Add our config entry to the device.""" device_registry = dr.async_get(hass) @@ -125,7 +127,9 @@ def __init__( ) -> None: """Create a battery replaced button.""" - super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) + super().__init__( + hass=hass, entity_description=entity_description, coordinator=coordinator + ) if coordinator.source_entity_id and not coordinator.device_id: self._attr_translation_placeholders = { @@ -135,9 +139,7 @@ def __init__( f"button.{coordinator.device_name.lower()}_{entity_description.key}" ) elif coordinator.source_entity_id and coordinator.device_id: - _, source_object_id = split_entity_id( - coordinator.source_entity_id - ) + _, source_object_id = split_entity_id(coordinator.source_entity_id) self._attr_translation_placeholders = { "device_name": coordinator.source_entity_name + " " } @@ -169,8 +171,7 @@ async def async_press(self) -> None: EVENT_BATTERY_REPLACED, { ATTR_DEVICE_ID: self.coordinator.device_id or "", - ATTR_SOURCE_ENTITY_ID: self.coordinator.source_entity_id - or "", + ATTR_SOURCE_ENTITY_ID: self.coordinator.source_entity_id or "", ATTR_DEVICE_NAME: self.coordinator.device_name, ATTR_BATTERY_TYPE_AND_QUANTITY: self.coordinator.battery_type_and_quantity, ATTR_BATTERY_TYPE: self.coordinator.battery_type, diff --git a/custom_components/battery_notes/common.py b/custom_components/battery_notes/common.py index 9c1047609..a762e01e0 100644 --- a/custom_components/battery_notes/common.py +++ b/custom_components/battery_notes/common.py @@ -16,11 +16,13 @@ def validate_is_float(num): return False return False + def utcnow_no_timezone() -> datetime: """Return UTC now without timezone information.""" return dt_util.utcnow().replace(tzinfo=None) + def get_device_model_id(device_entry: DeviceEntry) -> str | None: """Get the device model if available.""" return device_entry.model_id if hasattr(device_entry, "model_id") else None diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 7806c0ae0..05f2b813c 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -79,7 +79,6 @@ min=0, max=99, mode=selector.NumberSelectorMode.BOX ), ), - vol.Required(CONF_ADVANCED_SETTINGS): section( vol.Schema( { @@ -89,7 +88,7 @@ } ), {"collapsed": True}, - ) + ), } ) @@ -166,7 +165,8 @@ def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow: @classmethod @callback def async_get_supported_subentry_types( - cls, config_entry: ConfigEntry # noqa: ARG003 + cls, + config_entry: ConfigEntry, # noqa: ARG003 ) -> dict[str, type[ConfigSubentryFlow]]: """Return subentries supported by this integration.""" return { @@ -175,7 +175,9 @@ def async_get_supported_subentry_types( async def async_get_integration_entry(self) -> ConfigEntry | None: """Return the main integration config entry, if it exists.""" - existing_entries = self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False) + existing_entries = self.hass.config_entries.async_entries( + domain=DOMAIN, include_ignore=False, include_disabled=False + ) for entry in existing_entries: if entry.title == INTEGRATION_NAME: return entry @@ -206,14 +208,10 @@ async def async_step_integration_discovery( CONF_ENABLE_AUTODISCOVERY: True, CONF_ENABLE_REPLACED: True, CONF_USER_LIBRARY: "", - } + }, } - self.async_create_entry( - title=INTEGRATION_NAME, - data={}, - options=options - ) + self.async_create_entry(title=INTEGRATION_NAME, data={}, options=options) config_entry = await self.async_get_integration_entry() if not config_entry: @@ -259,13 +257,11 @@ async def async_step_user( CONF_ENABLE_AUTODISCOVERY: True, CONF_ENABLE_REPLACED: True, CONF_USER_LIBRARY: "", - } + }, } return self.async_create_entry( - title=INTEGRATION_NAME, - data={}, - options=options + title=INTEGRATION_NAME, data={}, options=options ) self._set_confirm_only() @@ -274,7 +270,6 @@ async def async_step_user( description_placeholders={"documentation_url": DOCUMENTATION_URL}, ) - async def async_step_device( self, user_input: dict | None = None, @@ -375,7 +370,9 @@ async def async_step_battery( self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input.get( CONF_BATTERY_LOW_TEMPLATE, None ) - self.data[CONF_FILTER_OUTLIERS] = user_input.get(CONF_FILTER_OUTLIERS, False) + self.data[CONF_FILTER_OUTLIERS] = user_input.get( + CONF_FILTER_OUTLIERS, False + ) source_entity_id = self.data.get(CONF_SOURCE_ENTITY_ID, None) device_id = self.data.get(CONF_DEVICE_ID, None) @@ -386,9 +383,7 @@ async def async_step_battery( if source_entity_id: entity_registry = er.async_get(self.hass) entity_entry = entity_registry.async_get(source_entity_id) - _, source_object_id = split_entity_id( - source_entity_id - ) + _, source_object_id = split_entity_id(source_entity_id) if entity_entry: entity_unique_id = entity_entry.unique_id or entity_entry.entity_id else: @@ -426,7 +421,12 @@ async def async_step_battery( self.data.pop(CONF_MODEL_ID, None) self.data.pop(CONF_HW_VERSION, None) - subentry = ConfigSubentry(subentry_type=SUBENTRY_BATTERY_NOTE, data=MappingProxyType(self.data), title=str(title), unique_id=unique_id) + subentry = ConfigSubentry( + subentry_type=SUBENTRY_BATTERY_NOTE, + data=MappingProxyType(self.data), + title=str(title), + unique_id=unique_id, + ) self.hass.config_entries.async_add_subentry(config_entry, subentry) return self.async_abort(reason="created_sub_entry") @@ -473,13 +473,14 @@ async def async_step_battery( CONF_BATTERY_LOW_TEMPLATE ): selector.TemplateSelector(), vol.Optional( - CONF_FILTER_OUTLIERS, - default=False): selector.BooleanSelector(), + CONF_FILTER_OUTLIERS, default=False + ): selector.BooleanSelector(), } ), errors=errors, ) + class OptionsFlowHandler(OptionsFlow): """Options flow.""" @@ -499,6 +500,7 @@ async def async_step_init( ), ) + class BatteryNotesSubentryFlowHandler(ConfigSubentryFlow): """Flow for managing Battery Notes subentries.""" @@ -511,14 +513,16 @@ def _is_new(self) -> bool: return self.source == "user" async def async_step_user( - self, user_input: dict[str, Any] | None = None # pylint: disable=unused-argument + self, + user_input: dict[str, Any] | None = None, # pylint: disable=unused-argument ) -> SubentryFlowResult: """Add a subentry.""" - return self.async_show_menu(step_id="user", - menu_options=["device", "entity"], - description_placeholders={"documentation_url": DOCUMENTATION_URL}, - ) + return self.async_show_menu( + step_id="user", + menu_options=["device", "entity"], + description_placeholders={"documentation_url": DOCUMENTATION_URL}, + ) async def async_step_device( self, @@ -692,7 +696,9 @@ async def async_step_entity( last_step=False, ) - async def async_step_manual(self, user_input: dict[str, Any] | None = None) -> SubentryFlowResult: + async def async_step_manual( + self, user_input: dict[str, Any] | None = None + ) -> SubentryFlowResult: """Second step in config flow to add the battery type.""" # pylint: disable=unused-argument errors: dict[str, str] = {} @@ -721,7 +727,9 @@ async def async_step_battery( self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input.get( CONF_BATTERY_LOW_TEMPLATE, None ) - self.data[CONF_FILTER_OUTLIERS] = user_input.get(CONF_FILTER_OUTLIERS, False) + self.data[CONF_FILTER_OUTLIERS] = user_input.get( + CONF_FILTER_OUTLIERS, False + ) source_entity_id = self.data.get(CONF_SOURCE_ENTITY_ID, None) device_id = self.data.get(CONF_DEVICE_ID, None) @@ -732,9 +740,7 @@ async def async_step_battery( if source_entity_id: entity_registry = er.async_get(self.hass) entity_entry = entity_registry.async_get(source_entity_id) - _, source_object_id = split_entity_id( - source_entity_id - ) + _, source_object_id = split_entity_id(source_entity_id) if entity_entry: entity_unique_id = entity_entry.unique_id or entity_entry.entity_id else: @@ -750,7 +756,9 @@ async def async_step_battery( config_entry = self._get_entry() for existing_subentry in config_entry.subentries.values(): if existing_subentry.unique_id == unique_id: - _LOGGER.debug("Subentry with unique_id %s already exists", unique_id) + _LOGGER.debug( + "Subentry with unique_id %s already exists", unique_id + ) return self.async_abort(reason="already_configured") if CONF_NAME in self.data: @@ -769,7 +777,9 @@ async def async_step_battery( assert device_entry title = device_entry.name_by_user or device_entry.name - return self.async_create_entry(title=str(title), data=self.data, unique_id=unique_id) + return self.async_create_entry( + title=str(title), data=self.data, unique_id=unique_id + ) return self.async_show_form( step_id="battery", @@ -813,8 +823,8 @@ async def async_step_battery( CONF_BATTERY_LOW_TEMPLATE ): selector.TemplateSelector(), vol.Optional( - CONF_FILTER_OUTLIERS, - default=False): selector.BooleanSelector(), + CONF_FILTER_OUTLIERS, default=False + ): selector.BooleanSelector(), } ), errors=errors, @@ -837,8 +847,12 @@ async def async_step_reconfigure( if user_input.get(CONF_BATTERY_LOW_TEMPLATE, "") == "": self.data[CONF_BATTERY_LOW_TEMPLATE] = None else: - self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input[CONF_BATTERY_LOW_TEMPLATE] - self.data[CONF_FILTER_OUTLIERS] = user_input.get(CONF_FILTER_OUTLIERS, False) + self.data[CONF_BATTERY_LOW_TEMPLATE] = user_input[ + CONF_BATTERY_LOW_TEMPLATE + ] + self.data[CONF_FILTER_OUTLIERS] = user_input.get( + CONF_FILTER_OUTLIERS, False + ) # Save the updated subentry new_title = user_input.pop(CONF_NAME) @@ -880,51 +894,87 @@ async def async_step_reconfigure( if self.data.get(CONF_BATTERY_LOW_TEMPLATE, None) is None: data_schema = vol.Schema( { - vol.Optional(CONF_NAME, default=config_subentry.title): selector.TextSelector( - selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), + vol.Optional( + CONF_NAME, default=config_subentry.title + ): selector.TextSelector( + selector.TextSelectorConfig( + type=selector.TextSelectorType.TEXT + ), ), - vol.Required(CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE]): selector.TextSelector( - selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), + vol.Required( + CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE] + ): selector.TextSelector( + selector.TextSelectorConfig( + type=selector.TextSelectorType.TEXT + ), ), - vol.Required(CONF_BATTERY_QUANTITY, default=self.data[CONF_BATTERY_QUANTITY]): selector.NumberSelector( + vol.Required( + CONF_BATTERY_QUANTITY, default=self.data[CONF_BATTERY_QUANTITY] + ): selector.NumberSelector( selector.NumberSelectorConfig( min=1, max=100, mode=selector.NumberSelectorMode.BOX ), ), - vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data.get(CONF_BATTERY_LOW_THRESHOLD, 0)): selector.NumberSelector( + vol.Required( + CONF_BATTERY_LOW_THRESHOLD, + default=self.data.get(CONF_BATTERY_LOW_THRESHOLD, 0), + ): selector.NumberSelector( selector.NumberSelectorConfig( min=0, max=99, mode=selector.NumberSelectorMode.BOX ), ), - vol.Optional(CONF_BATTERY_LOW_TEMPLATE): selector.TemplateSelector(), - vol.Optional(CONF_FILTER_OUTLIERS, default=self.data.get(CONF_FILTER_OUTLIERS, False)): selector.BooleanSelector(), + vol.Optional( + CONF_BATTERY_LOW_TEMPLATE + ): selector.TemplateSelector(), + vol.Optional( + CONF_FILTER_OUTLIERS, + default=self.data.get(CONF_FILTER_OUTLIERS, False), + ): selector.BooleanSelector(), } ) else: data_schema = vol.Schema( { - vol.Optional(CONF_NAME, default=config_subentry.title): selector.TextSelector( - selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), + vol.Optional( + CONF_NAME, default=config_subentry.title + ): selector.TextSelector( + selector.TextSelectorConfig( + type=selector.TextSelectorType.TEXT + ), ), - vol.Required(CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE]): selector.TextSelector( - selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT), + vol.Required( + CONF_BATTERY_TYPE, default=self.data[CONF_BATTERY_TYPE] + ): selector.TextSelector( + selector.TextSelectorConfig( + type=selector.TextSelectorType.TEXT + ), ), - vol.Required(CONF_BATTERY_QUANTITY, default=self.data[CONF_BATTERY_QUANTITY]): selector.NumberSelector( + vol.Required( + CONF_BATTERY_QUANTITY, default=self.data[CONF_BATTERY_QUANTITY] + ): selector.NumberSelector( selector.NumberSelectorConfig( min=1, max=100, mode=selector.NumberSelectorMode.BOX ), ), - vol.Required(CONF_BATTERY_LOW_THRESHOLD, default=self.data.get(CONF_BATTERY_LOW_THRESHOLD, 0)): selector.NumberSelector( + vol.Required( + CONF_BATTERY_LOW_THRESHOLD, + default=self.data.get(CONF_BATTERY_LOW_THRESHOLD, 0), + ): selector.NumberSelector( selector.NumberSelectorConfig( min=0, max=99, mode=selector.NumberSelectorMode.BOX ), ), - vol.Optional(CONF_BATTERY_LOW_TEMPLATE, default=self.data.get(CONF_BATTERY_LOW_TEMPLATE, None)): selector.TemplateSelector(), - vol.Optional(CONF_FILTER_OUTLIERS, default=self.data.get(CONF_FILTER_OUTLIERS, False)): selector.BooleanSelector(), + vol.Optional( + CONF_BATTERY_LOW_TEMPLATE, + default=self.data.get(CONF_BATTERY_LOW_TEMPLATE, None), + ): selector.TemplateSelector(), + vol.Optional( + CONF_FILTER_OUTLIERS, + default=self.data.get(CONF_FILTER_OUTLIERS, False), + ): selector.BooleanSelector(), } ) - return self.async_show_form( step_id="reconfigure", description_placeholders={ diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index 571bc4883..e922dbbdd 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -64,9 +64,11 @@ _LOGGER = logging.getLogger(__name__) + @dataclass class BatteryNotesDomainConfig: """Class for sharing config data within the BatteryNotes integration.""" + enable_autodiscovery: bool = True show_all_devices: bool = False enable_replaced: bool = True @@ -78,10 +80,12 @@ class BatteryNotesDomainConfig: user_library: str = "" store: BatteryNotesStorage | None = None + MY_KEY: HassKey[BatteryNotesDomainConfig] = HassKey(DOMAIN) type BatteryNotesConfigEntry = ConfigEntry[BatteryNotesData] + @dataclass class BatteryNotesData: """Class for sharing data within the BatteryNotes integration.""" @@ -91,6 +95,7 @@ class BatteryNotesData: loaded_subentries: dict[str, ConfigSubentry] subentry_coordinators: dict[str, BatteryNotesSubentryCoordinator] | None = None + class BatteryNotesSubentryCoordinator(DataUpdateCoordinator[None]): """Define an object to hold Battery Notes device.""" @@ -119,7 +124,7 @@ def __init__( self, hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, - subentry: ConfigSubentry + subentry: ConfigSubentry, ): """Initialize.""" super().__init__(hass, _LOGGER, config_entry=config_entry, name=DOMAIN) @@ -254,13 +259,12 @@ def _link_to_source(self) -> bool: self.device_name = self.subentry.title else: for entity in entity_registry.entities.values(): - if not entity.device_id or entity.device_id != self.device_id: continue - if ( - not entity.domain - or entity.domain not in [SENSOR_DOMAIN, BINARY_SENSOR_DOMAIN] - ): + if not entity.domain or entity.domain not in [ + SENSOR_DOMAIN, + BINARY_SENSOR_DOMAIN, + ]: continue if not entity.platform or entity.platform == DOMAIN: continue @@ -292,7 +296,9 @@ def _link_to_source(self) -> bool: device_entry = device_registry.async_get(self.device_id) if device_entry: self.device_name = ( - self.subentry.title or device_entry.name_by_user or device_entry.name + self.subentry.title + or device_entry.name_by_user + or device_entry.name ) else: self.device_name = self.subentry.title @@ -338,16 +344,31 @@ def source_entity_name(self): entity_registry = er.async_get(self.hass) device_registry = dr.async_get(self.hass) registry_entry = entity_registry.async_get(self.source_entity_id) - device_entry = device_registry.async_get(self.device_id) if self.device_id else None + device_entry = ( + device_registry.async_get(self.device_id) + if self.device_id + else None + ) if registry_entry: - if registry_entry and registry_entry.name is None and registry_entry.has_entity_name and device_entry: + if ( + registry_entry + and registry_entry.name is None + and registry_entry.has_entity_name + and device_entry + ): self._source_entity_name = ( - registry_entry.name or registry_entry.original_name or device_entry.name_by_user or device_entry.name or self.source_entity_id + registry_entry.name + or registry_entry.original_name + or device_entry.name_by_user + or device_entry.name + or self.source_entity_id ) else: self._source_entity_name = ( - registry_entry.name or registry_entry.original_name or self.source_entity_id + registry_entry.name + or registry_entry.original_name + or self.source_entity_id ) return self._source_entity_name @@ -364,7 +385,8 @@ def battery_low_template_state(self, value): if ( self._previous_battery_low_template_state is not None and self.battery_low_template - and value not in [ + and value + not in [ STATE_UNAVAILABLE, STATE_UNKNOWN, ] @@ -394,7 +416,8 @@ def battery_low_template_state(self, value): if ( self._previous_battery_low_template_state and not self._battery_low_template_state - and value not in [ + and value + not in [ STATE_UNAVAILABLE, STATE_UNKNOWN, ] @@ -418,7 +441,6 @@ def battery_low_template_state(self, value): _LOGGER.debug("battery_increased event fired via template") - self._previous_battery_low_template_state = value @property @@ -430,11 +452,10 @@ def battery_low_binary_state(self): def battery_low_binary_state(self, value): """Set the current battery low status from a binary sensor and fire events if valid.""" self._battery_low_binary_state = value - if (self._previous_battery_low_binary_state is not None - and value not in [ - STATE_UNAVAILABLE, - STATE_UNKNOWN, - ]): + if self._previous_battery_low_binary_state is not None and value not in [ + STATE_UNAVAILABLE, + STATE_UNKNOWN, + ]: self.hass.bus.async_fire( EVENT_BATTERY_THRESHOLD, { @@ -461,7 +482,8 @@ def battery_low_binary_state(self, value): if ( self._previous_battery_low_binary_state and not self._battery_low_binary_state - and value not in [ + and value + not in [ STATE_UNAVAILABLE, STATE_UNKNOWN, ] @@ -504,7 +526,9 @@ def current_battery_level(self, value): "Checking outlier (%s=%s) -> %s", self.device_id or self.source_entity_id or "", value, - "skip" if self._outlier_filter.skip_processing else self._outlier_filter.filter_state(value), + "skip" + if self._outlier_filter.skip_processing + else self._outlier_filter.filter_state(value), ) if self._outlier_filter.skip_processing: return @@ -537,7 +561,9 @@ def current_battery_level(self, value): _LOGGER.debug("battery_threshold event fired Low: %s", self.battery_low) # Battery increased event - increase_threshold = self.config_entry.runtime_data.domain_config.battery_increased_threshod + increase_threshold = ( + self.config_entry.runtime_data.domain_config.battery_increased_threshod + ) if self._current_battery_level not in [STATE_UNAVAILABLE, STATE_UNKNOWN]: if ( @@ -585,9 +611,13 @@ def last_replaced(self) -> datetime | None: return None if self.source_entity_id: - entry = self.config_entry.runtime_data.store.async_get_entity(self.source_entity_id) + entry = self.config_entry.runtime_data.store.async_get_entity( + self.source_entity_id + ) else: - entry = self.config_entry.runtime_data.store.async_get_device(self.device_id) + entry = self.config_entry.runtime_data.store.async_get_device( + self.device_id + ) if entry: if LAST_REPLACED in entry and entry[LAST_REPLACED] is not None: @@ -618,9 +648,13 @@ def last_reported(self) -> datetime | None: return None if self.source_entity_id: - entry = self.config_entry.runtime_data.store.async_get_entity(self.source_entity_id) + entry = self.config_entry.runtime_data.store.async_get_entity( + self.source_entity_id + ) else: - entry = self.config_entry.runtime_data.store.async_get_device(self.device_id) + entry = self.config_entry.runtime_data.store.async_get_device( + self.device_id + ) if entry: if LAST_REPORTED in entry: @@ -654,9 +688,13 @@ def last_reported_level(self) -> float | None: return None if self.source_entity_id: - entry = self.config_entry.runtime_data.store.async_get_entity(self.source_entity_id) + entry = self.config_entry.runtime_data.store.async_get_entity( + self.source_entity_id + ) else: - entry = self.config_entry.runtime_data.store.async_get_device(self.device_id) + entry = self.config_entry.runtime_data.store.async_get_device( + self.device_id + ) if entry: if LAST_REPORTED_LEVEL in entry: @@ -704,7 +742,12 @@ def rounded_previous_battery_level(self) -> float: def _rounded_level(self, value) -> float: """Round the level, if preferred.""" if validate_is_float(value): - return round(float(value), None if self.config_entry.runtime_data.domain_config.round_battery else 1) + return round( + float(value), + None + if self.config_entry.runtime_data.domain_config.round_battery + else 1, + ) else: return value diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index 97d752e66..062505e14 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -78,7 +78,9 @@ class DiscoveryManager: so the user can add them to their HA instance. """ - def __init__(self, hass: HomeAssistant, ha_config: BatteryNotesDomainConfig) -> None: + def __init__( + self, hass: HomeAssistant, ha_config: BatteryNotesDomainConfig + ) -> None: """Init.""" self.hass = hass self.ha_config = ha_config @@ -138,15 +140,22 @@ def _init_entity_discovery( unique_id = f"bn_{device_entry.id}" # Iterate all the ignored devices and check if we have it already - for config_entry in self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=True, include_disabled=False): - if config_entry.source == SOURCE_IGNORE and config_entry.unique_id == unique_id: + for config_entry in self.hass.config_entries.async_entries( + domain=DOMAIN, include_ignore=True, include_disabled=False + ): + if ( + config_entry.source == SOURCE_IGNORE + and config_entry.unique_id == unique_id + ): _LOGGER.debug( "%s: Ignored, skipping new discovery", unique_id, ) return - for config_entry in self.hass.config_entries.async_entries(domain=DOMAIN, include_ignore=False, include_disabled=False): + for config_entry in self.hass.config_entries.async_entries( + domain=DOMAIN, include_ignore=False, include_disabled=False + ): for subentry in config_entry.subentries.values(): if subentry.data.get(CONF_DEVICE_ID, "") == device_entry.id: _LOGGER.debug( diff --git a/custom_components/battery_notes/entity.py b/custom_components/battery_notes/entity.py index 2aa5af148..519010944 100644 --- a/custom_components/battery_notes/entity.py +++ b/custom_components/battery_notes/entity.py @@ -61,22 +61,16 @@ def _set_entity_id(self, entity_description: BatteryNotesEntityDescription) -> N self._attr_translation_placeholders = { "device_name": self.coordinator.device_name + " " } - self.entity_id = ( - f"{entity_description.entity_type}.{self.coordinator.device_name.lower()}_{entity_description.key}" - ) + self.entity_id = f"{entity_description.entity_type}.{self.coordinator.device_name.lower()}_{entity_description.key}" elif self.coordinator.source_entity_id and self.coordinator.device_id: - _, source_object_id = split_entity_id( - self.coordinator.source_entity_id - ) + _, source_object_id = split_entity_id(self.coordinator.source_entity_id) self._attr_translation_placeholders = { "device_name": self.coordinator.source_entity_name + " " } self.entity_id = f"{entity_description.entity_type}.{source_object_id}_{entity_description.key}" else: self._attr_translation_placeholders = {"device_name": ""} - self.entity_id = ( - f"{entity_description.entity_type}.{self.coordinator.device_name.lower()}_{entity_description.key}" - ) + self.entity_id = f"{entity_description.entity_type}.{self.coordinator.device_name.lower()}_{entity_description.key}" def _associate_device( self, hass: HomeAssistant, device_registry: dr.DeviceRegistry @@ -87,7 +81,10 @@ def _associate_device( ): # Attach to the device_id self.device_entry = device_registry.async_get(self.coordinator.device_id) - elif self.entity_description.require_device is False and self.coordinator.source_entity_id: + elif ( + self.entity_description.require_device is False + and self.coordinator.source_entity_id + ): device_id = async_entity_id_to_device_id( hass, self.coordinator.source_entity_id ) diff --git a/custom_components/battery_notes/filters.py b/custom_components/battery_notes/filters.py index e13dc7809..dfb7910a2 100644 --- a/custom_components/battery_notes/filters.py +++ b/custom_components/battery_notes/filters.py @@ -35,7 +35,7 @@ def __repr__(self) -> str: return f"{self.timestamp} : {self.state}" -class Filter(): +class Filter: """Base filter class.""" def __init__( @@ -91,6 +91,7 @@ def filter_state(self, new_state: int | float | str) -> int | float | str: new_state = filtered.state return new_state + class LowOutlierFilter(Filter): """Low Outlier filter. @@ -106,9 +107,7 @@ def __init__( :param radius: band radius """ - super().__init__( - window_size - ) + super().__init__(window_size) self._radius = radius self._stats_internal: Counter = Counter() self._store_raw = True @@ -122,10 +121,10 @@ def _filter_state(self, new_state: FilterState) -> FilterState: if previous_state_values and new_state_value >= previous_state_values[-1]: _LOGGER.debug( - "New value higher than last previous state, allowing. %s >= %s", - new_state, - previous_state_values[-1] - ) + "New value higher than last previous state, allowing. %s >= %s", + new_state, + previous_state_values[-1], + ) return new_state median = statistics.median(previous_state_values) if self.states else 0 diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index e212708c5..f5e68ee84 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -18,18 +18,19 @@ _LOGGER = logging.getLogger(__name__) LIBRARY_DEVICES: Final[str] = "devices" -LIBRARY_MANUFACTURER: Final[str] = "manufacturer" -LIBRARY_MODEL: Final[str] = "model" -LIBRARY_MODEL_MATCH_METHOD: Final[str] = "model_match_method" -LIBRARY_MODEL_ID: Final[str] = "model_id" -LIBRARY_HW_VERSION: Final[str] = "hw_version" -LIBRARY_BATTERY_TYPE: Final[str] = "battery_type" -LIBRARY_BATTERY_QUANTITY: Final[str] = "battery_quantity" +LIBRARY_MANUFACTURER: Final[str] = "manufacturer" +LIBRARY_MODEL: Final[str] = "model" +LIBRARY_MODEL_MATCH_METHOD: Final[str] = "model_match_method" +LIBRARY_MODEL_ID: Final[str] = "model_id" +LIBRARY_HW_VERSION: Final[str] = "hw_version" +LIBRARY_BATTERY_TYPE: Final[str] = "battery_type" +LIBRARY_BATTERY_QUANTITY: Final[str] = "battery_quantity" LIBRARY_MISSING: Final[str] = "##MISSING##" DATA_LIBRARY: HassKey[Library] = HassKey(f"{DOMAIN}_library") -@dataclass(frozen=True,kw_only=True) + +@dataclass(frozen=True, kw_only=True) class LibraryDevice: """Class for keeping track of a library device.""" @@ -54,6 +55,7 @@ def from_json(cls, data: dict[str, Any]) -> LibraryDevice: battery_quantity=data.get(LIBRARY_BATTERY_QUANTITY, 1), ) + class Library: # pylint: disable=too-few-public-methods """Hold all known battery types.""" @@ -74,7 +76,9 @@ def _load_library_json(library_file: str) -> dict[str, Any]: # User Library domain_config = self.hass.data.get(MY_KEY) if domain_config and domain_config.user_library != "": - json_user_path = self.hass.config.path(STORAGE_DIR, "battery_notes", domain_config.user_library) + json_user_path = self.hass.config.path( + STORAGE_DIR, "battery_notes", domain_config.user_library + ) _LOGGER.debug("Using user library file at %s", json_user_path) try: @@ -88,15 +92,17 @@ def _load_library_json(library_file: str) -> dict[str, Any]: if manufacturer not in self._manufacturer_devices: self._manufacturer_devices[manufacturer] = [] self._manufacturer_devices[manufacturer].append(library_device) - _LOGGER.debug( - "Loaded %s user devices", len(user_json_data["devices"]) - ) + _LOGGER.debug("Loaded %s user devices", len(user_json_data["devices"])) except FileNotFoundError: # Try to move the user library to new location try: - legacy_data_directory = os.path.join(os.path.dirname(__file__), "data") - legacy_json_user_path = os.path.join(legacy_data_directory, domain_config.user_library) + legacy_data_directory = os.path.join( + os.path.dirname(__file__), "data" + ) + legacy_json_user_path = os.path.join( + legacy_data_directory, domain_config.user_library + ) os.makedirs(os.path.dirname(json_user_path), exist_ok=True) os.rename(legacy_json_user_path, json_user_path) @@ -111,7 +117,9 @@ def _load_library_json(library_file: str) -> dict[str, Any]: ) # Default Library - json_default_path = self.hass.config.path(STORAGE_DIR, "battery_notes", "library.json") + json_default_path = self.hass.config.path( + STORAGE_DIR, "battery_notes", "library.json" + ) _LOGGER.debug("Using library file at %s", json_default_path) @@ -152,18 +160,21 @@ async def get_device_battery_details( # device_to_find = ModelInfo("Philips", "Hue dimmer switch", "929002398602", None) # device_to_find = ModelInfo("Philips", "Hue dimmer switch", "929002398602", "1") - # Get all devices matching manufacturer & model matching_devices = None partial_matching_devices = None fully_matching_devices = None - manufacturer_devices = self._manufacturer_devices.get(device_to_find.manufacturer.casefold(), None) + manufacturer_devices = self._manufacturer_devices.get( + device_to_find.manufacturer.casefold(), None + ) if not manufacturer_devices: return None matching_devices = [ - x for x in manufacturer_devices if self.device_basic_match(x, device_to_find) + x + for x in manufacturer_devices + if self.device_basic_match(x, device_to_find) ] if matching_devices and len(matching_devices) > 1: @@ -206,7 +217,9 @@ def is_loaded(self) -> bool: """Library loaded successfully.""" return bool(self._manufacturer_devices) - def device_basic_match(self, library_device: LibraryDevice, device_to_find: ModelInfo) -> bool: + def device_basic_match( + self, library_device: LibraryDevice, device_to_find: ModelInfo + ) -> bool: """Check if device match on manufacturer and model.""" if ( library_device.manufacturer.casefold() @@ -247,32 +260,29 @@ def device_partial_match( ) -> bool: """Check if device match on hw_version or model_id.""" if device_to_find.hw_version is None and device_to_find.model_id is None: - if ( - library_device.hw_version is None - and library_device.model_id is None - ): + if library_device.hw_version is None and library_device.model_id is None: return True return False if device_to_find.hw_version is None or device_to_find.model_id is None: - if ( - (library_device.hw_version or "").casefold() - == str(device_to_find.hw_version).casefold() - or (library_device.model_id or "").casefold() - == str(device_to_find.model_id).casefold() - ): + if (library_device.hw_version or "").casefold() == str( + device_to_find.hw_version + ).casefold() or (library_device.model_id or "").casefold() == str( + device_to_find.model_id + ).casefold(): return True return False - def device_full_match(self, library_device: LibraryDevice, device_to_find: ModelInfo) -> bool: + def device_full_match( + self, library_device: LibraryDevice, device_to_find: ModelInfo + ) -> bool: """Check if device match on hw_version and model_id.""" - if ( - (library_device.hw_version or "").casefold() - == str(device_to_find.hw_version).casefold() - and (library_device.model_id or "").casefold() - == str(device_to_find.model_id).casefold() - ): + if (library_device.hw_version or "").casefold() == str( + device_to_find.hw_version + ).casefold() and (library_device.model_id or "").casefold() == str( + device_to_find.model_id + ).casefold(): return True return False diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index 8298587a6..1c2f02ab3 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -34,7 +34,8 @@ "User-Agent": f"BatteryNotes/{VERSION}", "Content-Type": CONTENT_TYPE_JSON, "Accept-Encoding": "gzip", - } +} + class LibraryUpdaterClientError(Exception): """Exception to indicate a general API error.""" @@ -60,7 +61,12 @@ def __init__(self, hass: HomeAssistant): # Fire the library check every 24 hours from just before now refresh_time = datetime.now() - timedelta(hours=0, minutes=1) async_track_utc_time_change( - hass, self.timer_update, hour=refresh_time.hour, minute=refresh_time.minute, second=refresh_time.second, local=True + hass, + self.timer_update, + hour=refresh_time.hour, + minute=refresh_time.minute, + second=refresh_time.second, + local=True, ) @callback @@ -98,7 +104,9 @@ def _update_library_json(library_file: str, content: str) -> None: content = await self._client.async_get_data() if self.validate_json(content): - json_path = self.hass.config.path(STORAGE_DIR, "battery_notes", "library.json") + json_path = self.hass.config.path( + STORAGE_DIR, "battery_notes", "library.json" + ) await self.hass.async_add_executor_job( _update_library_json, json_path, content @@ -114,15 +122,15 @@ def _update_library_json(library_file: str, content: str) -> None: except LibraryUpdaterClientError: if not startup: - _LOGGER.warning( - "Unable to update library, will retry later." - ) + _LOGGER.warning("Unable to update library, will retry later.") async def copy_schema(self): """Copy schema file to storage to be relative to downloaded library.""" install_schema_path = os.path.join(os.path.dirname(__file__), "schema.json") - storage_schema_path = self.hass.config.path(STORAGE_DIR, "battery_notes", "schema.json") + storage_schema_path = self.hass.config.path( + STORAGE_DIR, "battery_notes", "schema.json" + ) os.makedirs(os.path.dirname(storage_schema_path), exist_ok=True) await self.hass.async_add_executor_job( shutil.copyfile, @@ -138,9 +146,7 @@ async def time_to_update_library(self, hours: int) -> bool: return True if library_last_update := self.hass.data[MY_KEY].library_last_update: - time_since_last_update = ( - datetime.now() - library_last_update - ) + time_since_last_update = datetime.now() - library_last_update time_difference_in_hours = time_since_last_update / timedelta(hours=1) @@ -181,7 +187,9 @@ def __init__( async def async_get_data(self) -> Any: """Get data from the API.""" _LOGGER.debug("Updating library from %s", DEFAULT_LIBRARY_URL) - return await self._api_wrapper(method="get", url=DEFAULT_LIBRARY_URL, headers=HEADERS) + return await self._api_wrapper( + method="get", url=DEFAULT_LIBRARY_URL, headers=HEADERS + ) async def _api_wrapper( self, diff --git a/custom_components/battery_notes/repairs.py b/custom_components/battery_notes/repairs.py index b91da2613..463e20634 100644 --- a/custom_components/battery_notes/repairs.py +++ b/custom_components/battery_notes/repairs.py @@ -13,6 +13,7 @@ REQUIRED_KEYS = ("entry_id", "device_id", "source_entity_id") + class MissingDeviceRepairFlow(RepairsFlow): """Handler for an issue fixing flow.""" @@ -26,18 +27,19 @@ def __init__(self, data: dict[str, str | int | float | None] | None) -> None: self.source_entity_id = cast(str, data["source_entity_id"]) async def async_step_init( - self, user_input: dict[str, str] | None = None #pylint: disable=unused-argument + self, + user_input: dict[str, str] | None = None, # pylint: disable=unused-argument ) -> data_entry_flow.FlowResult: """Handle the first step of a fix flow.""" - return await (self.async_step_confirm()) + return await self.async_step_confirm() async def async_step_confirm( self, user_input: dict[str, str] | None = None ) -> data_entry_flow.FlowResult: """Handle the confirm step of a fix flow.""" if user_input is not None: - if (entry:= self.hass.config_entries.async_get_entry(self.entry_id)): + if entry := self.hass.config_entries.async_get_entry(self.entry_id): self.hass.config_entries.async_remove_subentry(entry, self.subentry_id) return self.async_create_entry(data={}) @@ -50,12 +52,12 @@ async def async_step_confirm( return self.async_show_form( step_id="confirm", data_schema=vol.Schema({}), - description_placeholders=description_placeholders + description_placeholders=description_placeholders, ) async def async_create_fix_flow( - hass: HomeAssistant, #pylint: disable=unused-argument + hass: HomeAssistant, # pylint: disable=unused-argument issue_id: str, data: dict[str, str | int | float | None] | None, ) -> RepairsFlow: diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 7cd009c0e..e117adfaa 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -96,6 +96,7 @@ class BatteryNotesSensorEntityDescription( _LOGGER = logging.getLogger(__name__) + async def async_setup_entry( hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, @@ -134,7 +135,9 @@ async def async_setup_entry( translation_key="battery_last_replaced", entity_category=EntityCategory.DIAGNOSTIC, device_class=SensorDeviceClass.TIMESTAMP, - entity_registry_enabled_default=config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), + entity_registry_enabled_default=config_entry.options[ + CONF_ADVANCED_SETTINGS + ].get(CONF_ENABLE_REPLACED, True), entity_type="sensor", ) @@ -143,7 +146,11 @@ async def async_setup_entry( key="battery_plus", translation_key="battery_plus", device_class=SensorDeviceClass.BATTERY, - suggested_display_precision=0 if config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, True) else 1, + suggested_display_precision=0 + if config_entry.options[CONF_ADVANCED_SETTINGS].get( + CONF_ROUND_BATTERY, True + ) + else 1, entity_type="sensor", require_device=True, ) @@ -177,8 +184,12 @@ async def async_setup_entry( battery_plus_sensor_entity_description, coordinator, f"{subentry.unique_id}{battery_plus_sensor_entity_description.unique_id_suffix}", - config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ENABLE_REPLACED, True), - config_entry.options[CONF_ADVANCED_SETTINGS].get(CONF_ROUND_BATTERY, False), + config_entry.options[CONF_ADVANCED_SETTINGS].get( + CONF_ENABLE_REPLACED, True + ), + config_entry.options[CONF_ADVANCED_SETTINGS].get( + CONF_ROUND_BATTERY, False + ), ) ) @@ -206,7 +217,9 @@ def __init__( ) -> None: # pylint: disable=unused-argument """Initialize the sensor.""" - super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) + super().__init__( + hass=hass, entity_description=entity_description, coordinator=coordinator + ) self._attr_unique_id = unique_id @@ -250,9 +263,8 @@ def extra_state_attributes(self) -> dict[str, Any] | None: attrs.update(super_attrs) return attrs -class BatteryNotesLastReplacedSensor( - BatteryNotesEntity, SensorEntity -): + +class BatteryNotesLastReplacedSensor(BatteryNotesEntity, SensorEntity): """Represents a battery note sensor.""" _attr_should_poll = False @@ -270,7 +282,9 @@ def __init__( ) -> None: # pylint: disable=unused-argument """Initialize the sensor.""" - super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) + super().__init__( + hass=hass, entity_description=entity_description, coordinator=coordinator + ) self._attr_device_class = description.device_class self._attr_unique_id = unique_id @@ -307,9 +321,8 @@ def native_value(self) -> datetime | None: """Return the native value of the sensor.""" return self._native_value -class BatteryNotesBatteryPlusSensor( - BatteryNotesEntity, RestoreSensor -): + +class BatteryNotesBatteryPlusSensor(BatteryNotesEntity, RestoreSensor): """Represents a battery plus type sensor.""" _attr_should_poll = False @@ -345,7 +358,9 @@ def __init__( ) -> None: # pylint: disable=unused-argument """Initialize the sensor.""" - super().__init__(hass=hass, entity_description=entity_description, coordinator=coordinator) + super().__init__( + hass=hass, entity_description=entity_description, coordinator=coordinator + ) self.config_entry = config_entry @@ -661,4 +676,3 @@ def extra_state_attributes(self) -> dict[str, Any] | None: def native_value(self) -> StateType | Any | datetime: """Return the value reported by the sensor.""" return self._attr_native_value - diff --git a/custom_components/battery_notes/services.py b/custom_components/battery_notes/services.py index 2dc96fddc..6267ffb42 100644 --- a/custom_components/battery_notes/services.py +++ b/custom_components/battery_notes/services.py @@ -47,6 +47,7 @@ _LOGGER = logging.getLogger(__name__) + @callback def async_setup_services(hass: HomeAssistant) -> None: """Set up the services for the Mastodon integration.""" @@ -79,9 +80,7 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: datetime_replaced_entry = call.data.get(SERVICE_DATA_DATE_TIME_REPLACED) if datetime_replaced_entry: - datetime_replaced = dt_util.as_utc(datetime_replaced_entry).replace( - tzinfo=None - ) + datetime_replaced = dt_util.as_utc(datetime_replaced_entry).replace(tzinfo=None) else: datetime_replaced = utcnow_no_timezone() @@ -105,8 +104,13 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: if not battery_notes_config_entry.runtime_data.subentry_coordinators: continue - for coordinator in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): - if coordinator.source_entity_id and coordinator.source_entity_id == source_entity_id: + for ( + coordinator + ) in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): + if ( + coordinator.source_entity_id + and coordinator.source_entity_id == source_entity_id + ): entity_found = True coordinator.last_replaced = datetime_replaced await coordinator.async_request_refresh() @@ -121,8 +125,7 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: EVENT_BATTERY_REPLACED, { ATTR_DEVICE_ID: coordinator.device_id or "", - ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id - or "", + ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id or "", ATTR_DEVICE_NAME: coordinator.device_name, ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, ATTR_BATTERY_TYPE: coordinator.battery_type, @@ -161,7 +164,9 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: if not battery_notes_config_entry.runtime_data.subentry_coordinators: continue - for coordinator in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): + for ( + coordinator + ) in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): if coordinator.device_id == device_id: device_found = True coordinator.last_replaced = datetime_replaced @@ -177,8 +182,7 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: EVENT_BATTERY_REPLACED, { ATTR_DEVICE_ID: coordinator.device_id or "", - ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id - or "", + ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id or "", ATTR_DEVICE_NAME: coordinator.device_name, ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, ATTR_BATTERY_TYPE: coordinator.battery_type, @@ -212,7 +216,9 @@ async def _async_battery_last_reported(call: ServiceCall) -> ServiceResponse: if not battery_notes_config_entry.runtime_data.subentry_coordinators: continue - for coordinator in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): + for ( + coordinator + ) in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): if coordinator.wrapped_battery and coordinator.last_reported: time_since_lastreported = ( datetime.fromisoformat(str(utcnow_no_timezone()) + "+00:00") @@ -224,8 +230,7 @@ async def _async_battery_last_reported(call: ServiceCall) -> ServiceResponse: EVENT_BATTERY_NOT_REPORTED, { ATTR_DEVICE_ID: coordinator.device_id or "", - ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id - or "", + ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id or "", ATTR_DEVICE_NAME: coordinator.device_name, ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, ATTR_BATTERY_TYPE: coordinator.battery_type, @@ -244,6 +249,7 @@ async def _async_battery_last_reported(call: ServiceCall) -> ServiceResponse: ) return None + async def _async_battery_low(call: ServiceCall) -> ServiceResponse: """Handle the service call.""" @@ -252,15 +258,16 @@ async def _async_battery_low(call: ServiceCall) -> ServiceResponse: if not battery_notes_config_entry.runtime_data.subentry_coordinators: continue - for coordinator in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): + for ( + coordinator + ) in battery_notes_config_entry.runtime_data.subentry_coordinators.values(): if coordinator.battery_low is True: call.hass.bus.async_fire( EVENT_BATTERY_THRESHOLD, { ATTR_DEVICE_ID: coordinator.device_id or "", ATTR_DEVICE_NAME: coordinator.device_name, - ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id - or "", + ATTR_SOURCE_ENTITY_ID: coordinator.source_entity_id or "", ATTR_BATTERY_LOW: coordinator.battery_low, ATTR_BATTERY_LOW_THRESHOLD: coordinator.battery_low_threshold, ATTR_BATTERY_TYPE_AND_QUANTITY: coordinator.battery_type_and_quantity, @@ -277,4 +284,4 @@ async def _async_battery_low(call: ServiceCall) -> ServiceResponse: "Raised event device %s battery low", coordinator.device_id, ) - return None \ No newline at end of file + return None diff --git a/custom_components/battery_notes/store.py b/custom_components/battery_notes/store.py index 30c62fb50..28427e644 100644 --- a/custom_components/battery_notes/store.py +++ b/custom_components/battery_notes/store.py @@ -28,7 +28,7 @@ @attr.s(slots=True, frozen=True) class DeviceEntry: - #pylint: disable=too-few-public-methods + # pylint: disable=too-few-public-methods """Battery Notes Device storage Entry.""" device_id = attr.ib(type=str, default=None) @@ -39,7 +39,7 @@ class DeviceEntry: @attr.s(slots=True, frozen=True) class EntityEntry: - #pylint: disable=too-few-public-methods + # pylint: disable=too-few-public-methods """Battery Notes Entity storage Entry.""" entity_id = attr.ib(type=str, default=None) @@ -124,7 +124,7 @@ async def async_delete(self): self.devices = {} @callback - def async_get_device(self, device_id)-> dict[str, Any] | None: + def async_get_device(self, device_id) -> dict[str, Any] | None: """Get an existing DeviceEntry by id.""" res = self.devices.get(device_id) return attr.asdict(res) if res else None From 4d901cffa34d226ebd0371a7e86f7178c1c31d06 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 30 Oct 2025 09:28:36 +0000 Subject: [PATCH 214/235] Formatting --- .github/scripts/library_doc/generate_file.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/scripts/library_doc/generate_file.py b/.github/scripts/library_doc/generate_file.py index 8461c3d14..6cd10ad8d 100644 --- a/.github/scripts/library_doc/generate_file.py +++ b/.github/scripts/library_doc/generate_file.py @@ -11,9 +11,7 @@ def generate_device_list(): """Generate static file containing the device library.""" # Load the existing JSON library file - with open( - "library/library.json", encoding="UTF-8" - ) as f: + with open("library/library.json", encoding="UTF-8") as f: devices_json = json.loads(f.read()) devices = devices_json.get("devices") From f94e6eba8a9ea61b663c6c4e60cc484ca83f8084 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 30 Oct 2025 09:31:23 +0000 Subject: [PATCH 215/235] Update gitignore --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ee42580ea..3bc5d361d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,8 @@ __pycache__ *.egg-info */build/* */dist/* - +.venv +.ruff_cache # misc .coverage @@ -17,5 +18,4 @@ config/* .DS_Store config/configuration.yaml backup/* - custom_components/battery_notes/frontend/node_modules From 3a5efd5f0be238f8a57060b111e52eeb15b09b67 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 30 Oct 2025 09:43:49 +0000 Subject: [PATCH 216/235] Change import --- custom_components/battery_notes/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index c8203f2a5..5b0483f7e 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -24,13 +24,15 @@ device_registry as dr, entity_registry as er, config_validation as cv, - helper_integration, ) from homeassistant.helpers.event import async_call_later from homeassistant.config_entries import SOURCE_IGNORE, ConfigEntry, ConfigSubentry from homeassistant.helpers.device import async_entity_id_to_device_id from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue +from homeassistant.helpers.helper_integration import ( + async_remove_helper_config_entry_from_source_device, +) from .const import ( NAME as INTEGRATION_NAME, @@ -382,7 +384,7 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> source_device_id = async_entity_id_to_device_id(hass, source_entity_id) if source_device_id: - helper_integration.async_remove_helper_config_entry_from_source_device( + async_remove_helper_config_entry_from_source_device( hass=hass, helper_config_entry_id=entry.entry_id, source_device_id=source_device_id, From 1b5bc7ed0c5aaf3da88caa4c1a1ea08f494cdfd5 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 31 Oct 2025 10:19:05 +0000 Subject: [PATCH 217/235] Bump HA version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c6c20e708..70e44976e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ classifiers = [ "Programming Language :: Python :: 3", ] requires-python = "==3.13.2" -dependencies = ["homeassistant==2025.4.0"] +dependencies = ["homeassistant==2025.9.0"] [project.urls] documentation = "https://github.com/andrew-codechimp/HA-Battery-Notes" From 5832c6a8a78e67390cf68bd141389beac0a76c89 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 31 Oct 2025 10:28:11 +0000 Subject: [PATCH 218/235] Update uv lock --- uv.lock | 757 +++++++++++++++++++++++++++----------------------------- 1 file changed, 364 insertions(+), 393 deletions(-) diff --git a/uv.lock b/uv.lock index b005a9c9c..0c706bee1 100644 --- a/uv.lock +++ b/uv.lock @@ -4,31 +4,30 @@ requires-python = "==3.13.2" [[package]] name = "acme" -version = "3.2.0" +version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "josepy" }, { name = "pyopenssl" }, { name = "pyrfc3339" }, - { name = "pytz" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f9/6a/c94be0e8ee157f3c7721844863589c627c40bfa10d8838faeb6b28b59bb2/acme-3.2.0.tar.gz", hash = "sha256:e11d0ccf43ec19244ada40df1dc4ca49c9ce407749f3771d2cefe0674e206d84", size = 92875, upload-time = "2025-02-11T21:35:57.947Z" } +sdist = { url = "https://files.pythonhosted.org/packages/48/df/d006c4920fd04b843c21698bd038968cb9caa3315608f55abde0f8e4ad6b/acme-4.2.0.tar.gz", hash = "sha256:0df68c0e1acb3824a2100013f8cd51bda2e1a56aa23447449d14c942959f0c41", size = 96820, upload-time = "2025-08-05T19:19:08.86Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/1c/da759f277879f5b8aa0b6355689e091224b8af500c6983a1c8fb66bad5b0/acme-3.2.0-py3-none-any.whl", hash = "sha256:201b118d12426f746d936efc61706d30dc2f9e2635aebab0c86ec7f80eca5f30", size = 97444, upload-time = "2025-02-11T21:35:25.465Z" }, + { url = "https://files.pythonhosted.org/packages/86/26/9ff889b5d762616bf92ecbeb1ab93faddfd7bf6068146340359e9a6beb43/acme-4.2.0-py3-none-any.whl", hash = "sha256:6292011bbfa5f966521b2fb9469982c24ff4c58e240985f14564ccf35372e79a", size = 101573, upload-time = "2025-08-05T19:18:45.266Z" }, ] [[package]] name = "aiodns" -version = "3.2.0" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycares" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/84/41a6a2765abc124563f5380e76b9b24118977729e25a84112f8dfb2b33dc/aiodns-3.2.0.tar.gz", hash = "sha256:62869b23409349c21b072883ec8998316b234c9a9e36675756e8e317e8768f72", size = 7823, upload-time = "2024-03-31T11:27:30.639Z" } +sdist = { url = "https://files.pythonhosted.org/packages/17/0a/163e5260cecc12de6abc259d158d9da3b8ec062ab863107dcdb1166cdcef/aiodns-3.5.0.tar.gz", hash = "sha256:11264edbab51896ecf546c18eb0dd56dff0428c6aa6d2cd87e643e07300eb310", size = 14380, upload-time = "2025-06-13T16:21:53.595Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/14/13c65b1bd59f7e707e0cc0964fbab45c003f90292ed267d159eeeeaa2224/aiodns-3.2.0-py3-none-any.whl", hash = "sha256:e443c0c27b07da3174a109fd9e736d69058d808f144d3c9d56dbd1776964c5f5", size = 5735, upload-time = "2024-03-31T11:27:28.615Z" }, + { url = "https://files.pythonhosted.org/packages/f6/2c/711076e5f5d0707b8ec55a233c8bfb193e0981a800cd1b3b123e8ff61ca1/aiodns-3.5.0-py3-none-any.whl", hash = "sha256:6d0404f7d5215849233f6ee44854f2bb2481adf71b336b2279016ea5990ca5c5", size = 8068, upload-time = "2025-06-13T16:21:52.45Z" }, ] [[package]] @@ -42,22 +41,21 @@ wheels = [ [[package]] name = "aiohasupervisor" -version = "0.3.0" +version = "0.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "mashumaro" }, { name = "orjson" }, - { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/23/eceea174c1d827adea8a8b23f1428454157288fd58e6a9231e8861a45383/aiohasupervisor-0.3.0.tar.gz", hash = "sha256:91bf0b051f28582196f900a31c9bcbebec6de9e3ed1a32a2947a892c04748ce2", size = 40542, upload-time = "2025-02-05T14:41:08.946Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/13/e9c818c4be157db6383d6e0f5c56df4764553c241bc566cd819f42bd398c/aiohasupervisor-0.3.2.tar.gz", hash = "sha256:eb291b600cc5cf05072e4bd16df5655cfaea3b9f3b964844896b38230e529a7c", size = 42599, upload-time = "2025-08-26T14:47:47.357Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/09/98c83e4a20ae951d49720caeb6daf784293498fab0450af5b2236ca0c079/aiohasupervisor-0.3.0-py3-none-any.whl", hash = "sha256:f85b45c80ee24b381523e5a84a39f962f25e72c90026a3dcef2becea1d7f5501", size = 38550, upload-time = "2025-02-05T14:41:06.838Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e4/6f62ce34142558cb748c20976dfd8696b8bb4ed71653d43795f3de26a07d/aiohasupervisor-0.3.2-py3-none-any.whl", hash = "sha256:93599f698e7daf238e8040053d455104bac149f9e59fda757c6378708fbd1629", size = 39220, upload-time = "2025-08-26T14:47:46.262Z" }, ] [[package]] name = "aiohttp" -version = "3.11.16" +version = "3.12.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -68,24 +66,25 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f1/d9/1c4721d143e14af753f2bf5e3b681883e1f24b592c0482df6fa6e33597fa/aiohttp-3.11.16.tar.gz", hash = "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", size = 7676826, upload-time = "2025-04-02T02:17:44.74Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/52/52/7c712b2d9fb4d5e5fd6d12f9ab76e52baddfee71e3c8203ca7a7559d7f51/aiohttp-3.11.16-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", size = 698005, upload-time = "2025-04-02T02:16:37.923Z" }, - { url = "https://files.pythonhosted.org/packages/51/3e/61057814f7247666d43ac538abcd6335b022869ade2602dab9bf33f607d2/aiohttp-3.11.16-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", size = 461106, upload-time = "2025-04-02T02:16:39.961Z" }, - { url = "https://files.pythonhosted.org/packages/4f/85/6b79fb0ea6e913d596d5b949edc2402b20803f51b1a59e1bbc5bb7ba7569/aiohttp-3.11.16-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", size = 453394, upload-time = "2025-04-02T02:16:41.562Z" }, - { url = "https://files.pythonhosted.org/packages/4b/04/e1bb3fcfbd2c26753932c759593a32299aff8625eaa0bf8ff7d9c0c34a36/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", size = 1666643, upload-time = "2025-04-02T02:16:43.62Z" }, - { url = "https://files.pythonhosted.org/packages/0e/27/97bc0fdd1f439b8f060beb3ba8fb47b908dc170280090801158381ad7942/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", size = 1721948, upload-time = "2025-04-02T02:16:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/2c/4f/bc4c5119e75c05ef15c5670ef1563bbe25d4ed4893b76c57b0184d815e8b/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", size = 1774454, upload-time = "2025-04-02T02:16:48.562Z" }, - { url = "https://files.pythonhosted.org/packages/73/5b/54b42b2150bb26fdf795464aa55ceb1a49c85f84e98e6896d211eabc6670/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", size = 1677785, upload-time = "2025-04-02T02:16:50.367Z" }, - { url = "https://files.pythonhosted.org/packages/10/ee/a0fe68916d3f82eae199b8535624cf07a9c0a0958c7a76e56dd21140487a/aiohttp-3.11.16-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", size = 1608456, upload-time = "2025-04-02T02:16:52.158Z" }, - { url = "https://files.pythonhosted.org/packages/8b/48/83afd779242b7cf7e1ceed2ff624a86d3221e17798061cf9a79e0b246077/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", size = 1622424, upload-time = "2025-04-02T02:16:54.386Z" }, - { url = "https://files.pythonhosted.org/packages/6f/27/452f1d5fca1f516f9f731539b7f5faa9e9d3bf8a3a6c3cd7c4b031f20cbd/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", size = 1660943, upload-time = "2025-04-02T02:16:56.887Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e1/5c7d63143b8d00c83b958b9e78e7048c4a69903c760c1e329bf02bac57a1/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", size = 1622797, upload-time = "2025-04-02T02:16:58.676Z" }, - { url = "https://files.pythonhosted.org/packages/46/9e/2ac29cca2746ee8e449e73cd2fcb3d454467393ec03a269d50e49af743f1/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", size = 1687162, upload-time = "2025-04-02T02:17:01.076Z" }, - { url = "https://files.pythonhosted.org/packages/ad/6b/eaa6768e02edebaf37d77f4ffb74dd55f5cbcbb6a0dbf798ccec7b0ac23b/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", size = 1718518, upload-time = "2025-04-02T02:17:03.388Z" }, - { url = "https://files.pythonhosted.org/packages/e5/18/dda87cbad29472a51fa058d6d8257dfce168289adaeb358b86bd93af3b20/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", size = 1675254, upload-time = "2025-04-02T02:17:05.579Z" }, - { url = "https://files.pythonhosted.org/packages/32/d9/d2fb08c614df401d92c12fcbc60e6e879608d5e8909ef75c5ad8d4ad8aa7/aiohttp-3.11.16-cp313-cp313-win32.whl", hash = "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", size = 410698, upload-time = "2025-04-02T02:17:07.499Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ed/853e36d5a33c24544cfa46585895547de152dfef0b5c79fa675f6e4b7b87/aiohttp-3.11.16-cp313-cp313-win_amd64.whl", hash = "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", size = 436395, upload-time = "2025-04-02T02:17:09.566Z" }, + { url = "https://files.pythonhosted.org/packages/f2/33/918091abcf102e39d15aba2476ad9e7bd35ddb190dcdd43a854000d3da0d/aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315", size = 696741, upload-time = "2025-07-29T05:51:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2a/7495a81e39a998e400f3ecdd44a62107254803d1681d9189be5c2e4530cd/aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd", size = 474407, upload-time = "2025-07-29T05:51:21.165Z" }, + { url = "https://files.pythonhosted.org/packages/49/fc/a9576ab4be2dcbd0f73ee8675d16c707cfc12d5ee80ccf4015ba543480c9/aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4", size = 466703, upload-time = "2025-07-29T05:51:22.948Z" }, + { url = "https://files.pythonhosted.org/packages/09/2f/d4bcc8448cf536b2b54eed48f19682031ad182faa3a3fee54ebe5b156387/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7", size = 1705532, upload-time = "2025-07-29T05:51:25.211Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f3/59406396083f8b489261e3c011aa8aee9df360a96ac8fa5c2e7e1b8f0466/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d", size = 1686794, upload-time = "2025-07-29T05:51:27.145Z" }, + { url = "https://files.pythonhosted.org/packages/dc/71/164d194993a8d114ee5656c3b7ae9c12ceee7040d076bf7b32fb98a8c5c6/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b", size = 1738865, upload-time = "2025-07-29T05:51:29.366Z" }, + { url = "https://files.pythonhosted.org/packages/1c/00/d198461b699188a93ead39cb458554d9f0f69879b95078dce416d3209b54/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d", size = 1788238, upload-time = "2025-07-29T05:51:31.285Z" }, + { url = "https://files.pythonhosted.org/packages/85/b8/9e7175e1fa0ac8e56baa83bf3c214823ce250d0028955dfb23f43d5e61fd/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d", size = 1710566, upload-time = "2025-07-29T05:51:33.219Z" }, + { url = "https://files.pythonhosted.org/packages/59/e4/16a8eac9df39b48ae102ec030fa9f726d3570732e46ba0c592aeeb507b93/aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645", size = 1624270, upload-time = "2025-07-29T05:51:35.195Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/cd84dee7b6ace0740908fd0af170f9fab50c2a41ccbc3806aabcb1050141/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461", size = 1677294, upload-time = "2025-07-29T05:51:37.215Z" }, + { url = "https://files.pythonhosted.org/packages/ce/42/d0f1f85e50d401eccd12bf85c46ba84f947a84839c8a1c2c5f6e8ab1eb50/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9", size = 1708958, upload-time = "2025-07-29T05:51:39.328Z" }, + { url = "https://files.pythonhosted.org/packages/d5/6b/f6fa6c5790fb602538483aa5a1b86fcbad66244997e5230d88f9412ef24c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d", size = 1651553, upload-time = "2025-07-29T05:51:41.356Z" }, + { url = "https://files.pythonhosted.org/packages/04/36/a6d36ad545fa12e61d11d1932eef273928b0495e6a576eb2af04297fdd3c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693", size = 1727688, upload-time = "2025-07-29T05:51:43.452Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c8/f195e5e06608a97a4e52c5d41c7927301bf757a8e8bb5bbf8cef6c314961/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64", size = 1761157, upload-time = "2025-07-29T05:51:45.643Z" }, + { url = "https://files.pythonhosted.org/packages/05/6a/ea199e61b67f25ba688d3ce93f63b49b0a4e3b3d380f03971b4646412fc6/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51", size = 1710050, upload-time = "2025-07-29T05:51:48.203Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2e/ffeb7f6256b33635c29dbed29a22a723ff2dd7401fff42ea60cf2060abfb/aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0", size = 422647, upload-time = "2025-07-29T05:51:50.718Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8e/78ee35774201f38d5e1ba079c9958f7629b1fd079459aea9467441dbfbf5/aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84", size = 449067, upload-time = "2025-07-29T05:51:52.549Z" }, ] [[package]] @@ -104,26 +103,26 @@ wheels = [ [[package]] name = "aiohttp-cors" -version = "0.7.0" +version = "0.8.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/9e/6cdce7c3f346d8fd487adf68761728ad8cd5fbc296a7b07b92518350d31f/aiohttp-cors-0.7.0.tar.gz", hash = "sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d", size = 35966, upload-time = "2018-03-06T15:45:42.936Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/d89e846a5444b3d5eb8985a6ddb0daef3774928e1bfbce8e84ec97b0ffa7/aiohttp_cors-0.8.1.tar.gz", hash = "sha256:ccacf9cb84b64939ea15f859a146af1f662a6b1d68175754a07315e305fb1403", size = 38626, upload-time = "2025-03-31T14:16:20.048Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/e7/e436a0c0eb5127d8b491a9b83ecd2391c6ff7dcd5548dfaec2080a2340fd/aiohttp_cors-0.7.0-py3-none-any.whl", hash = "sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e", size = 27564, upload-time = "2018-03-06T15:45:42.034Z" }, + { url = "https://files.pythonhosted.org/packages/98/3b/40a68de458904bcc143622015fff2352b6461cd92fd66d3527bf1c6f5716/aiohttp_cors-0.8.1-py3-none-any.whl", hash = "sha256:3180cf304c5c712d626b9162b195b1db7ddf976a2a25172b35bb2448b890a80d", size = 25231, upload-time = "2025-03-31T14:16:18.478Z" }, ] [[package]] name = "aiohttp-fast-zlib" -version = "0.2.3" +version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d7/73/c93543264f745202a6fe78ad8ddb7c13a9d3e3ea47cde26501d683bd46a4/aiohttp_fast_zlib-0.2.3.tar.gz", hash = "sha256:d7e34621f2ac47155d9ad5d78f15ffb066a4ee849cb3d55df0077395ab4b3eff", size = 8591, upload-time = "2025-02-22T17:52:51.832Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/a6/982f3a013b42e914a2420631afcaecb729c49525cc6cc58e15d27ee4cb4b/aiohttp_fast_zlib-0.3.0.tar.gz", hash = "sha256:963a09de571b67fa0ef9cb44c5a32ede5cb1a51bc79fc21181b1cddd56b58b28", size = 8770, upload-time = "2025-06-07T12:41:49.161Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/55/9aebf9f5dac1a34bb0a4f300d2ec4692f86df44e458f3061a659dec2b98f/aiohttp_fast_zlib-0.2.3-py3-none-any.whl", hash = "sha256:41a93670f88042faff3ebbd039fd2fc37a0c956193c20eb758be45b1655a7e04", size = 8421, upload-time = "2025-02-22T17:52:49.971Z" }, + { url = "https://files.pythonhosted.org/packages/b7/11/ea9ecbcd6cf68c5de690fd39b66341405ab091aa0c3598277e687aa65901/aiohttp_fast_zlib-0.3.0-py3-none-any.whl", hash = "sha256:d4cb20760a3e1137c93cb42c13871cbc9cd1fdc069352f2712cd650d6c0e537e", size = 8615, upload-time = "2025-06-07T12:41:47.454Z" }, ] [[package]] @@ -239,11 +238,11 @@ wheels = [ [[package]] name = "attrs" -version = "25.1.0" +version = "25.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562, upload-time = "2025-01-25T11:30:12.508Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152, upload-time = "2025-01-25T11:30:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, ] [[package]] @@ -288,41 +287,61 @@ wheels = [ [[package]] name = "awesomeversion" -version = "24.6.0" +version = "25.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/e9/1baaf8619a3d66b467ba105976897e67b36dbad93b619753768357dbd475/awesomeversion-24.6.0.tar.gz", hash = "sha256:aee7ccbaed6f8d84e0f0364080c7734a0166d77ea6ccfcc4900b38917f1efc71", size = 11997, upload-time = "2024-06-24T11:09:27.958Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/95/bd19ef0ef6735bd7131c0310f71432ea5fdf3dc2b3245a262d1f34bae55e/awesomeversion-25.5.0.tar.gz", hash = "sha256:d64c9f3579d2f60a5aa506a9dd0b38a74ab5f45e04800f943a547c1102280f31", size = 11693, upload-time = "2025-05-29T12:38:02.352Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/a5/258ffce7048e8be24c6f402bcbf5d1b3933d5d63421d000a55e74248481b/awesomeversion-24.6.0-py3-none-any.whl", hash = "sha256:6768415b8954b379a25cebf21ed4f682cab10aebf3f82a6640aaaa15ec6821f2", size = 14716, upload-time = "2024-06-24T11:09:26.133Z" }, + { url = "https://files.pythonhosted.org/packages/dd/99/dc26ce0845a99f90fd99464a1d9124d5eacaa8bac92072af059cf002def4/awesomeversion-25.5.0-py3-none-any.whl", hash = "sha256:34a676ae10e10d3a96829fcc890a1d377fe1a7a2b98ee19951631951c2aebff6", size = 13998, upload-time = "2025-05-29T12:38:01.127Z" }, ] [[package]] name = "bcrypt" -version = "4.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/7e/d95e7d96d4828e965891af92e43b52a4cd3395dc1c1ef4ee62748d0471d0/bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", size = 24294, upload-time = "2024-07-22T18:09:10.445Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/81/4e8f5bc0cd947e91fb720e1737371922854da47a94bc9630454e7b2845f8/bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", size = 471568, upload-time = "2024-07-22T18:08:55.603Z" }, - { url = "https://files.pythonhosted.org/packages/05/d2/1be1e16aedec04bcf8d0156e01b987d16a2063d38e64c3f28030a3427d61/bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", size = 277372, upload-time = "2024-07-22T18:08:51.446Z" }, - { url = "https://files.pythonhosted.org/packages/e3/96/7a654027638ad9b7589effb6db77eb63eba64319dfeaf9c0f4ca953e5f76/bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", size = 273488, upload-time = "2024-07-22T18:09:02.005Z" }, - { url = "https://files.pythonhosted.org/packages/46/54/dc7b58abeb4a3d95bab653405935e27ba32f21b812d8ff38f271fb6f7f55/bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", size = 277759, upload-time = "2024-07-22T18:08:50.017Z" }, - { url = "https://files.pythonhosted.org/packages/ac/be/da233c5f11fce3f8adec05e8e532b299b64833cc962f49331cdd0e614fa9/bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", size = 273796, upload-time = "2024-07-22T18:09:07.605Z" }, - { url = "https://files.pythonhosted.org/packages/b0/b8/8b4add88d55a263cf1c6b8cf66c735280954a04223fcd2880120cc767ac3/bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", size = 311082, upload-time = "2024-07-22T18:08:35.765Z" }, - { url = "https://files.pythonhosted.org/packages/7b/76/2aa660679abbdc7f8ee961552e4bb6415a81b303e55e9374533f22770203/bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", size = 305912, upload-time = "2024-07-22T18:08:40.049Z" }, - { url = "https://files.pythonhosted.org/packages/00/03/2af7c45034aba6002d4f2b728c1a385676b4eab7d764410e34fd768009f2/bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", size = 325185, upload-time = "2024-07-22T18:08:41.833Z" }, - { url = "https://files.pythonhosted.org/packages/dc/5d/6843443ce4ab3af40bddb6c7c085ed4a8418b3396f7a17e60e6d9888416c/bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", size = 335188, upload-time = "2024-07-22T18:08:29.25Z" }, - { url = "https://files.pythonhosted.org/packages/cb/4c/ff8ca83d816052fba36def1d24e97d9a85739b9bbf428c0d0ecd296a07c8/bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", size = 156481, upload-time = "2024-07-22T18:09:00.303Z" }, - { url = "https://files.pythonhosted.org/packages/65/f1/e09626c88a56cda488810fb29d5035f1662873777ed337880856b9d204ae/bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", size = 151336, upload-time = "2024-07-22T18:08:48.473Z" }, - { url = "https://files.pythonhosted.org/packages/96/86/8c6a84daed4dd878fbab094400c9174c43d9b838ace077a2f8ee8bc3ae12/bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", size = 472414, upload-time = "2024-07-22T18:08:32.176Z" }, - { url = "https://files.pythonhosted.org/packages/f6/05/e394515f4e23c17662e5aeb4d1859b11dc651be01a3bd03c2e919a155901/bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", size = 277599, upload-time = "2024-07-22T18:08:53.974Z" }, - { url = "https://files.pythonhosted.org/packages/4b/3b/ad784eac415937c53da48983756105d267b91e56aa53ba8a1b2014b8d930/bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", size = 273491, upload-time = "2024-07-22T18:08:45.231Z" }, - { url = "https://files.pythonhosted.org/packages/cc/14/b9ff8e0218bee95e517b70e91130effb4511e8827ac1ab00b4e30943a3f6/bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", size = 277934, upload-time = "2024-07-22T18:09:09.189Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d0/31938bb697600a04864246acde4918c4190a938f891fd11883eaaf41327a/bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", size = 273804, upload-time = "2024-07-22T18:09:04.618Z" }, - { url = "https://files.pythonhosted.org/packages/e7/c3/dae866739989e3f04ae304e1201932571708cb292a28b2f1b93283e2dcd8/bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", size = 311275, upload-time = "2024-07-22T18:08:43.317Z" }, - { url = "https://files.pythonhosted.org/packages/5d/2c/019bc2c63c6125ddf0483ee7d914a405860327767d437913942b476e9c9b/bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", size = 306355, upload-time = "2024-07-22T18:09:06.053Z" }, - { url = "https://files.pythonhosted.org/packages/75/fe/9e137727f122bbe29771d56afbf4e0dbc85968caa8957806f86404a5bfe1/bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", size = 325381, upload-time = "2024-07-22T18:08:33.904Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d4/586b9c18a327561ea4cd336ff4586cca1a7aa0f5ee04e23a8a8bb9ca64f1/bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", size = 335685, upload-time = "2024-07-22T18:08:56.897Z" }, - { url = "https://files.pythonhosted.org/packages/24/55/1a7127faf4576138bb278b91e9c75307490178979d69c8e6e273f74b974f/bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", size = 155857, upload-time = "2024-07-22T18:08:30.827Z" }, - { url = "https://files.pythonhosted.org/packages/1c/2a/c74052e54162ec639266d91539cca7cbf3d1d3b8b36afbfeaee0ea6a1702/bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", size = 151717, upload-time = "2024-07-22T18:08:52.781Z" }, +version = "4.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/5d/6d7433e0f3cd46ce0b43cd65e1db465ea024dbb8216fb2404e919c2ad77b/bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18", size = 25697, upload-time = "2025-02-28T01:24:09.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/2c/3d44e853d1fe969d229bd58d39ae6902b3d924af0e2b5a60d17d4b809ded/bcrypt-4.3.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281", size = 483719, upload-time = "2025-02-28T01:22:34.539Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e2/58ff6e2a22eca2e2cff5370ae56dba29d70b1ea6fc08ee9115c3ae367795/bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb", size = 272001, upload-time = "2025-02-28T01:22:38.078Z" }, + { url = "https://files.pythonhosted.org/packages/37/1f/c55ed8dbe994b1d088309e366749633c9eb90d139af3c0a50c102ba68a1a/bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180", size = 277451, upload-time = "2025-02-28T01:22:40.787Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1c/794feb2ecf22fe73dcfb697ea7057f632061faceb7dcf0f155f3443b4d79/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f", size = 272792, upload-time = "2025-02-28T01:22:43.144Z" }, + { url = "https://files.pythonhosted.org/packages/13/b7/0b289506a3f3598c2ae2bdfa0ea66969812ed200264e3f61df77753eee6d/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09", size = 289752, upload-time = "2025-02-28T01:22:45.56Z" }, + { url = "https://files.pythonhosted.org/packages/dc/24/d0fb023788afe9e83cc118895a9f6c57e1044e7e1672f045e46733421fe6/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d", size = 277762, upload-time = "2025-02-28T01:22:47.023Z" }, + { url = "https://files.pythonhosted.org/packages/e4/38/cde58089492e55ac4ef6c49fea7027600c84fd23f7520c62118c03b4625e/bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd", size = 272384, upload-time = "2025-02-28T01:22:49.221Z" }, + { url = "https://files.pythonhosted.org/packages/de/6a/d5026520843490cfc8135d03012a413e4532a400e471e6188b01b2de853f/bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af", size = 277329, upload-time = "2025-02-28T01:22:51.603Z" }, + { url = "https://files.pythonhosted.org/packages/b3/a3/4fc5255e60486466c389e28c12579d2829b28a527360e9430b4041df4cf9/bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231", size = 305241, upload-time = "2025-02-28T01:22:53.283Z" }, + { url = "https://files.pythonhosted.org/packages/c7/15/2b37bc07d6ce27cc94e5b10fd5058900eb8fb11642300e932c8c82e25c4a/bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c", size = 309617, upload-time = "2025-02-28T01:22:55.461Z" }, + { url = "https://files.pythonhosted.org/packages/5f/1f/99f65edb09e6c935232ba0430c8c13bb98cb3194b6d636e61d93fe60ac59/bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f", size = 335751, upload-time = "2025-02-28T01:22:57.81Z" }, + { url = "https://files.pythonhosted.org/packages/00/1b/b324030c706711c99769988fcb694b3cb23f247ad39a7823a78e361bdbb8/bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d", size = 355965, upload-time = "2025-02-28T01:22:59.181Z" }, + { url = "https://files.pythonhosted.org/packages/aa/dd/20372a0579dd915dfc3b1cd4943b3bca431866fcb1dfdfd7518c3caddea6/bcrypt-4.3.0-cp313-cp313t-win32.whl", hash = "sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4", size = 155316, upload-time = "2025-02-28T01:23:00.763Z" }, + { url = "https://files.pythonhosted.org/packages/6d/52/45d969fcff6b5577c2bf17098dc36269b4c02197d551371c023130c0f890/bcrypt-4.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669", size = 147752, upload-time = "2025-02-28T01:23:02.908Z" }, + { url = "https://files.pythonhosted.org/packages/11/22/5ada0b9af72b60cbc4c9a399fdde4af0feaa609d27eb0adc61607997a3fa/bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d", size = 498019, upload-time = "2025-02-28T01:23:05.838Z" }, + { url = "https://files.pythonhosted.org/packages/b8/8c/252a1edc598dc1ce57905be173328eda073083826955ee3c97c7ff5ba584/bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b", size = 279174, upload-time = "2025-02-28T01:23:07.274Z" }, + { url = "https://files.pythonhosted.org/packages/29/5b/4547d5c49b85f0337c13929f2ccbe08b7283069eea3550a457914fc078aa/bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e", size = 283870, upload-time = "2025-02-28T01:23:09.151Z" }, + { url = "https://files.pythonhosted.org/packages/be/21/7dbaf3fa1745cb63f776bb046e481fbababd7d344c5324eab47f5ca92dd2/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59", size = 279601, upload-time = "2025-02-28T01:23:11.461Z" }, + { url = "https://files.pythonhosted.org/packages/6d/64/e042fc8262e971347d9230d9abbe70d68b0a549acd8611c83cebd3eaec67/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753", size = 297660, upload-time = "2025-02-28T01:23:12.989Z" }, + { url = "https://files.pythonhosted.org/packages/50/b8/6294eb84a3fef3b67c69b4470fcdd5326676806bf2519cda79331ab3c3a9/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761", size = 284083, upload-time = "2025-02-28T01:23:14.5Z" }, + { url = "https://files.pythonhosted.org/packages/62/e6/baff635a4f2c42e8788fe1b1633911c38551ecca9a749d1052d296329da6/bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb", size = 279237, upload-time = "2025-02-28T01:23:16.686Z" }, + { url = "https://files.pythonhosted.org/packages/39/48/46f623f1b0c7dc2e5de0b8af5e6f5ac4cc26408ac33f3d424e5ad8da4a90/bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d", size = 283737, upload-time = "2025-02-28T01:23:18.897Z" }, + { url = "https://files.pythonhosted.org/packages/49/8b/70671c3ce9c0fca4a6cc3cc6ccbaa7e948875a2e62cbd146e04a4011899c/bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f", size = 312741, upload-time = "2025-02-28T01:23:21.041Z" }, + { url = "https://files.pythonhosted.org/packages/27/fb/910d3a1caa2d249b6040a5caf9f9866c52114d51523ac2fb47578a27faee/bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732", size = 316472, upload-time = "2025-02-28T01:23:23.183Z" }, + { url = "https://files.pythonhosted.org/packages/dc/cf/7cf3a05b66ce466cfb575dbbda39718d45a609daa78500f57fa9f36fa3c0/bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef", size = 343606, upload-time = "2025-02-28T01:23:25.361Z" }, + { url = "https://files.pythonhosted.org/packages/e3/b8/e970ecc6d7e355c0d892b7f733480f4aa8509f99b33e71550242cf0b7e63/bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304", size = 362867, upload-time = "2025-02-28T01:23:26.875Z" }, + { url = "https://files.pythonhosted.org/packages/a9/97/8d3118efd8354c555a3422d544163f40d9f236be5b96c714086463f11699/bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51", size = 160589, upload-time = "2025-02-28T01:23:28.381Z" }, + { url = "https://files.pythonhosted.org/packages/29/07/416f0b99f7f3997c69815365babbc2e8754181a4b1899d921b3c7d5b6f12/bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62", size = 152794, upload-time = "2025-02-28T01:23:30.187Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c1/3fa0e9e4e0bfd3fd77eb8b52ec198fd6e1fd7e9402052e43f23483f956dd/bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3", size = 498969, upload-time = "2025-02-28T01:23:31.945Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d4/755ce19b6743394787fbd7dff6bf271b27ee9b5912a97242e3caf125885b/bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24", size = 279158, upload-time = "2025-02-28T01:23:34.161Z" }, + { url = "https://files.pythonhosted.org/packages/9b/5d/805ef1a749c965c46b28285dfb5cd272a7ed9fa971f970435a5133250182/bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef", size = 284285, upload-time = "2025-02-28T01:23:35.765Z" }, + { url = "https://files.pythonhosted.org/packages/ab/2b/698580547a4a4988e415721b71eb45e80c879f0fb04a62da131f45987b96/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b", size = 279583, upload-time = "2025-02-28T01:23:38.021Z" }, + { url = "https://files.pythonhosted.org/packages/f2/87/62e1e426418204db520f955ffd06f1efd389feca893dad7095bf35612eec/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676", size = 297896, upload-time = "2025-02-28T01:23:39.575Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c6/8fedca4c2ada1b6e889c52d2943b2f968d3427e5d65f595620ec4c06fa2f/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1", size = 284492, upload-time = "2025-02-28T01:23:40.901Z" }, + { url = "https://files.pythonhosted.org/packages/4d/4d/c43332dcaaddb7710a8ff5269fcccba97ed3c85987ddaa808db084267b9a/bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe", size = 279213, upload-time = "2025-02-28T01:23:42.653Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/1e36379e169a7df3a14a1c160a49b7b918600a6008de43ff20d479e6f4b5/bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0", size = 284162, upload-time = "2025-02-28T01:23:43.964Z" }, + { url = "https://files.pythonhosted.org/packages/1c/0a/644b2731194b0d7646f3210dc4d80c7fee3ecb3a1f791a6e0ae6bb8684e3/bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f", size = 312856, upload-time = "2025-02-28T01:23:46.011Z" }, + { url = "https://files.pythonhosted.org/packages/dc/62/2a871837c0bb6ab0c9a88bf54de0fc021a6a08832d4ea313ed92a669d437/bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23", size = 316726, upload-time = "2025-02-28T01:23:47.575Z" }, + { url = "https://files.pythonhosted.org/packages/0c/a1/9898ea3faac0b156d457fd73a3cb9c2855c6fd063e44b8522925cdd8ce46/bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe", size = 343664, upload-time = "2025-02-28T01:23:49.059Z" }, + { url = "https://files.pythonhosted.org/packages/40/f2/71b4ed65ce38982ecdda0ff20c3ad1b15e71949c78b2c053df53629ce940/bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505", size = 363128, upload-time = "2025-02-28T01:23:50.399Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/12f6a58eca6dea4be992d6c681b7ec9410a1d9f5cf368c61437e31daa879/bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a", size = 160598, upload-time = "2025-02-28T01:23:51.775Z" }, + { url = "https://files.pythonhosted.org/packages/a9/cf/45fb5261ece3e6b9817d3d82b2f343a505fd58674a92577923bc500bd1aa/bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b", size = 152799, upload-time = "2025-02-28T01:23:53.139Z" }, ] [[package]] @@ -547,37 +566,37 @@ wheels = [ [[package]] name = "cryptography" -version = "44.0.1" +version = "45.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/67/545c79fe50f7af51dbad56d16b23fe33f63ee6a5d956b3cb68ea110cbe64/cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14", size = 710819, upload-time = "2025-02-11T15:50:58.39Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/27/5e3524053b4c8889da65cf7814a9d0d8514a05194a25e1e34f46852ee6eb/cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009", size = 6642022, upload-time = "2025-02-11T15:49:32.752Z" }, - { url = "https://files.pythonhosted.org/packages/34/b9/4d1fa8d73ae6ec350012f89c3abfbff19fc95fe5420cf972e12a8d182986/cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f", size = 3943865, upload-time = "2025-02-11T15:49:36.659Z" }, - { url = "https://files.pythonhosted.org/packages/6e/57/371a9f3f3a4500807b5fcd29fec77f418ba27ffc629d88597d0d1049696e/cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2", size = 4162562, upload-time = "2025-02-11T15:49:39.541Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1d/5b77815e7d9cf1e3166988647f336f87d5634a5ccecec2ffbe08ef8dd481/cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911", size = 3951923, upload-time = "2025-02-11T15:49:42.461Z" }, - { url = "https://files.pythonhosted.org/packages/28/01/604508cd34a4024467cd4105887cf27da128cba3edd435b54e2395064bfb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69", size = 3685194, upload-time = "2025-02-11T15:49:45.226Z" }, - { url = "https://files.pythonhosted.org/packages/c6/3d/d3c55d4f1d24580a236a6753902ef6d8aafd04da942a1ee9efb9dc8fd0cb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026", size = 4187790, upload-time = "2025-02-11T15:49:48.215Z" }, - { url = "https://files.pythonhosted.org/packages/ea/a6/44d63950c8588bfa8594fd234d3d46e93c3841b8e84a066649c566afb972/cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd", size = 3951343, upload-time = "2025-02-11T15:49:50.313Z" }, - { url = "https://files.pythonhosted.org/packages/c1/17/f5282661b57301204cbf188254c1a0267dbd8b18f76337f0a7ce1038888c/cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0", size = 4187127, upload-time = "2025-02-11T15:49:52.051Z" }, - { url = "https://files.pythonhosted.org/packages/f3/68/abbae29ed4f9d96596687f3ceea8e233f65c9645fbbec68adb7c756bb85a/cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf", size = 4070666, upload-time = "2025-02-11T15:49:56.56Z" }, - { url = "https://files.pythonhosted.org/packages/0f/10/cf91691064a9e0a88ae27e31779200b1505d3aee877dbe1e4e0d73b4f155/cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864", size = 4288811, upload-time = "2025-02-11T15:49:59.248Z" }, - { url = "https://files.pythonhosted.org/packages/38/78/74ea9eb547d13c34e984e07ec8a473eb55b19c1451fe7fc8077c6a4b0548/cryptography-44.0.1-cp37-abi3-win32.whl", hash = "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a", size = 2771882, upload-time = "2025-02-11T15:50:01.478Z" }, - { url = "https://files.pythonhosted.org/packages/cf/6c/3907271ee485679e15c9f5e93eac6aa318f859b0aed8d369afd636fafa87/cryptography-44.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00", size = 3206989, upload-time = "2025-02-11T15:50:03.312Z" }, - { url = "https://files.pythonhosted.org/packages/9f/f1/676e69c56a9be9fd1bffa9bc3492366901f6e1f8f4079428b05f1414e65c/cryptography-44.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008", size = 6643714, upload-time = "2025-02-11T15:50:05.555Z" }, - { url = "https://files.pythonhosted.org/packages/ba/9f/1775600eb69e72d8f9931a104120f2667107a0ee478f6ad4fe4001559345/cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862", size = 3943269, upload-time = "2025-02-11T15:50:08.54Z" }, - { url = "https://files.pythonhosted.org/packages/25/ba/e00d5ad6b58183829615be7f11f55a7b6baa5a06910faabdc9961527ba44/cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3", size = 4166461, upload-time = "2025-02-11T15:50:11.419Z" }, - { url = "https://files.pythonhosted.org/packages/b3/45/690a02c748d719a95ab08b6e4decb9d81e0ec1bac510358f61624c86e8a3/cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7", size = 3950314, upload-time = "2025-02-11T15:50:14.181Z" }, - { url = "https://files.pythonhosted.org/packages/e6/50/bf8d090911347f9b75adc20f6f6569ed6ca9b9bff552e6e390f53c2a1233/cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a", size = 3686675, upload-time = "2025-02-11T15:50:16.3Z" }, - { url = "https://files.pythonhosted.org/packages/e1/e7/cfb18011821cc5f9b21efb3f94f3241e3a658d267a3bf3a0f45543858ed8/cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c", size = 4190429, upload-time = "2025-02-11T15:50:19.302Z" }, - { url = "https://files.pythonhosted.org/packages/07/ef/77c74d94a8bfc1a8a47b3cafe54af3db537f081742ee7a8a9bd982b62774/cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62", size = 3950039, upload-time = "2025-02-11T15:50:22.257Z" }, - { url = "https://files.pythonhosted.org/packages/6d/b9/8be0ff57c4592382b77406269b1e15650c9f1a167f9e34941b8515b97159/cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41", size = 4189713, upload-time = "2025-02-11T15:50:24.261Z" }, - { url = "https://files.pythonhosted.org/packages/78/e1/4b6ac5f4100545513b0847a4d276fe3c7ce0eacfa73e3b5ebd31776816ee/cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b", size = 4071193, upload-time = "2025-02-11T15:50:26.18Z" }, - { url = "https://files.pythonhosted.org/packages/3d/cb/afff48ceaed15531eab70445abe500f07f8f96af2bb35d98af6bfa89ebd4/cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7", size = 4289566, upload-time = "2025-02-11T15:50:28.221Z" }, - { url = "https://files.pythonhosted.org/packages/30/6f/4eca9e2e0f13ae459acd1ca7d9f0257ab86e68f44304847610afcb813dc9/cryptography-44.0.1-cp39-abi3-win32.whl", hash = "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9", size = 2772371, upload-time = "2025-02-11T15:50:29.997Z" }, - { url = "https://files.pythonhosted.org/packages/d2/05/5533d30f53f10239616a357f080892026db2d550a40c393d0a8a7af834a9/cryptography-44.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f", size = 3207303, upload-time = "2025-02-11T15:50:32.258Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/13/1f/9fa001e74a1993a9cadd2333bb889e50c66327b8594ac538ab8a04f915b7/cryptography-45.0.3.tar.gz", hash = "sha256:ec21313dd335c51d7877baf2972569f40a4291b76a0ce51391523ae358d05899", size = 744738, upload-time = "2025-05-25T14:17:24.777Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/b2/2345dc595998caa6f68adf84e8f8b50d18e9fc4638d32b22ea8daedd4b7a/cryptography-45.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:7573d9eebaeceeb55285205dbbb8753ac1e962af3d9640791d12b36864065e71", size = 7056239, upload-time = "2025-05-25T14:16:12.22Z" }, + { url = "https://files.pythonhosted.org/packages/71/3d/ac361649a0bfffc105e2298b720d8b862330a767dab27c06adc2ddbef96a/cryptography-45.0.3-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d377dde61c5d67eb4311eace661c3efda46c62113ff56bf05e2d679e02aebb5b", size = 4205541, upload-time = "2025-05-25T14:16:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/70/3e/c02a043750494d5c445f769e9c9f67e550d65060e0bfce52d91c1362693d/cryptography-45.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae1e637f527750811588e4582988932c222f8251f7b7ea93739acb624e1487f", size = 4433275, upload-time = "2025-05-25T14:16:16.421Z" }, + { url = "https://files.pythonhosted.org/packages/40/7a/9af0bfd48784e80eef3eb6fd6fde96fe706b4fc156751ce1b2b965dada70/cryptography-45.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ca932e11218bcc9ef812aa497cdf669484870ecbcf2d99b765d6c27a86000942", size = 4209173, upload-time = "2025-05-25T14:16:18.163Z" }, + { url = "https://files.pythonhosted.org/packages/31/5f/d6f8753c8708912df52e67969e80ef70b8e8897306cd9eb8b98201f8c184/cryptography-45.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af3f92b1dc25621f5fad065288a44ac790c5798e986a34d393ab27d2b27fcff9", size = 3898150, upload-time = "2025-05-25T14:16:20.34Z" }, + { url = "https://files.pythonhosted.org/packages/8b/50/f256ab79c671fb066e47336706dc398c3b1e125f952e07d54ce82cf4011a/cryptography-45.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f8f8f0b73b885ddd7f3d8c2b2234a7d3ba49002b0223f58cfde1bedd9563c56", size = 4466473, upload-time = "2025-05-25T14:16:22.605Z" }, + { url = "https://files.pythonhosted.org/packages/62/e7/312428336bb2df0848d0768ab5a062e11a32d18139447a76dfc19ada8eed/cryptography-45.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9cc80ce69032ffa528b5e16d217fa4d8d4bb7d6ba8659c1b4d74a1b0f4235fca", size = 4211890, upload-time = "2025-05-25T14:16:24.738Z" }, + { url = "https://files.pythonhosted.org/packages/e7/53/8a130e22c1e432b3c14896ec5eb7ac01fb53c6737e1d705df7e0efb647c6/cryptography-45.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c824c9281cb628015bfc3c59335163d4ca0540d49de4582d6c2637312907e4b1", size = 4466300, upload-time = "2025-05-25T14:16:26.768Z" }, + { url = "https://files.pythonhosted.org/packages/ba/75/6bb6579688ef805fd16a053005fce93944cdade465fc92ef32bbc5c40681/cryptography-45.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5833bb4355cb377ebd880457663a972cd044e7f49585aee39245c0d592904578", size = 4332483, upload-time = "2025-05-25T14:16:28.316Z" }, + { url = "https://files.pythonhosted.org/packages/2f/11/2538f4e1ce05c6c4f81f43c1ef2bd6de7ae5e24ee284460ff6c77e42ca77/cryptography-45.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bb5bf55dcb69f7067d80354d0a348368da907345a2c448b0babc4215ccd3497", size = 4573714, upload-time = "2025-05-25T14:16:30.474Z" }, + { url = "https://files.pythonhosted.org/packages/f5/bb/e86e9cf07f73a98d84a4084e8fd420b0e82330a901d9cac8149f994c3417/cryptography-45.0.3-cp311-abi3-win32.whl", hash = "sha256:3ad69eeb92a9de9421e1f6685e85a10fbcfb75c833b42cc9bc2ba9fb00da4710", size = 2934752, upload-time = "2025-05-25T14:16:32.204Z" }, + { url = "https://files.pythonhosted.org/packages/c7/75/063bc9ddc3d1c73e959054f1fc091b79572e716ef74d6caaa56e945b4af9/cryptography-45.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:97787952246a77d77934d41b62fb1b6f3581d83f71b44796a4158d93b8f5c490", size = 3412465, upload-time = "2025-05-25T14:16:33.888Z" }, + { url = "https://files.pythonhosted.org/packages/71/9b/04ead6015229a9396890d7654ee35ef630860fb42dc9ff9ec27f72157952/cryptography-45.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:c92519d242703b675ccefd0f0562eb45e74d438e001f8ab52d628e885751fb06", size = 7031892, upload-time = "2025-05-25T14:16:36.214Z" }, + { url = "https://files.pythonhosted.org/packages/46/c7/c7d05d0e133a09fc677b8a87953815c522697bdf025e5cac13ba419e7240/cryptography-45.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5edcb90da1843df85292ef3a313513766a78fbbb83f584a5a58fb001a5a9d57", size = 4196181, upload-time = "2025-05-25T14:16:37.934Z" }, + { url = "https://files.pythonhosted.org/packages/08/7a/6ad3aa796b18a683657cef930a986fac0045417e2dc428fd336cfc45ba52/cryptography-45.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38deed72285c7ed699864f964a3f4cf11ab3fb38e8d39cfcd96710cd2b5bb716", size = 4423370, upload-time = "2025-05-25T14:16:39.502Z" }, + { url = "https://files.pythonhosted.org/packages/4f/58/ec1461bfcb393525f597ac6a10a63938d18775b7803324072974b41a926b/cryptography-45.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5555365a50efe1f486eed6ac7062c33b97ccef409f5970a0b6f205a7cfab59c8", size = 4197839, upload-time = "2025-05-25T14:16:41.322Z" }, + { url = "https://files.pythonhosted.org/packages/d4/3d/5185b117c32ad4f40846f579369a80e710d6146c2baa8ce09d01612750db/cryptography-45.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e4253ed8f5948a3589b3caee7ad9a5bf218ffd16869c516535325fece163dcc", size = 3886324, upload-time = "2025-05-25T14:16:43.041Z" }, + { url = "https://files.pythonhosted.org/packages/67/85/caba91a57d291a2ad46e74016d1f83ac294f08128b26e2a81e9b4f2d2555/cryptography-45.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cfd84777b4b6684955ce86156cfb5e08d75e80dc2585e10d69e47f014f0a5342", size = 4450447, upload-time = "2025-05-25T14:16:44.759Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d1/164e3c9d559133a38279215c712b8ba38e77735d3412f37711b9f8f6f7e0/cryptography-45.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:a2b56de3417fd5f48773ad8e91abaa700b678dc7fe1e0c757e1ae340779acf7b", size = 4200576, upload-time = "2025-05-25T14:16:46.438Z" }, + { url = "https://files.pythonhosted.org/packages/71/7a/e002d5ce624ed46dfc32abe1deff32190f3ac47ede911789ee936f5a4255/cryptography-45.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:57a6500d459e8035e813bd8b51b671977fb149a8c95ed814989da682314d0782", size = 4450308, upload-time = "2025-05-25T14:16:48.228Z" }, + { url = "https://files.pythonhosted.org/packages/87/ad/3fbff9c28cf09b0a71e98af57d74f3662dea4a174b12acc493de00ea3f28/cryptography-45.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f22af3c78abfbc7cbcdf2c55d23c3e022e1a462ee2481011d518c7fb9c9f3d65", size = 4325125, upload-time = "2025-05-25T14:16:49.844Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b4/51417d0cc01802304c1984d76e9592f15e4801abd44ef7ba657060520bf0/cryptography-45.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:232954730c362638544758a8160c4ee1b832dc011d2c41a306ad8f7cccc5bb0b", size = 4560038, upload-time = "2025-05-25T14:16:51.398Z" }, + { url = "https://files.pythonhosted.org/packages/80/38/d572f6482d45789a7202fb87d052deb7a7b136bf17473ebff33536727a2c/cryptography-45.0.3-cp37-abi3-win32.whl", hash = "sha256:cb6ab89421bc90e0422aca911c69044c2912fc3debb19bb3c1bfe28ee3dff6ab", size = 2924070, upload-time = "2025-05-25T14:16:53.472Z" }, + { url = "https://files.pythonhosted.org/packages/91/5a/61f39c0ff4443651cc64e626fa97ad3099249152039952be8f344d6b0c86/cryptography-45.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:d54ae41e6bd70ea23707843021c778f151ca258081586f0cfa31d936ae43d1b2", size = 3395005, upload-time = "2025-05-25T14:16:55.134Z" }, ] [[package]] @@ -604,26 +623,26 @@ wheels = [ [[package]] name = "fnv-hash-fast" -version = "1.4.0" +version = "1.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fnvhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ec/36/fa1cab334dc1228235d76a22bdeab67b6895e08eb1870821c500e86b240b/fnv_hash_fast-1.4.0.tar.gz", hash = "sha256:12a2a437263f08815bd2d5759c12e881408718bb82cfffceb0341575f2c43f0a", size = 5661, upload-time = "2025-03-05T01:09:25.465Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/85/ebcbccceb212bdc9b0d964609e319469075df2a7393dcad7048a333507b6/fnv_hash_fast-1.5.0.tar.gz", hash = "sha256:c3f0d077a5e0eee6bc12938a6f560b6394b5736f3e30db83b2eca8e0fb948a74", size = 5670, upload-time = "2025-04-23T02:04:49.804Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/05/178cf5b827f0d54caa3fbb28e6e7493ad5e0d75a165b57f8c2fe9fcd3519/fnv_hash_fast-1.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7f1bbfe718df3aa10aafa2c40cf6bb9581a267c914a4005fc0f5e3ce21a01a12", size = 18552, upload-time = "2025-03-05T01:15:50.836Z" }, - { url = "https://files.pythonhosted.org/packages/b6/5b/88866809455c974b5cf8c8c18c2ad293df796083703c0da8ec6c4e50135f/fnv_hash_fast-1.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:25dd05a0e7f8381b2d881b122400862da4f855b80fa9d6f5a20cda0706fde9b7", size = 18585, upload-time = "2025-03-05T01:15:52.297Z" }, - { url = "https://files.pythonhosted.org/packages/da/60/effbe5965ab6da6e6805ca18729f588bee486b8e4127b8bf52037908a3a3/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1038ab67c143f1119b2cad9fb3d909439e88f72f3b137015eb642ad91245734", size = 21761, upload-time = "2025-03-05T01:15:54.267Z" }, - { url = "https://files.pythonhosted.org/packages/a9/87/d80f730b9f535cec9a6db8c11e9e38413e0a398d9e7f2e0abde80b3587b3/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c5ae87deee0204f2aaabfc861bf322f0f1dea078c847e10e35bc67c7becfefd6", size = 23126, upload-time = "2025-03-05T01:15:55.387Z" }, - { url = "https://files.pythonhosted.org/packages/ce/70/0c795f5a92a58f6d105078c632a9a5cf1de4bcdd42d3fec20592ed7c59f4/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a07b27755378f08e399fc124f724f3af58f8f54167f6fd525068e51ba7e9e9f", size = 22152, upload-time = "2025-03-05T01:15:56.579Z" }, - { url = "https://files.pythonhosted.org/packages/9f/72/14a8bb3844037cc6afe0ba147020ba2d450f44d29a32a0d2863583822ee2/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37cb8e67d8d4df670a699d928a4ed74b7284724d73df736a8ff9f57178e6a720", size = 19755, upload-time = "2025-03-05T01:15:57.696Z" }, - { url = "https://files.pythonhosted.org/packages/c6/f8/7cce1f63cd07c0c3d998ddd5f193b56247edd0ccb049c7549d05f559c889/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:5fa7945986ae71c68eef522335d33a671ed2c33952272ea4360d0c44331f90eb", size = 21792, upload-time = "2025-03-05T01:09:23.45Z" }, - { url = "https://files.pythonhosted.org/packages/1a/86/5e3d38f4ef3c7c862ba8cbda1d64b48b8ba314d937fe967815ee8e1d85bb/fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e6dd8f20122d0fba69171858438eb74f1f12f4630178ab0db9d05bd0dfc68054", size = 22437, upload-time = "2025-03-05T01:15:58.782Z" }, - { url = "https://files.pythonhosted.org/packages/89/85/bb90b080e30c4e082e3120874e218956a0b8a78c5913139b38c8056be4da/fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c410adea6d70c8663a168b1f499bb3cb9ff743675921aa8b6fb99e07cd83eb45", size = 20259, upload-time = "2025-03-05T01:15:59.894Z" }, - { url = "https://files.pythonhosted.org/packages/83/00/788bb2e0f369c543a8bdbc5621a7070f31b13ee6992420e198636b42276a/fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:579e5ba4265f4fc41dbe6fbe12d133d22aa7948455ef8a16fbe7bc5d1666d6d8", size = 24059, upload-time = "2025-03-05T01:16:01.121Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9d/ede35e832d6801ae8373abc8926c631cb6739e7d5e432366be44a9bf98d2/fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c9568b00ab3e91af8a8409c2955b5d781f9a338c0c00428e788ff77f3baac3ec", size = 22927, upload-time = "2025-03-05T01:16:02.228Z" }, - { url = "https://files.pythonhosted.org/packages/df/5c/2aa4c0b1b1648d80567499062bfe0414384df2487e794885d5ff4dc235a4/fnv_hash_fast-1.4.0-cp313-cp313-win32.whl", hash = "sha256:c04e54d919b5e0ef2cb6a2de0fbabb3d075ee2609324a678d2471c87542bbacb", size = 18938, upload-time = "2025-03-05T01:16:04.28Z" }, - { url = "https://files.pythonhosted.org/packages/d3/7a/a666e222003f52941aa4b620f2658cc1f665a84657886e584a69613bfb58/fnv_hash_fast-1.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:5eec9b18aee7ed014ba0b8a2cf59d5c2f2d83af683c4ad87e9c03dd2f4f5d573", size = 20453, upload-time = "2025-03-05T01:16:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/29/8e/eb6fcf4ff3d70919cc8eed1383c68682b5831b1e89d951e6922d650edeee/fnv_hash_fast-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0294a449e672583589e8e5cce9d60dfc5e29db3fb05737ccae98deba28b7d77f", size = 18597, upload-time = "2025-04-23T02:10:26.498Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f3/e5db61ba58224fd5a47fa7a16be8ee0ad1c09deadac2f73363aefa7342a9/fnv_hash_fast-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:643002874f4620c408fdf881041e7d8b23683e56b1d588604a3640758c4e6dfe", size = 18568, upload-time = "2025-04-23T02:10:27.508Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1d/8fe9a5237dd43a0a8f236413fe0e0e33b0f4f91170e6cf9f9242ff940855/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13904ceb14e09c5d6092eca8f6e1a65ea8bb606328b4b86d055365f23657ca58", size = 21736, upload-time = "2025-04-23T02:10:28.825Z" }, + { url = "https://files.pythonhosted.org/packages/d7/d5/5629db362f2f515429228b564e51a404c0b7b6cad04f4896161bfb5bb974/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:5747cc25ee940eaa70c05d0b3d0a49808e952b7dd8388453980b94ea9e95e837", size = 23091, upload-time = "2025-04-23T02:10:29.875Z" }, + { url = "https://files.pythonhosted.org/packages/c0/0c/4ba49df5da5b345cb456ea1934569472555a9c4ead4a5ae899494b52e385/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9640989256fcb9e95a383ebde372b79bb4b7e14d296e5242fb32c422a6d83480", size = 22098, upload-time = "2025-04-23T02:10:31.066Z" }, + { url = "https://files.pythonhosted.org/packages/00/3d/99d8c58f550bff0da4e51f71643fa0b2b16ef47e4e8746b0698221e01451/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e3b79e3fada2925810efd1605f265f0335cafe48f1389c96c51261b3e2e05ff", size = 19733, upload-time = "2025-04-23T02:10:32.87Z" }, + { url = "https://files.pythonhosted.org/packages/ee/00/20389a610628b5d294811fabe1bca408a4f5fe4cb5745ae05f52c77ef1b6/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:ccd18302d1a2d800f6403be7d8cb02293f2e39363bc64cd843ed040396d36f1a", size = 21731, upload-time = "2025-04-23T02:04:48.356Z" }, + { url = "https://files.pythonhosted.org/packages/41/29/0c7a0c4bd2c06d7c917d38b81a084e53176ef514d5fd9d40163be1b78d78/fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:14c7672ae4cfaf8f88418dc23ef50977f4603c602932038ae52fae44b1b03aec", size = 22374, upload-time = "2025-04-23T02:10:33.88Z" }, + { url = "https://files.pythonhosted.org/packages/ca/12/5efe53c767def55ab00ab184b4fe04591ddabffbe6daf08476dfe18dc8fb/fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:90fff41560a95d5262f2237259a94d0c8c662e131b13540e9db51dbec1a14912", size = 20260, upload-time = "2025-04-23T02:10:34.943Z" }, + { url = "https://files.pythonhosted.org/packages/81/00/83261b804ee585ec1de0da3226185e2934ec7a1747b6a871bb2cbd777e51/fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9b52650bd9107cfe8a81087b6bd9fa995f0ba23dafa1a7cb343aed99c136062", size = 23974, upload-time = "2025-04-23T02:10:35.943Z" }, + { url = "https://files.pythonhosted.org/packages/84/1a/72d8716adfe349eb3762e923df6e25346311469dfd3dbca4fc05d8176ced/fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a4b3fa3e5e3273872d021bc2d6ef26db273bdd82a1bedd49b3f798dbcb34bba", size = 22844, upload-time = "2025-04-23T02:10:36.925Z" }, + { url = "https://files.pythonhosted.org/packages/8d/65/0dd16e6b1f6d163b56b34e8c6c1af41086e8d3e5fc3b77701d24c5f5cdde/fnv_hash_fast-1.5.0-cp313-cp313-win32.whl", hash = "sha256:381175ad08ee8b0c69c14283a60a20d953c24bc19e2d80e5932eb590211c50dc", size = 18983, upload-time = "2025-04-23T02:10:37.918Z" }, + { url = "https://files.pythonhosted.org/packages/8d/8d/179abdc6304491ea72f276e1c85f5c15269f680d1cfeda07cb9963e4a03c/fnv_hash_fast-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:db8e61e38d5eddf4a4115e82bbee35f0b1b1d5affe8736f78ffc833751746cf2", size = 20507, upload-time = "2025-04-23T02:10:38.967Z" }, ] [[package]] @@ -714,7 +733,7 @@ dev = [ ] [package.metadata] -requires-dist = [{ name = "homeassistant", specifier = "==2025.4.0" }] +requires-dist = [{ name = "homeassistant", specifier = "==2025.9.0" }] [package.metadata.requires-dev] dev = [ @@ -722,18 +741,6 @@ dev = [ { name = "ruff", specifier = ">=0.14.2" }, ] -[[package]] -name = "ha-ffmpeg" -version = "3.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "async-timeout" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1e/3b/bd1284a9bc39cc119b0da551a81be6cf30dc3cfb369ce8c62fb648d7a2ea/ha_ffmpeg-3.2.2.tar.gz", hash = "sha256:80e4a77b3eda73df456ec9cc3295a898ed7cbb8cd2d59798f10e8c10a8e6c401", size = 7608, upload-time = "2024-11-08T13:32:14.181Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/66/7863e5a3713bb71c02f050f14a751b02e7a2d50eaf2109c96a1202e65d8b/ha_ffmpeg-3.2.2-py3-none-any.whl", hash = "sha256:4fd4a4f4cdaf3243d2737942f3f41f141e4437d2af1167655815dc03283b1652", size = 8749, upload-time = "2024-11-08T13:32:12.69Z" }, -] - [[package]] name = "habluetooth" version = "5.7.0" @@ -765,7 +772,7 @@ wheels = [ [[package]] name = "hass-nabucasa" -version = "0.94.0" +version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "acme" }, @@ -775,27 +782,17 @@ dependencies = [ { name = "attrs" }, { name = "ciso8601" }, { name = "cryptography" }, + { name = "josepy" }, { name = "pycognito" }, { name = "pyjwt" }, + { name = "sentence-stream" }, { name = "snitun" }, { name = "webrtc-models" }, + { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/33/ac792655794278f3d429b821a5a6f4628eb9de75fdacc222da0a13cfc9a0/hass_nabucasa-0.94.0.tar.gz", hash = "sha256:2ae8ca877dbd7c128fd49f64383e69bd86a395ed175cf73d6f33478d07491947", size = 72357, upload-time = "2025-03-03T10:54:57.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/cd/fabe44c4513600e153082e15a0b98c69d728e8fa0ed5bac7658b330f8979/hass_nabucasa-0.94.0-py3-none-any.whl", hash = "sha256:5acbe999373b81e7f6cc8d2f5918fe9db0a9e18e52e6ddb19d7857818c039c46", size = 61929, upload-time = "2025-03-03T10:54:55.93Z" }, -] - -[[package]] -name = "hassil" -version = "2.2.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyyaml" }, - { name = "unicode-rbnf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c9/f4/bf2f642321114c4ca4586efb194274905388a09b1c95e52529eba2fd4d51/hassil-2.2.3.tar.gz", hash = "sha256:8516ebde2caf72362ea566cd677cb382138be3f5d36889fee21bb313bfd7d0d8", size = 46867, upload-time = "2025-02-04T17:36:22.142Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/bc/e75262103f27b0736f4bfb12637787684268c1ceec9686d549fb40c36b3a/hass_nabucasa-1.1.0.tar.gz", hash = "sha256:c9714b54ed94c8e32a8a2eec2b3e42e57739c8fa85eda164b08b292f1f311246", size = 90993, upload-time = "2025-09-03T08:40:04.711Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/ae/684cf7117bdd757bb7d92c20deb528db2d42a3d018fc788f1c415421d809/hassil-2.2.3-py3-none-any.whl", hash = "sha256:d22032c5268e6bdfc7fb60fa8f52f3a955d5ca982ccbfe535ed074c593e66bdf", size = 42097, upload-time = "2025-02-04T17:36:21.09Z" }, + { url = "https://files.pythonhosted.org/packages/54/35/adba64783adaeaf4108e51d7c869397e3e1fafda7777ec54274b4fff1e05/hass_nabucasa-1.1.0-py3-none-any.whl", hash = "sha256:d10498e0f61d19369e12eba121c391cc5a79f7b71d6d3295ca0e8ff7ecfb96f6", size = 73127, upload-time = "2025-09-03T08:40:03.286Z" }, ] [[package]] @@ -810,18 +807,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/85/9b/9904cec885cc32c45e8c22cd7e19d9c342e30074fdb7c58f3d5b33ea1adb/home_assistant_bluetooth-1.13.1-py3-none-any.whl", hash = "sha256:cdf13b5b45f7744165677831e309ee78fbaf0c2866c6b5931e14d1e4e7dae5d7", size = 7915, upload-time = "2025-02-04T16:11:13.163Z" }, ] -[[package]] -name = "home-assistant-intents" -version = "2025.3.28" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4b/f1/9c13e5535bbcf4801f81d88f452581b113246e485d8ff9f9d64faffcf50f/home_assistant_intents-2025.3.28.tar.gz", hash = "sha256:3b93717525ae738f9163a2215bb0628321b86bd8418bfd64e1d5ce571b84fef4", size = 451905, upload-time = "2025-03-28T14:26:00.919Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/e5/627c5cb34ed05bbe3227834702327fab6cbed6c5d6f0c6f053a85cc2b10f/home_assistant_intents-2025.3.28-py3-none-any.whl", hash = "sha256:14f589a5a188f8b0c52f06ff8998c171fda25f8729de7a4011636295d90e7295", size = 470049, upload-time = "2025-03-28T14:25:59.107Z" }, -] - [[package]] name = "homeassistant" -version = "2025.4.0" +version = "2025.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiodns" }, @@ -844,28 +832,20 @@ dependencies = [ { name = "cronsim" }, { name = "cryptography" }, { name = "fnv-hash-fast" }, - { name = "ha-ffmpeg" }, { name = "hass-nabucasa" }, - { name = "hassil" }, { name = "home-assistant-bluetooth" }, - { name = "home-assistant-intents" }, { name = "httpx" }, { name = "ifaddr" }, { name = "jinja2" }, { name = "lru-dict" }, - { name = "mutagen" }, - { name = "numpy" }, { name = "orjson" }, { name = "packaging" }, { name = "pillow" }, { name = "propcache" }, { name = "psutil-home-assistant" }, { name = "pyjwt" }, - { name = "pymicro-vad" }, { name = "pyopenssl" }, - { name = "pyspeex-noise" }, { name = "python-slugify" }, - { name = "pyturbojpeg" }, { name = "pyyaml" }, { name = "requests" }, { name = "securetar" }, @@ -883,9 +863,9 @@ dependencies = [ { name = "yarl" }, { name = "zeroconf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f2/f1/4163474410566c1b5a0888740f87d414bd84263fa17360a3c3938cb4e65e/homeassistant-2025.4.0.tar.gz", hash = "sha256:c1f9702e4a935da061d5f95254d25c039282862a510b3643ee76fb55a2b610f3", size = 25040180, upload-time = "2025-04-02T17:19:14.907Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/d1/c3c7c042acb9adcaa51f60f8e88feee726905f2b8bf0e7f7308aa18e02ad/homeassistant-2025.9.0.tar.gz", hash = "sha256:f2afb8dc2ecedb3dc809b79a1c7099e2b0ad177631aec880904578f7716cedfc", size = 27782182, upload-time = "2025-09-03T18:30:25.159Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/5d/f346faa9fa684a0321db3800598ee62cf14b8163eab30c9fe5222ecf5425/homeassistant-2025.4.0-py3-none-any.whl", hash = "sha256:b1159c123b97fe372feadbe505cf920b87fbcd932177e5c0c86a6f6b3c6ee1b9", size = 42937231, upload-time = "2025-04-02T17:19:08.558Z" }, + { url = "https://files.pythonhosted.org/packages/40/2f/a0e924149bff1f4dbfee7d7d146811300eee649eeff83f9d4b2ad2ebd2c7/homeassistant-2025.9.0-py3-none-any.whl", hash = "sha256:51bda990b96c419f5e2a3410aa1a636e454ac5a65616ea8ec663f04956c5a725", size = 46884752, upload-time = "2025-09-03T18:30:18.917Z" }, ] [[package]] @@ -957,15 +937,14 @@ wheels = [ [[package]] name = "josepy" -version = "1.15.0" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, - { name = "pyopenssl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c1/8a/cd416f56cd4492878e8d62701b4ad32407c5ce541f247abf31d6e5f3b79b/josepy-1.15.0.tar.gz", hash = "sha256:46c9b13d1a5104ffbfa5853e555805c915dcde71c2cd91ce5386e84211281223", size = 59310, upload-time = "2025-01-22T23:56:23.577Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/ad/6f520aee9cc9618d33430380741e9ef859b2c560b1e7915e755c084f6bc0/josepy-2.2.0.tar.gz", hash = "sha256:74c033151337c854f83efe5305a291686cef723b4b970c43cfe7270cf4a677a9", size = 56500, upload-time = "2025-10-14T14:54:42.108Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/74/fc54f4b03cb66b0b351131fcf1797fe9d7c1e6ce9a38fd940d9bc2d9531b/josepy-1.15.0-py3-none-any.whl", hash = "sha256:878c08cedd0a892c98c6d1a90b3cb869736f9c751f68ec8901e7b05a0c040fed", size = 32774, upload-time = "2025-01-22T23:56:21.524Z" }, + { url = "https://files.pythonhosted.org/packages/f8/b2/b5caed897fbb1cc286c62c01feca977e08d99a17230ff3055b9a98eccf1d/josepy-2.2.0-py3-none-any.whl", hash = "sha256:63e9dd116d4078778c25ca88f880cc5d95f1cab0099bebe3a34c2e299f65d10b", size = 29211, upload-time = "2025-10-14T14:54:41.144Z" }, ] [[package]] @@ -1061,63 +1040,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, ] -[[package]] -name = "mutagen" -version = "1.47.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/e6/64bc71b74eef4b68e61eb921dcf72dabd9e4ec4af1e11891bbd312ccbb77/mutagen-1.47.0.tar.gz", hash = "sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99", size = 1274186, upload-time = "2023-09-03T16:33:33.411Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/7a/620f945b96be1f6ee357d211d5bf74ab1b7fe72a9f1525aafbfe3aee6875/mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719", size = 194391, upload-time = "2023-09-03T16:33:29.955Z" }, -] - -[[package]] -name = "numpy" -version = "2.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/d0/c12ddfd3a02274be06ffc71f3efc6d0e457b0409c4481596881e748cb264/numpy-2.2.2.tar.gz", hash = "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f", size = 20233295, upload-time = "2025-01-19T00:02:09.581Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/fe/df5624001f4f5c3e0b78e9017bfab7fdc18a8d3b3d3161da3d64924dd659/numpy-2.2.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc", size = 20899188, upload-time = "2025-01-18T23:31:15.292Z" }, - { url = "https://files.pythonhosted.org/packages/a9/80/d349c3b5ed66bd3cb0214be60c27e32b90a506946857b866838adbe84040/numpy-2.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369", size = 14113972, upload-time = "2025-01-18T23:31:42.323Z" }, - { url = "https://files.pythonhosted.org/packages/9d/50/949ec9cbb28c4b751edfa64503f0913cbfa8d795b4a251e7980f13a8a655/numpy-2.2.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd", size = 5114294, upload-time = "2025-01-18T23:31:54.219Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f3/399c15629d5a0c68ef2aa7621d430b2be22034f01dd7f3c65a9c9666c445/numpy-2.2.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be", size = 6648426, upload-time = "2025-01-18T23:32:06.055Z" }, - { url = "https://files.pythonhosted.org/packages/2c/03/c72474c13772e30e1bc2e558cdffd9123c7872b731263d5648b5c49dd459/numpy-2.2.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84", size = 14045990, upload-time = "2025-01-18T23:32:38.031Z" }, - { url = "https://files.pythonhosted.org/packages/83/9c/96a9ab62274ffafb023f8ee08c88d3d31ee74ca58869f859db6845494fa6/numpy-2.2.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff", size = 16096614, upload-time = "2025-01-18T23:33:12.265Z" }, - { url = "https://files.pythonhosted.org/packages/d5/34/cd0a735534c29bec7093544b3a509febc9b0df77718a9b41ffb0809c9f46/numpy-2.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0", size = 15242123, upload-time = "2025-01-18T23:33:46.412Z" }, - { url = "https://files.pythonhosted.org/packages/5e/6d/541717a554a8f56fa75e91886d9b79ade2e595918690eb5d0d3dbd3accb9/numpy-2.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de", size = 17859160, upload-time = "2025-01-18T23:34:37.857Z" }, - { url = "https://files.pythonhosted.org/packages/b9/a5/fbf1f2b54adab31510728edd06a05c1b30839f37cf8c9747cb85831aaf1b/numpy-2.2.2-cp313-cp313-win32.whl", hash = "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9", size = 6273337, upload-time = "2025-01-18T23:40:10.83Z" }, - { url = "https://files.pythonhosted.org/packages/56/e5/01106b9291ef1d680f82bc47d0c5b5e26dfed15b0754928e8f856c82c881/numpy-2.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369", size = 12609010, upload-time = "2025-01-18T23:40:31.34Z" }, - { url = "https://files.pythonhosted.org/packages/9f/30/f23d9876de0f08dceb707c4dcf7f8dd7588266745029debb12a3cdd40be6/numpy-2.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391", size = 20924451, upload-time = "2025-01-18T23:35:26.639Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ec/6ea85b2da9d5dfa1dbb4cb3c76587fc8ddcae580cb1262303ab21c0926c4/numpy-2.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39", size = 14122390, upload-time = "2025-01-18T23:36:30.596Z" }, - { url = "https://files.pythonhosted.org/packages/68/05/bfbdf490414a7dbaf65b10c78bc243f312c4553234b6d91c94eb7c4b53c2/numpy-2.2.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317", size = 5156590, upload-time = "2025-01-18T23:36:52.637Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ec/fe2e91b2642b9d6544518388a441bcd65c904cea38d9ff998e2e8ebf808e/numpy-2.2.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49", size = 6671958, upload-time = "2025-01-18T23:37:05.361Z" }, - { url = "https://files.pythonhosted.org/packages/b1/6f/6531a78e182f194d33ee17e59d67d03d0d5a1ce7f6be7343787828d1bd4a/numpy-2.2.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2", size = 14019950, upload-time = "2025-01-18T23:37:38.605Z" }, - { url = "https://files.pythonhosted.org/packages/e1/fb/13c58591d0b6294a08cc40fcc6b9552d239d773d520858ae27f39997f2ae/numpy-2.2.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7", size = 16079759, upload-time = "2025-01-18T23:38:05.757Z" }, - { url = "https://files.pythonhosted.org/packages/2c/f2/f2f8edd62abb4b289f65a7f6d1f3650273af00b91b7267a2431be7f1aec6/numpy-2.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb", size = 15226139, upload-time = "2025-01-18T23:38:38.458Z" }, - { url = "https://files.pythonhosted.org/packages/aa/29/14a177f1a90b8ad8a592ca32124ac06af5eff32889874e53a308f850290f/numpy-2.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648", size = 17856316, upload-time = "2025-01-18T23:39:11.454Z" }, - { url = "https://files.pythonhosted.org/packages/95/03/242ae8d7b97f4e0e4ab8dd51231465fb23ed5e802680d629149722e3faf1/numpy-2.2.2-cp313-cp313t-win32.whl", hash = "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4", size = 6329134, upload-time = "2025-01-18T23:39:28.128Z" }, - { url = "https://files.pythonhosted.org/packages/80/94/cd9e9b04012c015cb6320ab3bf43bc615e248dddfeb163728e800a5d96f0/numpy-2.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576", size = 12696208, upload-time = "2025-01-18T23:39:51.85Z" }, -] - [[package]] name = "orjson" -version = "3.10.16" +version = "3.11.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/c7/03913cc4332174071950acf5b0735463e3f63760c80585ef369270c2b372/orjson-3.10.16.tar.gz", hash = "sha256:d2aaa5c495e11d17b9b93205f5fa196737ee3202f000aaebf028dc9a73750f10", size = 5410415, upload-time = "2025-03-24T17:00:23.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/4d/8df5f83256a809c22c4d6792ce8d43bb503be0fb7a8e4da9025754b09658/orjson-3.11.3.tar.gz", hash = "sha256:1c0603b1d2ffcd43a411d64797a19556ef76958aef1c182f22dc30860152a98a", size = 5482394, upload-time = "2025-08-26T17:46:43.171Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/b9/ff6aa28b8c86af9526160905593a2fe8d004ac7a5e592ee0b0ff71017511/orjson-3.10.16-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:148a97f7de811ba14bc6dbc4a433e0341ffd2cc285065199fb5f6a98013744bd", size = 249289, upload-time = "2025-03-24T16:59:40.117Z" }, - { url = "https://files.pythonhosted.org/packages/6c/81/6d92a586149b52684ab8fd70f3623c91d0e6a692f30fd8c728916ab2263c/orjson-3.10.16-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1d960c1bf0e734ea36d0adc880076de3846aaec45ffad29b78c7f1b7962516b8", size = 133640, upload-time = "2025-03-24T16:59:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/c2/88/b72443f4793d2e16039ab85d0026677932b15ab968595fb7149750d74134/orjson-3.10.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a318cd184d1269f68634464b12871386808dc8b7c27de8565234d25975a7a137", size = 138286, upload-time = "2025-03-24T16:59:42.769Z" }, - { url = "https://files.pythonhosted.org/packages/c3/3c/72a22d4b28c076c4016d5a52bd644a8e4d849d3bb0373d9e377f9e3b2250/orjson-3.10.16-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df23f8df3ef9223d1d6748bea63fca55aae7da30a875700809c500a05975522b", size = 132307, upload-time = "2025-03-24T16:59:44.143Z" }, - { url = "https://files.pythonhosted.org/packages/8a/a2/f1259561bdb6ad7061ff1b95dab082fe32758c4bc143ba8d3d70831f0a06/orjson-3.10.16-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b94dda8dd6d1378f1037d7f3f6b21db769ef911c4567cbaa962bb6dc5021cf90", size = 136739, upload-time = "2025-03-24T16:59:45.995Z" }, - { url = "https://files.pythonhosted.org/packages/3d/af/c7583c4b34f33d8b8b90cfaab010ff18dd64e7074cc1e117a5f1eff20dcf/orjson-3.10.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f12970a26666a8775346003fd94347d03ccb98ab8aa063036818381acf5f523e", size = 138076, upload-time = "2025-03-24T16:59:47.776Z" }, - { url = "https://files.pythonhosted.org/packages/d7/59/d7fc7fbdd3d4a64c2eae4fc7341a5aa39cf9549bd5e2d7f6d3c07f8b715b/orjson-3.10.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15a1431a245d856bd56e4d29ea0023eb4d2c8f71efe914beb3dee8ab3f0cd7fb", size = 142643, upload-time = "2025-03-24T16:59:49.258Z" }, - { url = "https://files.pythonhosted.org/packages/92/0e/3bd8f2197d27601f16b4464ae948826da2bcf128af31230a9dbbad7ceb57/orjson-3.10.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c83655cfc247f399a222567d146524674a7b217af7ef8289c0ff53cfe8db09f0", size = 133168, upload-time = "2025-03-24T16:59:51.027Z" }, - { url = "https://files.pythonhosted.org/packages/af/a8/351fd87b664b02f899f9144d2c3dc848b33ac04a5df05234cbfb9e2a7540/orjson-3.10.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fa59ae64cb6ddde8f09bdbf7baf933c4cd05734ad84dcf4e43b887eb24e37652", size = 135271, upload-time = "2025-03-24T16:59:52.449Z" }, - { url = "https://files.pythonhosted.org/packages/ba/b0/a6d42a7d412d867c60c0337d95123517dd5a9370deea705ea1be0f89389e/orjson-3.10.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ca5426e5aacc2e9507d341bc169d8af9c3cbe88f4cd4c1cf2f87e8564730eb56", size = 412444, upload-time = "2025-03-24T16:59:53.825Z" }, - { url = "https://files.pythonhosted.org/packages/79/ec/7572cd4e20863f60996f3f10bc0a6da64a6fd9c35954189a914cec0b7377/orjson-3.10.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6fd5da4edf98a400946cd3a195680de56f1e7575109b9acb9493331047157430", size = 152737, upload-time = "2025-03-24T16:59:55.599Z" }, - { url = "https://files.pythonhosted.org/packages/a9/19/ceb9e8fed5403b2e76a8ac15f581b9d25780a3be3c9b3aa54b7777a210d5/orjson-3.10.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:980ecc7a53e567169282a5e0ff078393bac78320d44238da4e246d71a4e0e8f5", size = 137482, upload-time = "2025-03-24T16:59:57.045Z" }, - { url = "https://files.pythonhosted.org/packages/1b/78/a78bb810f3786579dbbbd94768284cbe8f2fd65167cd7020260679665c17/orjson-3.10.16-cp313-cp313-win32.whl", hash = "sha256:28f79944dd006ac540a6465ebd5f8f45dfdf0948ff998eac7a908275b4c1add6", size = 141714, upload-time = "2025-03-24T16:59:58.666Z" }, - { url = "https://files.pythonhosted.org/packages/81/9c/b66ce9245ff319df2c3278acd351a3f6145ef34b4a2d7f4b0f739368370f/orjson-3.10.16-cp313-cp313-win_amd64.whl", hash = "sha256:fe0a145e96d51971407cb8ba947e63ead2aa915db59d6631a355f5f2150b56b7", size = 133954, upload-time = "2025-03-24T17:00:00.101Z" }, + { url = "https://files.pythonhosted.org/packages/fc/79/8932b27293ad35919571f77cb3693b5906cf14f206ef17546052a241fdf6/orjson-3.11.3-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:af40c6612fd2a4b00de648aa26d18186cd1322330bd3a3cc52f87c699e995810", size = 238127, upload-time = "2025-08-26T17:45:38.146Z" }, + { url = "https://files.pythonhosted.org/packages/1c/82/cb93cd8cf132cd7643b30b6c5a56a26c4e780c7a145db6f83de977b540ce/orjson-3.11.3-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:9f1587f26c235894c09e8b5b7636a38091a9e6e7fe4531937534749c04face43", size = 127494, upload-time = "2025-08-26T17:45:39.57Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/2d9eb181a9b6bb71463a78882bcac1027fd29cf62c38a40cc02fc11d3495/orjson-3.11.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61dcdad16da5bb486d7227a37a2e789c429397793a6955227cedbd7252eb5a27", size = 123017, upload-time = "2025-08-26T17:45:40.876Z" }, + { url = "https://files.pythonhosted.org/packages/b4/14/a0e971e72d03b509190232356d54c0f34507a05050bd026b8db2bf2c192c/orjson-3.11.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11c6d71478e2cbea0a709e8a06365fa63da81da6498a53e4c4f065881d21ae8f", size = 127898, upload-time = "2025-08-26T17:45:42.188Z" }, + { url = "https://files.pythonhosted.org/packages/8e/af/dc74536722b03d65e17042cc30ae586161093e5b1f29bccda24765a6ae47/orjson-3.11.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff94112e0098470b665cb0ed06efb187154b63649403b8d5e9aedeb482b4548c", size = 130742, upload-time = "2025-08-26T17:45:43.511Z" }, + { url = "https://files.pythonhosted.org/packages/62/e6/7a3b63b6677bce089fe939353cda24a7679825c43a24e49f757805fc0d8a/orjson-3.11.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b756575aaa2a855a75192f356bbda11a89169830e1439cfb1a3e1a6dde7be", size = 132377, upload-time = "2025-08-26T17:45:45.525Z" }, + { url = "https://files.pythonhosted.org/packages/fc/cd/ce2ab93e2e7eaf518f0fd15e3068b8c43216c8a44ed82ac2b79ce5cef72d/orjson-3.11.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9416cc19a349c167ef76135b2fe40d03cea93680428efee8771f3e9fb66079d", size = 135313, upload-time = "2025-08-26T17:45:46.821Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/f98355eff0bd1a38454209bbc73372ce351ba29933cb3e2eba16c04b9448/orjson-3.11.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b822caf5b9752bc6f246eb08124c3d12bf2175b66ab74bac2ef3bbf9221ce1b2", size = 132908, upload-time = "2025-08-26T17:45:48.126Z" }, + { url = "https://files.pythonhosted.org/packages/eb/92/8f5182d7bc2a1bed46ed960b61a39af8389f0ad476120cd99e67182bfb6d/orjson-3.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:414f71e3bdd5573893bf5ecdf35c32b213ed20aa15536fe2f588f946c318824f", size = 130905, upload-time = "2025-08-26T17:45:49.414Z" }, + { url = "https://files.pythonhosted.org/packages/1a/60/c41ca753ce9ffe3d0f67b9b4c093bdd6e5fdb1bc53064f992f66bb99954d/orjson-3.11.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:828e3149ad8815dc14468f36ab2a4b819237c155ee1370341b91ea4c8672d2ee", size = 403812, upload-time = "2025-08-26T17:45:51.085Z" }, + { url = "https://files.pythonhosted.org/packages/dd/13/e4a4f16d71ce1868860db59092e78782c67082a8f1dc06a3788aef2b41bc/orjson-3.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac9e05f25627ffc714c21f8dfe3a579445a5c392a9c8ae7ba1d0e9fb5333f56e", size = 146277, upload-time = "2025-08-26T17:45:52.851Z" }, + { url = "https://files.pythonhosted.org/packages/8d/8b/bafb7f0afef9344754a3a0597a12442f1b85a048b82108ef2c956f53babd/orjson-3.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e44fbe4000bd321d9f3b648ae46e0196d21577cf66ae684a96ff90b1f7c93633", size = 135418, upload-time = "2025-08-26T17:45:54.806Z" }, + { url = "https://files.pythonhosted.org/packages/60/d4/bae8e4f26afb2c23bea69d2f6d566132584d1c3a5fe89ee8c17b718cab67/orjson-3.11.3-cp313-cp313-win32.whl", hash = "sha256:2039b7847ba3eec1f5886e75e6763a16e18c68a63efc4b029ddf994821e2e66b", size = 136216, upload-time = "2025-08-26T17:45:57.182Z" }, + { url = "https://files.pythonhosted.org/packages/88/76/224985d9f127e121c8cad882cea55f0ebe39f97925de040b75ccd4b33999/orjson-3.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:29be5ac4164aa8bdcba5fa0700a3c9c316b411d8ed9d39ef8a882541bd452fae", size = 131362, upload-time = "2025-08-26T17:45:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cf/0dce7a0be94bd36d1346be5067ed65ded6adb795fdbe3abd234c8d576d01/orjson-3.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:18bd1435cb1f2857ceb59cfb7de6f92593ef7b831ccd1b9bfb28ca530e539dce", size = 125989, upload-time = "2025-08-26T17:45:59.95Z" }, ] [[package]] @@ -1131,70 +1074,76 @@ wheels = [ [[package]] name = "pillow" -version = "11.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/af/c097e544e7bd278333db77933e535098c259609c4eb3b85381109602fb5b/pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", size = 46742715, upload-time = "2025-01-02T08:13:58.407Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/31/9ca79cafdce364fd5c980cd3416c20ce1bebd235b470d262f9d24d810184/pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc", size = 3226640, upload-time = "2025-01-02T08:11:58.329Z" }, - { url = "https://files.pythonhosted.org/packages/ac/0f/ff07ad45a1f172a497aa393b13a9d81a32e1477ef0e869d030e3c1532521/pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0", size = 3101437, upload-time = "2025-01-02T08:12:01.797Z" }, - { url = "https://files.pythonhosted.org/packages/08/2f/9906fca87a68d29ec4530be1f893149e0cb64a86d1f9f70a7cfcdfe8ae44/pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1", size = 4326605, upload-time = "2025-01-02T08:12:05.224Z" }, - { url = "https://files.pythonhosted.org/packages/b0/0f/f3547ee15b145bc5c8b336401b2d4c9d9da67da9dcb572d7c0d4103d2c69/pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec", size = 4411173, upload-time = "2025-01-02T08:12:08.281Z" }, - { url = "https://files.pythonhosted.org/packages/b1/df/bf8176aa5db515c5de584c5e00df9bab0713548fd780c82a86cba2c2fedb/pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5", size = 4369145, upload-time = "2025-01-02T08:12:11.411Z" }, - { url = "https://files.pythonhosted.org/packages/de/7c/7433122d1cfadc740f577cb55526fdc39129a648ac65ce64db2eb7209277/pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114", size = 4496340, upload-time = "2025-01-02T08:12:15.29Z" }, - { url = "https://files.pythonhosted.org/packages/25/46/dd94b93ca6bd555588835f2504bd90c00d5438fe131cf01cfa0c5131a19d/pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352", size = 4296906, upload-time = "2025-01-02T08:12:17.485Z" }, - { url = "https://files.pythonhosted.org/packages/a8/28/2f9d32014dfc7753e586db9add35b8a41b7a3b46540e965cb6d6bc607bd2/pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3", size = 4431759, upload-time = "2025-01-02T08:12:20.382Z" }, - { url = "https://files.pythonhosted.org/packages/33/48/19c2cbe7403870fbe8b7737d19eb013f46299cdfe4501573367f6396c775/pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9", size = 2291657, upload-time = "2025-01-02T08:12:23.922Z" }, - { url = "https://files.pythonhosted.org/packages/3b/ad/285c556747d34c399f332ba7c1a595ba245796ef3e22eae190f5364bb62b/pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c", size = 2626304, upload-time = "2025-01-02T08:12:28.069Z" }, - { url = "https://files.pythonhosted.org/packages/e5/7b/ef35a71163bf36db06e9c8729608f78dedf032fc8313d19bd4be5c2588f3/pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65", size = 2375117, upload-time = "2025-01-02T08:12:30.064Z" }, - { url = "https://files.pythonhosted.org/packages/79/30/77f54228401e84d6791354888549b45824ab0ffde659bafa67956303a09f/pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861", size = 3230060, upload-time = "2025-01-02T08:12:32.362Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b1/56723b74b07dd64c1010fee011951ea9c35a43d8020acd03111f14298225/pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081", size = 3106192, upload-time = "2025-01-02T08:12:34.361Z" }, - { url = "https://files.pythonhosted.org/packages/e1/cd/7bf7180e08f80a4dcc6b4c3a0aa9e0b0ae57168562726a05dc8aa8fa66b0/pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c", size = 4446805, upload-time = "2025-01-02T08:12:36.99Z" }, - { url = "https://files.pythonhosted.org/packages/97/42/87c856ea30c8ed97e8efbe672b58c8304dee0573f8c7cab62ae9e31db6ae/pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547", size = 4530623, upload-time = "2025-01-02T08:12:41.912Z" }, - { url = "https://files.pythonhosted.org/packages/ff/41/026879e90c84a88e33fb00cc6bd915ac2743c67e87a18f80270dfe3c2041/pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab", size = 4465191, upload-time = "2025-01-02T08:12:45.186Z" }, - { url = "https://files.pythonhosted.org/packages/e5/fb/a7960e838bc5df57a2ce23183bfd2290d97c33028b96bde332a9057834d3/pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9", size = 2295494, upload-time = "2025-01-02T08:12:47.098Z" }, - { url = "https://files.pythonhosted.org/packages/d7/6c/6ec83ee2f6f0fda8d4cf89045c6be4b0373ebfc363ba8538f8c999f63fcd/pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe", size = 2631595, upload-time = "2025-01-02T08:12:50.47Z" }, - { url = "https://files.pythonhosted.org/packages/cf/6c/41c21c6c8af92b9fea313aa47c75de49e2f9a467964ee33eb0135d47eb64/pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756", size = 2377651, upload-time = "2025-01-02T08:12:53.356Z" }, +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, ] [[package]] name = "propcache" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/76/f941e63d55c0293ff7829dd21e7cf1147e90a526756869a9070f287a68c9/propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5", size = 42722, upload-time = "2025-02-20T19:03:29.191Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/0f/a79dd23a0efd6ee01ab0dc9750d8479b343bfd0c73560d59d271eb6a99d4/propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568", size = 77287, upload-time = "2025-02-20T19:01:40.897Z" }, - { url = "https://files.pythonhosted.org/packages/b8/51/76675703c90de38ac75adb8deceb3f3ad99b67ff02a0fa5d067757971ab8/propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9", size = 44923, upload-time = "2025-02-20T19:01:42.397Z" }, - { url = "https://files.pythonhosted.org/packages/01/9b/fd5ddbee66cf7686e73c516227c2fd9bf471dbfed0f48329d095ea1228d3/propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767", size = 44325, upload-time = "2025-02-20T19:01:43.976Z" }, - { url = "https://files.pythonhosted.org/packages/13/1c/6961f11eb215a683b34b903b82bde486c606516c1466bf1fa67f26906d51/propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8", size = 225116, upload-time = "2025-02-20T19:01:45.488Z" }, - { url = "https://files.pythonhosted.org/packages/ef/ea/f8410c40abcb2e40dffe9adeed017898c930974650a63e5c79b886aa9f73/propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0", size = 229905, upload-time = "2025-02-20T19:01:49.454Z" }, - { url = "https://files.pythonhosted.org/packages/ef/5a/a9bf90894001468bf8e6ea293bb00626cc9ef10f8eb7996e9ec29345c7ed/propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d", size = 233221, upload-time = "2025-02-20T19:01:51.142Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ce/fffdddd9725b690b01d345c1156b4c2cc6dca09ab5c23a6d07b8f37d6e2f/propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05", size = 227627, upload-time = "2025-02-20T19:01:53.695Z" }, - { url = "https://files.pythonhosted.org/packages/58/ae/45c89a5994a334735a3032b48e8e4a98c05d9536ddee0719913dc27da548/propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe", size = 214217, upload-time = "2025-02-20T19:01:55.309Z" }, - { url = "https://files.pythonhosted.org/packages/01/84/bc60188c3290ff8f5f4a92b9ca2d93a62e449c8daf6fd11ad517ad136926/propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1", size = 212921, upload-time = "2025-02-20T19:01:57.893Z" }, - { url = "https://files.pythonhosted.org/packages/14/b3/39d60224048feef7a96edabb8217dc3f75415457e5ebbef6814f8b2a27b5/propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92", size = 208200, upload-time = "2025-02-20T19:02:00.026Z" }, - { url = "https://files.pythonhosted.org/packages/9d/b3/0a6720b86791251273fff8a01bc8e628bc70903513bd456f86cde1e1ef84/propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787", size = 208400, upload-time = "2025-02-20T19:02:03.997Z" }, - { url = "https://files.pythonhosted.org/packages/e9/4f/bb470f3e687790547e2e78105fb411f54e0cdde0d74106ccadd2521c6572/propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545", size = 218116, upload-time = "2025-02-20T19:02:06.042Z" }, - { url = "https://files.pythonhosted.org/packages/34/71/277f7f9add469698ac9724c199bfe06f85b199542121a71f65a80423d62a/propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e", size = 222911, upload-time = "2025-02-20T19:02:08.748Z" }, - { url = "https://files.pythonhosted.org/packages/92/e3/a7b9782aef5a2fc765b1d97da9ec7aed2f25a4e985703608e73232205e3f/propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626", size = 216563, upload-time = "2025-02-20T19:02:11.322Z" }, - { url = "https://files.pythonhosted.org/packages/ab/76/0583ca2c551aa08ffcff87b2c6849c8f01c1f6fb815a5226f0c5c202173e/propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374", size = 39763, upload-time = "2025-02-20T19:02:12.977Z" }, - { url = "https://files.pythonhosted.org/packages/80/ec/c6a84f9a36f608379b95f0e786c111d5465926f8c62f12be8cdadb02b15c/propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a", size = 43650, upload-time = "2025-02-20T19:02:15.041Z" }, - { url = "https://files.pythonhosted.org/packages/ee/95/7d32e3560f5bf83fc2f2a4c1b0c181d327d53d5f85ebd045ab89d4d97763/propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf", size = 82140, upload-time = "2025-02-20T19:02:16.562Z" }, - { url = "https://files.pythonhosted.org/packages/86/89/752388f12e6027a5e63f5d075f15291ded48e2d8311314fff039da5a9b11/propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0", size = 47296, upload-time = "2025-02-20T19:02:17.974Z" }, - { url = "https://files.pythonhosted.org/packages/1b/4c/b55c98d586c69180d3048984a57a5ea238bdeeccf82dbfcd598e935e10bb/propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829", size = 46724, upload-time = "2025-02-20T19:02:19.588Z" }, - { url = "https://files.pythonhosted.org/packages/0f/b6/67451a437aed90c4e951e320b5b3d7eb584ade1d5592f6e5e8f678030989/propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa", size = 291499, upload-time = "2025-02-20T19:02:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ff/e4179facd21515b24737e1e26e02615dfb5ed29416eed4cf5bc6ac5ce5fb/propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6", size = 293911, upload-time = "2025-02-20T19:02:24.248Z" }, - { url = "https://files.pythonhosted.org/packages/76/8d/94a8585992a064a23bd54f56c5e58c3b8bf0c0a06ae10e56f2353ae16c3d/propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db", size = 293301, upload-time = "2025-02-20T19:02:26.034Z" }, - { url = "https://files.pythonhosted.org/packages/b0/b8/2c860c92b4134f68c7716c6f30a0d723973f881c32a6d7a24c4ddca05fdf/propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54", size = 281947, upload-time = "2025-02-20T19:02:27.838Z" }, - { url = "https://files.pythonhosted.org/packages/cd/72/b564be7411b525d11757b713c757c21cd4dc13b6569c3b2b8f6d3c96fd5e/propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121", size = 268072, upload-time = "2025-02-20T19:02:29.594Z" }, - { url = "https://files.pythonhosted.org/packages/37/68/d94649e399e8d7fc051e5a4f2334efc567993525af083db145a70690a121/propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e", size = 275190, upload-time = "2025-02-20T19:02:32.255Z" }, - { url = "https://files.pythonhosted.org/packages/d8/3c/446e125f5bbbc1922964dd67cb541c01cdb678d811297b79a4ff6accc843/propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e", size = 254145, upload-time = "2025-02-20T19:02:33.932Z" }, - { url = "https://files.pythonhosted.org/packages/f4/80/fd3f741483dc8e59f7ba7e05eaa0f4e11677d7db2077522b92ff80117a2a/propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a", size = 257163, upload-time = "2025-02-20T19:02:35.675Z" }, - { url = "https://files.pythonhosted.org/packages/dc/cf/6292b5ce6ed0017e6a89024a827292122cc41b6259b30ada0c6732288513/propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac", size = 280249, upload-time = "2025-02-20T19:02:38.406Z" }, - { url = "https://files.pythonhosted.org/packages/e8/f0/fd9b8247b449fe02a4f96538b979997e229af516d7462b006392badc59a1/propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e", size = 288741, upload-time = "2025-02-20T19:02:40.149Z" }, - { url = "https://files.pythonhosted.org/packages/64/71/cf831fdc2617f86cfd7f414cfc487d018e722dac8acc098366ce9bba0941/propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf", size = 277061, upload-time = "2025-02-20T19:02:42.309Z" }, - { url = "https://files.pythonhosted.org/packages/42/78/9432542a35d944abeca9e02927a0de38cd7a298466d8ffa171536e2381c3/propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863", size = 42252, upload-time = "2025-02-20T19:02:44.447Z" }, - { url = "https://files.pythonhosted.org/packages/6f/45/960365f4f8978f48ebb56b1127adf33a49f2e69ecd46ac1f46d6cf78a79d/propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46", size = 46425, upload-time = "2025-02-20T19:02:48.071Z" }, - { url = "https://files.pythonhosted.org/packages/b5/35/6c4c6fc8774a9e3629cd750dc24a7a4fb090a25ccd5c3246d127b70f9e22/propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043", size = 12101, upload-time = "2025-02-20T19:03:27.202Z" }, +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, + { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, + { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, + { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, + { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, + { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, + { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, + { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, + { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, + { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, + { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, + { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, + { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, + { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, + { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, ] [[package]] @@ -1291,12 +1240,6 @@ crypto = [ { name = "cryptography" }, ] -[[package]] -name = "pymicro-vad" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/0f/a92acea368e2b37fbc706f6d049f04557497d981316a2f428b26f14666a9/pymicro_vad-1.0.1.tar.gz", hash = "sha256:60e0508b338b694c7ad71c633c0da6fcd2678a88abb8e948b80fa68934965111", size = 135575, upload-time = "2024-07-31T20:04:04.619Z" } - [[package]] name = "pyobjc-core" version = "12.0" @@ -1350,14 +1293,14 @@ wheels = [ [[package]] name = "pyopenssl" -version = "25.0.0" +version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/26/e25b4a374b4639e0c235527bbe31c0524f26eda701d79456a7e1877f4cc5/pyopenssl-25.0.0.tar.gz", hash = "sha256:cd2cef799efa3936bb08e8ccb9433a575722b9dd986023f1cabc4ae64e9dac16", size = 179573, upload-time = "2025-01-12T17:22:48.897Z" } +sdist = { url = "https://files.pythonhosted.org/packages/04/8c/cd89ad05804f8e3c17dea8f178c3f40eeab5694c30e0c9f5bcd49f576fc3/pyopenssl-25.1.0.tar.gz", hash = "sha256:8d031884482e0c67ee92bf9a4d8cceb08d92aba7136432ffb0703c5280fc205b", size = 179937, upload-time = "2025-05-17T16:28:31.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/d7/eb76863d2060dcbe7c7e6cccfd95ac02ea0b9acc37745a0d99ff6457aefb/pyOpenSSL-25.0.0-py3-none-any.whl", hash = "sha256:424c247065e46e76a37411b9ab1782541c23bb658bf003772c3405fbaa128e90", size = 56453, upload-time = "2025-01-12T17:22:43.44Z" }, + { url = "https://files.pythonhosted.org/packages/80/28/2659c02301b9500751f8d42f9a6632e1508aa5120de5e43042b8b30f8d5d/pyopenssl-25.1.0-py3-none-any.whl", hash = "sha256:2b11f239acc47ac2e5aca04fd7fa829800aeee22a2eb30d744572a157bd8a1ab", size = 56771, upload-time = "2025-05-17T16:28:29.197Z" }, ] [[package]] @@ -1375,12 +1318,6 @@ version = "0.1.6.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/08/64/a99f27d3b4347486c7bfc0aa516016c46dc4c0f380ffccbd742a61af1eda/PyRIC-0.1.6.3.tar.gz", hash = "sha256:b539b01cafebd2406c00097f94525ea0f8ecd1dd92f7731f43eac0ef16c2ccc9", size = 870401, upload-time = "2016-12-04T07:54:48.374Z" } -[[package]] -name = "pyspeex-noise" -version = "1.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/1d/7d2ebb8f73c2b2e929b4ba5370b35dbc91f37268ea53f4b6acd9afa532cb/pyspeex_noise-1.0.2.tar.gz", hash = "sha256:56a888ca2ef7fdea2316aa7fad3636d2fcf5f4450f3a0db58caa7c10a614b254", size = 49882, upload-time = "2024-08-27T17:00:34.859Z" } - [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1405,15 +1342,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051, upload-time = "2024-02-08T18:32:43.911Z" }, ] -[[package]] -name = "pyturbojpeg" -version = "1.7.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8b/ba/37c075c7cc86b89a22db4ac46c2e4f444666f9a43975a512b7cf70ced2fd/PyTurboJPEG-1.7.5.tar.gz", hash = "sha256:5dd5f40dbf4159f41b6abaa123733910e8b1182df562b6ddb768991868b487d3", size = 12065, upload-time = "2024-07-28T08:34:03.778Z" } - [[package]] name = "pytz" version = "2025.2" @@ -1440,9 +1368,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, ] +[[package]] +name = "regex" +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, +] + [[package]] name = "requests" -version = "2.32.3" +version = "2.32.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1450,9 +1401,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, ] [[package]] @@ -1505,6 +1456,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/e0/b93a18e9bb7f7d2573a9c6819d42d996851edde0b0406d017067d7d23a0a/securetar-2025.2.1-py3-none-any.whl", hash = "sha256:760ad9d93579d5923f3d0da86e0f185d0f844cf01795a8754539827bb6a1bab4", size = 11545, upload-time = "2025-02-25T14:17:50.832Z" }, ] +[[package]] +name = "sentence-stream" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/61/51918209769d7373c9bcaecac6222fb494b1d1f272e818e515e5129ef89c/sentence_stream-1.1.0.tar.gz", hash = "sha256:a512604a9f43d4132e29ad04664e8b1778f4a20265799ac86e8d62d181009483", size = 9262, upload-time = "2025-07-24T15:37:37.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/c8/8e39ad90b52372ed3bd1254450ef69f55f7920a838f906e29a414ffcf4b2/sentence_stream-1.1.0-py3-none-any.whl", hash = "sha256:3fceb47673ff16f5e301d7d0935db18413f8f1143ba4aea7ea2d9f808c5f1436", size = 7989, upload-time = "2025-07-24T15:37:36.606Z" }, +] + [[package]] name = "six" version = "1.17.0" @@ -1525,38 +1488,36 @@ wheels = [ [[package]] name = "snitun" -version = "0.40.0" +version = "0.44.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, - { name = "async-timeout" }, - { name = "attrs" }, { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9a/5d/c39d5dee7119017efa571e7ce09fcb4f098734cb367adab59bed497ae0e9/snitun-0.40.0.tar.gz", hash = "sha256:f5a70b3aab07524f196d27baf7a8f8774b3b00c442e91392539dd11dbd033c9c", size = 33111, upload-time = "2024-12-18T12:43:16.948Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/83/acef455bd45428b512148db8c67ffdbb5e3460ab4e036dd896de15db0e7b/snitun-0.44.0.tar.gz", hash = "sha256:b9f693568ea6a7da6a9fa459597a404c1657bfb9259eb076005a8eb1247df087", size = 41098, upload-time = "2025-07-22T21:42:19.373Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/07/9982bd349e7a1aef3f8077ccfcf7ee9b447bd70ccab8121ad786334a882a/snitun-0.40.0-py3-none-any.whl", hash = "sha256:dedb58d3042d13311142b55337ad6ce6ed339e43da9dca4c4c2c83df77c64ac0", size = 39122, upload-time = "2024-12-18T12:43:12.756Z" }, + { url = "https://files.pythonhosted.org/packages/c8/77/6b58e87ea1ced25cd90bb90e1def088485fae8e35771255943a4bd9c72ab/snitun-0.44.0-py3-none-any.whl", hash = "sha256:8c351ed936c9768d68b1dc5a33ad91c1b8d57cad09f29e73e0b19df0e573c08b", size = 48365, upload-time = "2025-07-22T21:42:18.013Z" }, ] [[package]] name = "sqlalchemy" -version = "2.0.39" +version = "2.0.41" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/8e/e77fcaa67f8b9f504b4764570191e291524575ddbfe78a90fc656d671fdc/sqlalchemy-2.0.39.tar.gz", hash = "sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22", size = 9644602, upload-time = "2025-03-11T18:27:09.744Z" } +sdist = { url = "https://files.pythonhosted.org/packages/63/66/45b165c595ec89aa7dcc2c1cd222ab269bc753f1fc7a1e68f8481bd957bf/sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9", size = 9689424, upload-time = "2025-05-14T17:10:32.339Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/47/55778362642344324a900b6b2b1b26f7f02225b374eb93adc4a363a2d8ae/sqlalchemy-2.0.39-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87", size = 2102484, upload-time = "2025-03-11T19:21:54.018Z" }, - { url = "https://files.pythonhosted.org/packages/1b/e1/f5f26f67d095f408138f0fb2c37f827f3d458f2ae51881546045e7e55566/sqlalchemy-2.0.39-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716", size = 2092955, upload-time = "2025-03-11T19:21:55.658Z" }, - { url = "https://files.pythonhosted.org/packages/c5/c2/0db0022fc729a54fc7aef90a3457bf20144a681baef82f7357832b44c566/sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4", size = 3179367, upload-time = "2025-03-11T19:09:31.059Z" }, - { url = "https://files.pythonhosted.org/packages/33/b7/f33743d87d0b4e7a1f12e1631a4b9a29a8d0d7c0ff9b8c896d0bf897fb60/sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6b0a1c7ed54a5361aaebb910c1fa864bae34273662bb4ff788a527eafd6e14d", size = 3192705, upload-time = "2025-03-11T19:32:50.795Z" }, - { url = "https://files.pythonhosted.org/packages/c9/74/6814f31719109c973ddccc87bdfc2c2a9bc013bec64a375599dc5269a310/sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e", size = 3125927, upload-time = "2025-03-11T19:09:32.678Z" }, - { url = "https://files.pythonhosted.org/packages/e8/6b/18f476f4baaa9a0e2fbc6808d8f958a5268b637c8eccff497bf96908d528/sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c08a972cbac2a14810463aec3a47ff218bb00c1a607e6689b531a7c589c50723", size = 3154055, upload-time = "2025-03-11T19:32:53.344Z" }, - { url = "https://files.pythonhosted.org/packages/b4/60/76714cecb528da46bc53a0dd36d1ccef2f74ef25448b630a0a760ad07bdb/sqlalchemy-2.0.39-cp313-cp313-win32.whl", hash = "sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7", size = 2075315, upload-time = "2025-03-11T18:43:16.946Z" }, - { url = "https://files.pythonhosted.org/packages/5b/7c/76828886d913700548bac5851eefa5b2c0251ebc37921fe476b93ce81b50/sqlalchemy-2.0.39-cp313-cp313-win_amd64.whl", hash = "sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0", size = 2099175, upload-time = "2025-03-11T18:43:18.141Z" }, - { url = "https://files.pythonhosted.org/packages/7b/0f/d69904cb7d17e65c65713303a244ec91fd3c96677baf1d6331457fd47e16/sqlalchemy-2.0.39-py3-none-any.whl", hash = "sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f", size = 1898621, upload-time = "2025-03-11T19:20:33.027Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ad/2e1c6d4f235a97eeef52d0200d8ddda16f6c4dd70ae5ad88c46963440480/sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443", size = 2115491, upload-time = "2025-05-14T17:55:31.177Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8d/be490e5db8400dacc89056f78a52d44b04fbf75e8439569d5b879623a53b/sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc", size = 2102827, upload-time = "2025-05-14T17:55:34.921Z" }, + { url = "https://files.pythonhosted.org/packages/a0/72/c97ad430f0b0e78efaf2791342e13ffeafcbb3c06242f01a3bb8fe44f65d/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1", size = 3225224, upload-time = "2025-05-14T17:50:41.418Z" }, + { url = "https://files.pythonhosted.org/packages/5e/51/5ba9ea3246ea068630acf35a6ba0d181e99f1af1afd17e159eac7e8bc2b8/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a", size = 3230045, upload-time = "2025-05-14T17:51:54.722Z" }, + { url = "https://files.pythonhosted.org/packages/78/2f/8c14443b2acea700c62f9b4a8bad9e49fc1b65cfb260edead71fd38e9f19/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d", size = 3159357, upload-time = "2025-05-14T17:50:43.483Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b2/43eacbf6ccc5276d76cea18cb7c3d73e294d6fb21f9ff8b4eef9b42bbfd5/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23", size = 3197511, upload-time = "2025-05-14T17:51:57.308Z" }, + { url = "https://files.pythonhosted.org/packages/fa/2e/677c17c5d6a004c3c45334ab1dbe7b7deb834430b282b8a0f75ae220c8eb/sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f", size = 2082420, upload-time = "2025-05-14T17:55:52.69Z" }, + { url = "https://files.pythonhosted.org/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df", size = 2108329, upload-time = "2025-05-14T17:55:54.495Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fc/9ba22f01b5cdacc8f5ed0d22304718d2c758fce3fd49a5372b886a86f37c/sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576", size = 1911224, upload-time = "2025-05-14T17:39:42.154Z" }, ] [[package]] @@ -1635,22 +1596,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/1d/c43d3e1bda52a321f6cde3526b3634602958dc8ccf1f20fd6616767fd1a1/ulid_transform-1.4.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:9b1429ca7403696b290e4e97ffadbf8ed0b7470a97ad7e273372c3deae5bfb2f", size = 51566, upload-time = "2025-03-07T10:44:00.79Z" }, ] -[[package]] -name = "unicode-rbnf" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/1f/d952ba97832647e608700c36b22d1c4476016076c9ed1ce74ae814bea55a/unicode_rbnf-2.4.0.tar.gz", hash = "sha256:6d2f12a7581c69ea6218ee61fafcd2da46e1f9986bdcd0964c5151f7c2a938ac", size = 89069, upload-time = "2025-10-07T20:59:41.3Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/21/82f5d435808cba330668a8b69efb180e3ef9739d4998e8cd0381e8c9cb23/unicode_rbnf-2.4.0-py3-none-any.whl", hash = "sha256:0176b30ac9b7b84008d7dc0f23078055dc10d2671fdadfab5747943243e20e2d", size = 141691, upload-time = "2025-10-07T20:59:40.139Z" }, -] - [[package]] name = "urllib3" -version = "1.26.20" +version = "2.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380, upload-time = "2024-08-29T15:43:11.37Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225, upload-time = "2024-08-29T15:43:08.921Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] [[package]] @@ -1664,27 +1616,28 @@ wheels = [ [[package]] name = "uv" -version = "0.6.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/32/ffa984c2ecbcf48d0ae813adf1aad79b3ecb5ffc743362088755d64ae3be/uv-0.6.10.tar.gz", hash = "sha256:cbbb03deb30af457cd93ad299ee5c3258ade3d900b4dee1af936c8a6d87d5bcb", size = 3109190, upload-time = "2025-03-26T01:08:35.208Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/5a/5ef9324c333478608eaca8c97a374a869b861a9a614c1e6695045e06d90c/uv-0.6.10-py3-none-linux_armv6l.whl", hash = "sha256:06932d36f1afaf611522a6a7ec361dac48dc67a1147d24e9eadee9703b15faaf", size = 15825875, upload-time = "2025-03-26T01:07:49.96Z" }, - { url = "https://files.pythonhosted.org/packages/f7/2f/001f6bb4342ba50cf921bd4a338ea40e5228ea6a817bd3101fbabaf010dd/uv-0.6.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e5c2ba1922c47a245d7393465fcee942df5a8bd8b80489a7b8860ba9d60102f9", size = 15967139, upload-time = "2025-03-26T01:07:53.521Z" }, - { url = "https://files.pythonhosted.org/packages/36/6b/f66dcd28508bceed7cff48efb9dfe62a50a40a0685c41fb5e6ecd45f33cd/uv-0.6.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd8a4bcfd33a0dcae3fc0936bff8602f74e5719cf839e3df233059a0b8c8330d", size = 14796758, upload-time = "2025-03-26T01:07:56.269Z" }, - { url = "https://files.pythonhosted.org/packages/5a/a2/13eb03e8691b098f9ee63c4d3fa3a054c48bfa05a0a52aec3df33ab52376/uv-0.6.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:4dd20c47898c15ebd4b5f48101062ea248e32513bfc61fc04bc822abfe39ce8a", size = 15252527, upload-time = "2025-03-26T01:07:58.728Z" }, - { url = "https://files.pythonhosted.org/packages/58/90/053bde333fbf9030dff1354797bd74ce3624235bcf59d7558397749a88c1/uv-0.6.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:950c9cd7b75f67e25760d2f43ad4b0ee3f8c6724fe0a9cf9eff948b3044b6a6d", size = 15560957, upload-time = "2025-03-26T01:08:01.188Z" }, - { url = "https://files.pythonhosted.org/packages/34/80/feb9ecc8ab8f9e1968d6783dd47e7ebd1dfcd0231c8b7b0efd7204625cec/uv-0.6.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acca1dca7be342b2b8e26e509aa07c3144cb009788140eee045da2aad6a0c6fe", size = 16249302, upload-time = "2025-03-26T01:08:03.734Z" }, - { url = "https://files.pythonhosted.org/packages/0f/14/9a2e40e25fba7b550cb57cce62a07ddf28350cb53e9e8bd2e70c0fbacdbb/uv-0.6.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:13ac09945976dc0df0edde7e4ba3a46107036a114117c8ff84916e55216c2e32", size = 17196146, upload-time = "2025-03-26T01:08:06.129Z" }, - { url = "https://files.pythonhosted.org/packages/5e/05/5c9cd846243aca204f96c2da13da0fb38b6143eb3827dedea0e1dc1bcf1c/uv-0.6.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:145e75b99d6b7bdce8e454a851cfcd5605ff0491d568244c66fa75ca6b071bd6", size = 16944298, upload-time = "2025-03-26T01:08:08.827Z" }, - { url = "https://files.pythonhosted.org/packages/d2/14/63233a3143535a6df34ee6dc8246ef09ee79d99b902a6cc1ee179c1898f9/uv-0.6.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666d9fe312c810bba77633dbd463dc85f5a6a0d07905726a014dc53d07c774d9", size = 21226376, upload-time = "2025-03-26T01:08:11.488Z" }, - { url = "https://files.pythonhosted.org/packages/0a/d3/7e881e2a391203a7567cf03c72213701e63923591d2072c4e7fe694c919f/uv-0.6.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b98e8884093cbfb1a1cc3f855aa22f97ec8da1a87e0e761800e165d4f9224a45", size = 16621313, upload-time = "2025-03-26T01:08:14.435Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a9/124aa76690a04cf30344386358b772cdede17d84660ae1dce8643bf64939/uv-0.6.10-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:e8a8a75cf34c0814c1eabdbe651741d44fb125a6dcbe159b2da02871bbfdec7e", size = 15461518, upload-time = "2025-03-26T01:08:17.002Z" }, - { url = "https://files.pythonhosted.org/packages/ef/97/19813f2ec2faac77da5548c35d6ae039d044b973ecbb0732e3f07662fd36/uv-0.6.10-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:5260f52386e217615553f2f42740ce2f64ba439ff0fd502dc5b06250eb8ae613", size = 15524130, upload-time = "2025-03-26T01:08:19.392Z" }, - { url = "https://files.pythonhosted.org/packages/09/3f/5637bbf27ac145a09ea8eba8e0c926f7a3fe8fc4b3b1c91131c4558f4ec2/uv-0.6.10-py3-none-musllinux_1_1_i686.whl", hash = "sha256:603aebbaf6be938120c73fd36e9fd85f5e1b671d3d4638b3086f478e2bb423d9", size = 15901256, upload-time = "2025-03-26T01:08:22.141Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9b/2c688a897efad60d6e0587027968c1fdb0a63f70a8bef33d0b8154cc0fcd/uv-0.6.10-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d1f1bc7d94a4a7fdd75142be71b6bf2d7e01282f322721da185d711f065d7b80", size = 16746279, upload-time = "2025-03-26T01:08:24.916Z" }, - { url = "https://files.pythonhosted.org/packages/75/d4/df57d3f40c93c21fceed94156da41183daabd15422506e0fe73236c458a1/uv-0.6.10-py3-none-win32.whl", hash = "sha256:df6560256b93441c70ea2c062975bce2307a32de280f103cedb8db4a0f542348", size = 15953827, upload-time = "2025-03-26T01:08:27.395Z" }, - { url = "https://files.pythonhosted.org/packages/8a/21/a71c95c85624544c56695ae2469745bbda834e77dfc1e29d76711409eda5/uv-0.6.10-py3-none-win_amd64.whl", hash = "sha256:d795721fdd32e0471c952b7cb02a030657b6e67625fe836f4df14a3ae4aa4921", size = 17425178, upload-time = "2025-03-26T01:08:29.898Z" }, - { url = "https://files.pythonhosted.org/packages/ce/07/e6ffe467e1e365f7dd7863c4d505b1941af8cf69c494d0dbda08ba907043/uv-0.6.10-py3-none-win_arm64.whl", hash = "sha256:5188dc7041f4166bf64182d76c32c873f750259b6e4621a1400c26ebeea8c8dd", size = 16169219, upload-time = "2025-03-26T01:08:32.812Z" }, +version = "0.8.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/a1/4dea87c10875b441d906f82df42d725a4a04c2e8ae720d9fa01e1f75e3dc/uv-0.8.9.tar.gz", hash = "sha256:54d76faf5338d1e5643a32b048c600de0cdaa7084e5909106103df04f3306615", size = 3478291, upload-time = "2025-08-12T02:32:37.187Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/d8/a2a24d30660b5f05f86699f86b642b1193bea1017e77e5e5d3e1c64f7bcc/uv-0.8.9-py3-none-linux_armv6l.whl", hash = "sha256:4633c693c79c57a77c52608cbca8a6bb17801bfa223326fbc5c5142654c23cc3", size = 18477020, upload-time = "2025-08-12T02:31:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/4d/21/937e590fb08ce4c82503fddb08b54613c0d42dd06c660460f8f0552dd3a7/uv-0.8.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1cdc11cbc81824e51ebb1bac35745a79048557e869ef9da458e99f1c3a96c7f9", size = 18486975, upload-time = "2025-08-12T02:31:54.804Z" }, + { url = "https://files.pythonhosted.org/packages/60/a8/e6fc3e204731aa26b09934bbdecc8d6baa58a2d9e55b59b13130bacf8e52/uv-0.8.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7b20ee83e3bf294e0b1347d0b27c56ea1a4fa7eeff4361fbf1f39587d4273059", size = 17178749, upload-time = "2025-08-12T02:31:57.251Z" }, + { url = "https://files.pythonhosted.org/packages/b2/3e/3104a054bb6e866503a13114ee969d4b66227ebab19a38e3468f36c03a87/uv-0.8.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:3418315e624f60a1c4ed37987b35d5ff0d03961d380e7e7946a3378499d5d779", size = 17790897, upload-time = "2025-08-12T02:31:59.451Z" }, + { url = "https://files.pythonhosted.org/packages/50/e6/ab64cca644f40bf85fb9b3a9050aad25af7882a1d774a384fc473ef9c697/uv-0.8.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7efe01b3ed9816e07e6cd4e088472a558a1d2946177f31002b4c42cd55cb4604", size = 18124831, upload-time = "2025-08-12T02:32:02.151Z" }, + { url = "https://files.pythonhosted.org/packages/08/d1/68a001e3ad5d0601ea9ff348b54a78c8ba87fd2a6b6b5e27b379f6f3dff0/uv-0.8.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e571132495d7ab24d2f0270c559d6facd4224745d9db7dff8c20ec0c71ae105a", size = 18924774, upload-time = "2025-08-12T02:32:04.479Z" }, + { url = "https://files.pythonhosted.org/packages/ed/71/1b252e523eb875aa4ac8d06d5f8df175fa2d29e13da347d5d4823bce6c47/uv-0.8.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:67507c66837d8465daaad9f2ccd7da7af981d8c94eb8e32798f62a98c28de82d", size = 20256335, upload-time = "2025-08-12T02:32:07.12Z" }, + { url = "https://files.pythonhosted.org/packages/30/fc/062a25088b30a0fd27e4cc46baa272dd816acdec252b120d05a16d63170a/uv-0.8.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3162f495805a26fba5aacbee49c8650e1e74313c7a2e6df6aec5de9d1299087", size = 19920018, upload-time = "2025-08-12T02:32:10.041Z" }, + { url = "https://files.pythonhosted.org/packages/d8/55/90a0dc35938e68509ff8e8a49ff45b0fd13f3a44752e37d8967cd9d19316/uv-0.8.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60eb70afeb1c66180e12a15afd706bcc0968dbefccf7ef6e5d27a1aaa765419b", size = 19235553, upload-time = "2025-08-12T02:32:12.361Z" }, + { url = "https://files.pythonhosted.org/packages/ae/a4/2db5939a3a993a06bca0a42e2120b4385bf1a4ff54242780701759252052/uv-0.8.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011d2b2d4781555f7f7d29d2f0d6b2638fc60eeff479406ed570052664589e6a", size = 19259174, upload-time = "2025-08-12T02:32:14.697Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c9/c52249b5f40f8eb2157587ae4b997942335e4df312dfb83b16b5ebdecc61/uv-0.8.9-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:97621843e087a68c0b4969676367d757e1de43c00a9f554eb7da35641bdff8a2", size = 18048069, upload-time = "2025-08-12T02:32:16.955Z" }, + { url = "https://files.pythonhosted.org/packages/d0/ca/524137719fb09477e57c5983fa8864f824f5858b29fc679c0416634b79f0/uv-0.8.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b1be6a7b49d23b75d598691cc5c065a9e3cdf5e6e75d7b7f42f24d758ceef3c4", size = 18943440, upload-time = "2025-08-12T02:32:19.212Z" }, + { url = "https://files.pythonhosted.org/packages/f0/b8/877bf9a52207023a8bf9b762bed3853697ed71c5c9911a4e31231de49a23/uv-0.8.9-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:91598361309c3601382c552dc22256f70b2491ad03357b66caa4be6fdf1111dd", size = 18075581, upload-time = "2025-08-12T02:32:21.732Z" }, + { url = "https://files.pythonhosted.org/packages/96/de/272d4111ff71765bcbfd3ecb4d4fff4073f08cc38b3ecdb7272518c3fe93/uv-0.8.9-py3-none-musllinux_1_1_i686.whl", hash = "sha256:dc81df9dd7571756e34255592caab92821652face35c3f52ad05efaa4bcc39d3", size = 18420275, upload-time = "2025-08-12T02:32:24.488Z" }, + { url = "https://files.pythonhosted.org/packages/90/15/fecfc6665d1bfc5c7dbd32ff1d63413ac43d7f6d16d76fdc4d2513cbe807/uv-0.8.9-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:9ef728e0a5caa2bb129c009a68b30819552e7addf934916a466116e302748bed", size = 19354288, upload-time = "2025-08-12T02:32:27.714Z" }, + { url = "https://files.pythonhosted.org/packages/52/b5/9fef88ac0cc3ca71ff718fa7d7e90c1b3a8639b041c674825aae00d24bf5/uv-0.8.9-py3-none-win32.whl", hash = "sha256:a347c2f2630a45a3b7ceae28a78a528137edfec4847bb29da1561bd8d1f7d254", size = 18197270, upload-time = "2025-08-12T02:32:30.288Z" }, + { url = "https://files.pythonhosted.org/packages/04/0a/dacd483c9726d2b74e42ee1f186aabab508222114f3099a7610ad0f78004/uv-0.8.9-py3-none-win_amd64.whl", hash = "sha256:dc12048cdb53210d0c7218bb403ad30118b1fe8eeff3fbcc184c13c26fcc47d4", size = 20221458, upload-time = "2025-08-12T02:32:32.706Z" }, + { url = "https://files.pythonhosted.org/packages/ac/7e/f2b35278304673dcf9e8fe84b6d15531d91c59530dcf7919111f39a8d28f/uv-0.8.9-py3-none-win_arm64.whl", hash = "sha256:53332de28e9ee00effb695a15cdc70b2455d6b5f6b596d556076b5dd1fd3aa26", size = 18805689, upload-time = "2025-08-12T02:32:35.036Z" }, ] [[package]] @@ -1698,26 +1651,26 @@ wheels = [ [[package]] name = "voluptuous-openapi" -version = "0.0.6" +version = "0.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "voluptuous" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1f/6f/1075651d387c1570e4603080bdf0aa15aa254c21efb2688fdb18544cf4b9/voluptuous_openapi-0.0.6.tar.gz", hash = "sha256:4078c2acef23e04ceeab1ba58252590fcdc3ba6e3ed34521e8595374ab4de884", size = 13190, upload-time = "2025-01-07T07:19:07.266Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/20/ed87b130ae62076b731521b3c4bc502e6ba8cc92def09954e4e755934804/voluptuous_openapi-0.1.0.tar.gz", hash = "sha256:84bc44107c472ba8782f7a4cb342d19d155d5fe7f92367f092cd96cc850ff1b7", size = 14656, upload-time = "2025-05-11T21:10:14.876Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5c/331c21122901d4f5f4f6869683ab9859a08498074cee6075ff3eac3027a6/voluptuous_openapi-0.0.6-py3-none-any.whl", hash = "sha256:3561bbe5f46483f4cd9f631a0bd4a3ac3d7d74bab24f41bcd09b52501f712d5e", size = 9249, upload-time = "2025-01-07T07:19:05.948Z" }, + { url = "https://files.pythonhosted.org/packages/68/3b/9e689d9fc68f0032bf5b7cbf767fc8bd4771d75cddaf01267fcc05490061/voluptuous_openapi-0.1.0-py3-none-any.whl", hash = "sha256:c3aac740286d368c90a99e007d55ddca7fcddf790d218c60ee0eeec2fcd3db2b", size = 9967, upload-time = "2025-05-11T21:10:13.647Z" }, ] [[package]] name = "voluptuous-serialize" -version = "2.6.0" +version = "2.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "voluptuous" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/09/c26b38ab35d9f61e9bf5c3e805215db1316dd73c77569b47ab36a40d19b1/voluptuous-serialize-2.6.0.tar.gz", hash = "sha256:79acdc58239582a393144402d827fa8efd6df0f5350cdc606d9242f6f9bca7c4", size = 7562, upload-time = "2023-02-15T21:09:08.077Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/70/03a9b61324e1bb8b16682455b8b953bccd1001a28e43478c86f539e26285/voluptuous_serialize-2.7.0.tar.gz", hash = "sha256:d0da959f2fd93c8f1eb779c5d116231940493b51020c2c1026bab76eb56cd09e", size = 9202, upload-time = "2025-08-17T10:43:04.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/86/355e1c65934760e2fb037219f1f360562567cf6731d281440c1d57d36856/voluptuous_serialize-2.6.0-py3-none-any.whl", hash = "sha256:85a5c8d4d829cb49186c1b5396a8a517413cc5938e1bb0e374350190cd139616", size = 6819, upload-time = "2023-02-15T21:09:06.512Z" }, + { url = "https://files.pythonhosted.org/packages/f7/41/d536d9cf39821c35cc13aff403728e60e32b2fd711c240b6b9980af1c03f/voluptuous_serialize-2.7.0-py3-none-any.whl", hash = "sha256:ee3ebecace6136f38d0bf8c20ee97155db2486c6b2d0795563fafd04a519e76f", size = 7850, upload-time = "2025-08-17T10:43:03.498Z" }, ] [[package]] @@ -1847,54 +1800,72 @@ wheels = [ [[package]] name = "yarl" -version = "1.18.3" +version = "1.20.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062, upload-time = "2024-12-01T20:35:23.292Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/c7/c790513d5328a8390be8f47be5d52e141f78b66c6c48f48d241ca6bd5265/yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", size = 140789, upload-time = "2024-12-01T20:34:11.414Z" }, - { url = "https://files.pythonhosted.org/packages/30/aa/a2f84e93554a578463e2edaaf2300faa61c8701f0898725842c704ba5444/yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", size = 94144, upload-time = "2024-12-01T20:34:13.485Z" }, - { url = "https://files.pythonhosted.org/packages/c6/fc/d68d8f83714b221a85ce7866832cba36d7c04a68fa6a960b908c2c84f325/yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", size = 91974, upload-time = "2024-12-01T20:34:15.234Z" }, - { url = "https://files.pythonhosted.org/packages/56/4e/d2563d8323a7e9a414b5b25341b3942af5902a2263d36d20fb17c40411e2/yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", size = 333587, upload-time = "2024-12-01T20:34:17.358Z" }, - { url = "https://files.pythonhosted.org/packages/25/c9/cfec0bc0cac8d054be223e9f2c7909d3e8442a856af9dbce7e3442a8ec8d/yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", size = 344386, upload-time = "2024-12-01T20:34:19.842Z" }, - { url = "https://files.pythonhosted.org/packages/ab/5d/4c532190113b25f1364d25f4c319322e86232d69175b91f27e3ebc2caf9a/yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", size = 345421, upload-time = "2024-12-01T20:34:21.975Z" }, - { url = "https://files.pythonhosted.org/packages/23/d1/6cdd1632da013aa6ba18cee4d750d953104a5e7aac44e249d9410a972bf5/yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", size = 339384, upload-time = "2024-12-01T20:34:24.717Z" }, - { url = "https://files.pythonhosted.org/packages/9a/c4/6b3c39bec352e441bd30f432cda6ba51681ab19bb8abe023f0d19777aad1/yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", size = 326689, upload-time = "2024-12-01T20:34:26.886Z" }, - { url = "https://files.pythonhosted.org/packages/23/30/07fb088f2eefdc0aa4fc1af4e3ca4eb1a3aadd1ce7d866d74c0f124e6a85/yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", size = 345453, upload-time = "2024-12-01T20:34:29.605Z" }, - { url = "https://files.pythonhosted.org/packages/63/09/d54befb48f9cd8eec43797f624ec37783a0266855f4930a91e3d5c7717f8/yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", size = 341872, upload-time = "2024-12-01T20:34:31.454Z" }, - { url = "https://files.pythonhosted.org/packages/91/26/fd0ef9bf29dd906a84b59f0cd1281e65b0c3e08c6aa94b57f7d11f593518/yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", size = 347497, upload-time = "2024-12-01T20:34:34.004Z" }, - { url = "https://files.pythonhosted.org/packages/d9/b5/14ac7a256d0511b2ac168d50d4b7d744aea1c1aa20c79f620d1059aab8b2/yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", size = 359981, upload-time = "2024-12-01T20:34:36.624Z" }, - { url = "https://files.pythonhosted.org/packages/ca/b3/d493221ad5cbd18bc07e642894030437e405e1413c4236dd5db6e46bcec9/yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", size = 366229, upload-time = "2024-12-01T20:34:38.657Z" }, - { url = "https://files.pythonhosted.org/packages/04/56/6a3e2a5d9152c56c346df9b8fb8edd2c8888b1e03f96324d457e5cf06d34/yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", size = 360383, upload-time = "2024-12-01T20:34:40.501Z" }, - { url = "https://files.pythonhosted.org/packages/fd/b7/4b3c7c7913a278d445cc6284e59b2e62fa25e72758f888b7a7a39eb8423f/yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", size = 310152, upload-time = "2024-12-01T20:34:42.814Z" }, - { url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", size = 315723, upload-time = "2024-12-01T20:34:44.699Z" }, - { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109, upload-time = "2024-12-01T20:35:20.834Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, + { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, + { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, + { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, + { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, + { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, + { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, + { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, + { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, + { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, + { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, + { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, + { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, + { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, + { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, + { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, + { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, + { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, + { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, + { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, + { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, + { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, + { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, + { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, ] [[package]] name = "zeroconf" -version = "0.146.0" +version = "0.147.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ifaddr" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/ac/d4c67df0649c77f343e4976ef0a00e19a6e5c3342a6eaa6e64d7b853224f/zeroconf-0.146.0.tar.gz", hash = "sha256:a48010a1931acdba5b26e99326464788daeef96dcb7b9a44d1832352f76da49c", size = 161804, upload-time = "2025-03-05T01:47:18.095Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/eb/25e258fbd064e7b8f1497b9e345f29d6e44dd250a0fc5afd91aa04aafa57/zeroconf-0.146.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:faec552163f3007247ef9713fc817627d89844a782da8c1479b11ea3d3370684", size = 1840888, upload-time = "2025-03-05T02:20:56.799Z" }, - { url = "https://files.pythonhosted.org/packages/7b/1c/1fd373e225e7282c244003683740ca58bc39270cb79fa13b13435c6dc88a/zeroconf-0.146.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0fc7b22e33b9d5d81b5aee58af6447fc1cf9b11e04dc2a04e1a5d00b3ae4d23a", size = 1697122, upload-time = "2025-03-05T02:20:58.687Z" }, - { url = "https://files.pythonhosted.org/packages/bf/98/2a42f1f88f69b11db2524469e5dc6752dc819e4fe9b985e293be74b38dee/zeroconf-0.146.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6e24daeeb926f8c7d426c46082224786e26aa5b4ce9fb573133e52ff8bae81", size = 2143632, upload-time = "2025-03-05T02:21:00.927Z" }, - { url = "https://files.pythonhosted.org/packages/81/8c/6caf3a48575c2bcf7ba2739b2cda6f117a305c03e87b53d08f19c859fae3/zeroconf-0.146.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:9a798ea22c24a4148364f85b46ab33541072715bf8abccae2e3fd0c069f5808f", size = 2315076, upload-time = "2025-03-05T02:21:02.419Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b3/b86fa34f8d682b1bd3e144896b2c2cfb8a6c3308c1f773a7dcdb733d677b/zeroconf-0.146.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97a536e5b3d694e342bc908149342db2aae08a6f56466db63b6dffc26d2399ae", size = 2260655, upload-time = "2025-03-05T02:21:04.68Z" }, - { url = "https://files.pythonhosted.org/packages/06/2a/9b509a9d70c9f98b1b60f8d0002ac457df8f401325be6545ecb1f8071e8a/zeroconf-0.146.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f97a09c01424e2356c41b39f7c2fb7a743623c2d413a082e861030e28090aebb", size = 2097673, upload-time = "2025-03-05T02:21:06.287Z" }, - { url = "https://files.pythonhosted.org/packages/90/70/2fb1c0470fb4a230d9cd63e245b5d4bd349a19454d363499eb4cdee3b54a/zeroconf-0.146.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:55c2a0087847d5c8bc00cc1e85cb1d048e8b70b09b4e949a2b763f33389819bb", size = 2307311, upload-time = "2025-03-05T01:47:15.987Z" }, - { url = "https://files.pythonhosted.org/packages/64/c3/351b7c1d07c9bf43d75bbbf18f9d07f8081373e85865b5faa78b661ae882/zeroconf-0.146.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b87d01dc8d7d10b929cc63330cf2e0f726f105a57e8d86df5d946b93a0e6280f", size = 2297954, upload-time = "2025-03-05T02:21:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b17dda38b9c5b916b1491acb6f32044d198c89ee74074dec0a277f0d8f49/zeroconf-0.146.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f844214eed7b66c1db3ea4ab2dddf0d84b91c340d83b2721656f70efb8588ae4", size = 2152669, upload-time = "2025-03-05T02:21:09.702Z" }, - { url = "https://files.pythonhosted.org/packages/75/6c/ef97dcd5abdcfb6c4ea8a52d2cb08982541c43a9ec64dff1335ecc45a901/zeroconf-0.146.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cf9e85463a4fdeed8c5ea3b13e4a6c6de924d90b8b0982021e7331632f80192e", size = 2495779, upload-time = "2025-03-05T02:21:11.629Z" }, - { url = "https://files.pythonhosted.org/packages/90/f5/755bd701c69da699b6f0bd939972cd0978af6a7399174048a337de610f87/zeroconf-0.146.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fc1dd03301d370c21a8c5fbbe0a6a54a068a08384fa673d596c3f2424153aeca", size = 2459359, upload-time = "2025-03-05T02:21:13.346Z" }, - { url = "https://files.pythonhosted.org/packages/0c/24/12f936d8ec82e3ca14291e3c6f45f2a2b3d1139f5ae19670fd4624a66f86/zeroconf-0.146.0-cp313-cp313-win32.whl", hash = "sha256:b4e70e77a67b3f39e91b5c02df82ab49a54bfc4edb1aa5779e404a711938c5af", size = 1427510, upload-time = "2025-03-05T02:21:16.184Z" }, - { url = "https://files.pythonhosted.org/packages/49/bb/9ccf706c4f3dad7b72956d5123e2b228d0411a6f977f4db410ff6b8963c0/zeroconf-0.146.0-cp313-cp313-win_amd64.whl", hash = "sha256:5274ba298d2edd5d02bb3937181a1e82deef773075b04374eac149bd40fccd96", size = 1655847, upload-time = "2025-03-05T02:21:18.359Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/e2/78/f681afade2a4e7a9ade696cf3d3dcd9905e28720d74c16cafb83b5dd5c0a/zeroconf-0.147.0.tar.gz", hash = "sha256:f517375de6bf2041df826130da41dc7a3e8772176d3076a5da58854c7d2e8d7a", size = 163958, upload-time = "2025-05-03T16:24:54.207Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/83/c6ee14c962b79f616f8f987a52244e877647db3846007fc167f481a81b7d/zeroconf-0.147.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1deedbedea7402754b3a1a05a2a1c881443451ccd600b2a7f979e97dd9fcbe6d", size = 1841229, upload-time = "2025-05-03T16:59:17.783Z" }, + { url = "https://files.pythonhosted.org/packages/91/c0/42c08a8b2c5b6052d48a5517a5d05076b8ee2c0a458ea9bd5e0e2be38c01/zeroconf-0.147.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5c57d551e65a2a9b6333b685e3b074601f6e85762e4b4a490c663f1f2e215b24", size = 1697806, upload-time = "2025-05-03T16:59:20.083Z" }, + { url = "https://files.pythonhosted.org/packages/bf/79/d9b440786d62626f2ca4bd692b6c2bbd1e70e1124c56321bac6a2212a5eb/zeroconf-0.147.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:095bdb0cd369355ff919e3be930991b38557baaa8292d82f4a4a8567a3944f05", size = 2141482, upload-time = "2025-05-03T16:59:22.067Z" }, + { url = "https://files.pythonhosted.org/packages/48/12/ab7d31620892a7f4d446a3f0261ddb1198318348c039b4a5ec7d9d09579c/zeroconf-0.147.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:8ae0fe0bb947b3a128af586c76a16b5a7d027daa65e67637b042c745f9b136c4", size = 2315614, upload-time = "2025-05-03T16:59:24.091Z" }, + { url = "https://files.pythonhosted.org/packages/7b/48/2de072ee42e36328e1d80408b70eddf3df0a5b9640db188caa363b3e120f/zeroconf-0.147.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cbeea4d8d0c4f6eb5a82099d53f5729b628685039a44c1a84422080f8ec5b0d", size = 2259809, upload-time = "2025-05-03T16:59:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/02/ec/3344b1ed4e60b36dd73cb66c36299c83a356e853e728c68314061498e9cd/zeroconf-0.147.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:728f82417800c5c5dd3298f65cf7a8fef1707123b457d3832dbdf17d38f68840", size = 2096364, upload-time = "2025-05-03T16:59:27.786Z" }, + { url = "https://files.pythonhosted.org/packages/cd/30/5f34363e2d3c25a78fc925edcc5d45d332296a756d698ccfc060bba8a7aa/zeroconf-0.147.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:a2dc9ae96cd49b50d651a78204aafe9f41e907122dc98e719be5376b4dddec6f", size = 2307868, upload-time = "2025-05-03T16:24:52.178Z" }, + { url = "https://files.pythonhosted.org/packages/1b/a8/9b4242ae78bd271520e019faf47d8a2b36242b3b1a7fd47ee7510d380734/zeroconf-0.147.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9570ab3203cc4bd3ad023737ef4339558cdf1f33a5d45d76ed3fe77e5fa5f57", size = 2295063, upload-time = "2025-05-03T16:59:29.695Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e6/b63e4e09d71e94bfe0d30c6fc80b0e67e3845eb630bcfb056626db070776/zeroconf-0.147.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:fd783d9bac258e79d07e2bd164c1962b8f248579392b5078fd607e7bb6760b53", size = 2152284, upload-time = "2025-05-03T16:59:31.598Z" }, + { url = "https://files.pythonhosted.org/packages/72/12/42b990cb7ad997eb9f9fff15c61abff022adc44f5d1e96bd712ed6cd85ab/zeroconf-0.147.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b4acc76063cc379774db407dce0263616518bb5135057eb5eeafc447b3c05a81", size = 2498559, upload-time = "2025-05-03T16:59:33.444Z" }, + { url = "https://files.pythonhosted.org/packages/99/f9/080619bfcfc353deeb8cf7e813eaf73e8e28ff9a8ca7b97b9f0ecbf4d1d6/zeroconf-0.147.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:acc5334cb6cb98db3917bf9a3d6b6b7fdd205f8a74fd6f4b885abb4f61098857", size = 2456548, upload-time = "2025-05-03T16:59:35.721Z" }, + { url = "https://files.pythonhosted.org/packages/35/b6/a25b703f418200edd6932d56bbd32cbd087b828579cf223348fa778fb1ff/zeroconf-0.147.0-cp313-cp313-win32.whl", hash = "sha256:7c52c523aa756e67bf18d46db298a5964291f7d868b4a970163432e7d745b992", size = 1427188, upload-time = "2025-05-03T16:59:38.756Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e1/ba463435cdb0b38088eae56d508ec6128b9012f58cedab145b1b77e51316/zeroconf-0.147.0-cp313-cp313-win_amd64.whl", hash = "sha256:60f623af0e45fba69f5fe80d7b300c913afe7928fb43f4b9757f0f76f80f0d82", size = 1655531, upload-time = "2025-05-03T16:59:40.65Z" }, ] From 661c7e6787179c1aba0c630d362b8796392bd3cd Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 31 Oct 2025 11:18:56 +0000 Subject: [PATCH 219/235] lint fixes --- custom_components/battery_notes/__init__.py | 2 +- .../battery_notes/binary_sensor.py | 8 ++++---- custom_components/battery_notes/config_flow.py | 6 +++--- custom_components/battery_notes/coordinator.py | 4 ++-- .../battery_notes/library_updater.py | 3 +-- custom_components/battery_notes/repairs.py | 2 +- custom_components/battery_notes/sensor.py | 18 ++++++++---------- custom_components/battery_notes/services.py | 2 +- custom_components/battery_notes/store.py | 2 +- pyproject.toml | 2 -- 10 files changed, 22 insertions(+), 27 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 5b0483f7e..c7544a9f0 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -228,7 +228,7 @@ async def async_remove_entry( ) -async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> None: +async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> None: # noqa: PLR0912 """Migrate integration entry structure.""" migrate_base_entry: ConfigEntry | None = None diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 839c62506..50c513825 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -232,9 +232,9 @@ def _default_update(self, result: str | TemplateError) -> None: @callback def handle_result( self, - event: Event[EventStateChangedData] | None, - tmpl: Template, - last_result: str | None | TemplateError, + event: Event[EventStateChangedData] | None, # noqa: ARG002 + tmpl: Template, # noqa: ARG002 + last_result: str | None | TemplateError, # noqa: ARG002 result: str | TemplateError, ) -> None: # pylint: disable=unused-argument @@ -662,7 +662,7 @@ def __init__( @callback async def async_state_changed_listener( - self, event: Event[EventStateChangedData] | None = None + self, event: Event[EventStateChangedData] | None = None # noqa: ARG002 ) -> None: # pylint: disable=unused-argument """Handle child updates.""" diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 05f2b813c..c4b4d67b1 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -351,7 +351,7 @@ async def async_step_device( last_step=False, ) - async def async_step_battery( + async def async_step_battery( # noqa: PLR0912 self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Second step in config flow to add the battery type.""" @@ -514,7 +514,7 @@ def _is_new(self) -> bool: async def async_step_user( self, - user_input: dict[str, Any] | None = None, # pylint: disable=unused-argument + user_input: dict[str, Any] | None = None, # noqa: ARG002 ) -> SubentryFlowResult: """Add a subentry.""" @@ -712,7 +712,7 @@ async def async_step_manual( errors=errors, ) - async def async_step_battery( + async def async_step_battery( # noqa: PLR0912 self, user_input: dict[str, Any] | None = None ) -> SubentryFlowResult: """Second step in config flow to add the battery type.""" diff --git a/custom_components/battery_notes/coordinator.py b/custom_components/battery_notes/coordinator.py index e922dbbdd..6315d45ef 100644 --- a/custom_components/battery_notes/coordinator.py +++ b/custom_components/battery_notes/coordinator.py @@ -120,7 +120,7 @@ class BatteryNotesSubentryCoordinator(DataUpdateCoordinator[None]): _source_entity_name: str | None = None _outlier_filter: LowOutlierFilter | None = None - def __init__( + def __init__( # noqa: PLR0912 self, hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, @@ -208,7 +208,7 @@ def __init__( ) self.last_reported = last_reported - def _link_to_source(self) -> bool: + def _link_to_source(self) -> bool: # noqa: PLR0912 """Get the source device or entity, determine name and associate our wrapped battery if available.""" device_registry = dr.async_get(self.hass) entity_registry = er.async_get(self.hass) diff --git a/custom_components/battery_notes/library_updater.py b/custom_components/battery_notes/library_updater.py index 1c2f02ab3..fe9ed688d 100644 --- a/custom_components/battery_notes/library_updater.py +++ b/custom_components/battery_notes/library_updater.py @@ -70,7 +70,7 @@ def __init__(self, hass: HomeAssistant): ) @callback - async def timer_update(self, now: datetime) -> None: # pylint: disable=unused-argument + async def timer_update(self, now: datetime) -> None: # noqa: ARG002 """Need to update the library.""" if await self.time_to_update_library(23) is False: return @@ -89,7 +89,6 @@ async def timer_update(self, now: datetime) -> None: # pylint: disable=unused-a @callback async def get_library_updates(self, startup: bool = False) -> None: - # pylint: disable=unused-argument """Make a call to get the latest library.json.""" def _update_library_json(library_file: str, content: str) -> None: diff --git a/custom_components/battery_notes/repairs.py b/custom_components/battery_notes/repairs.py index 463e20634..ae97efe17 100644 --- a/custom_components/battery_notes/repairs.py +++ b/custom_components/battery_notes/repairs.py @@ -28,7 +28,7 @@ def __init__(self, data: dict[str, str | int | float | None] | None) -> None: async def async_step_init( self, - user_input: dict[str, str] | None = None, # pylint: disable=unused-argument + user_input: dict[str, str] | None = None, # noqa: ARG002 ) -> data_entry_flow.FlowResult: """Handle the first step of a fix flow.""" diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index e117adfaa..e73b42e7a 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -209,8 +209,8 @@ class BatteryNotesTypeSensor(BatteryNotesEntity, RestoreSensor): def __init__( self, hass, - config_entry: BatteryNotesConfigEntry, - subentry: ConfigSubentry, + config_entry: BatteryNotesConfigEntry, # noqa: ARG002 + subentry: ConfigSubentry, # noqa: ARG002 entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesSubentryCoordinator, unique_id: str, @@ -273,8 +273,8 @@ class BatteryNotesLastReplacedSensor(BatteryNotesEntity, SensorEntity): def __init__( self, hass, - config_entry: BatteryNotesConfigEntry, - subentry: ConfigSubentry, + config_entry: BatteryNotesConfigEntry, # noqa: ARG002 + subentry: ConfigSubentry, # noqa: ARG002 entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesSubentryCoordinator, description: BatteryNotesSensorEntityDescription, @@ -298,8 +298,7 @@ async def async_added_to_hass(self) -> None: """Handle added to Hass.""" await super().async_added_to_hass() - def _set_native_value(self, log_on_error=True): - # pylint: disable=unused-argument + def _set_native_value(self, log_on_error=True): # noqa: ARG002 if last_replaced := self.coordinator.last_replaced: self._native_value = last_replaced @@ -349,7 +348,7 @@ def __init__( self, hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, - subentry: ConfigSubentry, + subentry: ConfigSubentry, # noqa: ARG002 entity_description: BatteryNotesEntityDescription, coordinator: BatteryNotesSubentryCoordinator, unique_id: str, @@ -386,7 +385,7 @@ def __init__( @callback async def async_state_changed_listener( - self, event: Event[EventStateChangedData] | None = None + self, event: Event[EventStateChangedData] | None = None # noqa: ARG002 ) -> None: # pylint: disable=unused-argument """Handle child updates.""" @@ -438,9 +437,8 @@ async def async_state_changed_listener( @callback async def async_state_reported_listener( - self, event: Event[EventStateReportedData] | None = None + self, event: Event[EventStateReportedData] | None = None # noqa: ARG002 ) -> None: - # pylint: disable=unused-argument """Handle child updates.""" if not self.coordinator.wrapped_battery: diff --git a/custom_components/battery_notes/services.py b/custom_components/battery_notes/services.py index 6267ffb42..444db78fb 100644 --- a/custom_components/battery_notes/services.py +++ b/custom_components/battery_notes/services.py @@ -73,7 +73,7 @@ def async_setup_services(hass: HomeAssistant) -> None: ) -async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: +async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: # noqa: PLR0912 """Handle the service call.""" device_id = call.data.get(ATTR_DEVICE_ID, "") source_entity_id = call.data.get(ATTR_SOURCE_ENTITY_ID, "") diff --git a/custom_components/battery_notes/store.py b/custom_components/battery_notes/store.py index 28427e644..53c2f4d20 100644 --- a/custom_components/battery_notes/store.py +++ b/custom_components/battery_notes/store.py @@ -52,7 +52,7 @@ class MigratableStore(Store): """Holds battery notes data.""" async def _async_migrate_func( - self, old_major_version: int, old_minor_version: int, data: dict + self, old_major_version: int, old_minor_version: int, data: dict # noqa: ARG002 ): # pylint: disable=arguments-renamed # pylint: disable=unused-argument diff --git a/pyproject.toml b/pyproject.toml index 70e44976e..61eb23788 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,6 @@ ignore = [ "ANN202", # Missing return type annotation for private function "ANN204", # Missing return type annotation for special method "ARG001", # Unused function argument - "ARG002", # Unused method argument "ARG004", # Unused static method argument "COM818", # Trailing comma on bare tuple prohibited "D204", # 1 blank line required after class docstring @@ -96,7 +95,6 @@ ignore = [ "I001", # Import block is un-sorted or un-formatted "INP001", # File is part of an implicit namespace package "PGH003", # Use specific rule codes when ignoring type issues - "PLR0912", # Too many branches "PLR0913", # Too many arguments in function definition "PLR0915", # Too many statements "PLR2004", # Magic value used in comparison From b774f876875db09827e537dd0e1dab206799bfa9 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 15:33:54 +0000 Subject: [PATCH 220/235] Bump HA version --- pyproject.toml | 2 +- uv.lock | 757 ++++++++++++++++++++++++------------------------- 2 files changed, 365 insertions(+), 394 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a1aa56add..bd88c5e49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ Changelog = "https://github.com/andrew-codechimp/HA-Battery-Notes/releases" [dependency-groups] dev = [ "colorlog", - "homeassistant==2025.4.0", + "homeassistant==2025.9.0", "ruff", ] diff --git a/uv.lock b/uv.lock index 7597b18e6..efa7a9e33 100644 --- a/uv.lock +++ b/uv.lock @@ -4,31 +4,30 @@ requires-python = "==3.13.2" [[package]] name = "acme" -version = "3.2.0" +version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "josepy" }, { name = "pyopenssl" }, { name = "pyrfc3339" }, - { name = "pytz" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f9/6a/c94be0e8ee157f3c7721844863589c627c40bfa10d8838faeb6b28b59bb2/acme-3.2.0.tar.gz", hash = "sha256:e11d0ccf43ec19244ada40df1dc4ca49c9ce407749f3771d2cefe0674e206d84", size = 92875, upload-time = "2025-02-11T21:35:57.947Z" } +sdist = { url = "https://files.pythonhosted.org/packages/48/df/d006c4920fd04b843c21698bd038968cb9caa3315608f55abde0f8e4ad6b/acme-4.2.0.tar.gz", hash = "sha256:0df68c0e1acb3824a2100013f8cd51bda2e1a56aa23447449d14c942959f0c41", size = 96820, upload-time = "2025-08-05T19:19:08.86Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/1c/da759f277879f5b8aa0b6355689e091224b8af500c6983a1c8fb66bad5b0/acme-3.2.0-py3-none-any.whl", hash = "sha256:201b118d12426f746d936efc61706d30dc2f9e2635aebab0c86ec7f80eca5f30", size = 97444, upload-time = "2025-02-11T21:35:25.465Z" }, + { url = "https://files.pythonhosted.org/packages/86/26/9ff889b5d762616bf92ecbeb1ab93faddfd7bf6068146340359e9a6beb43/acme-4.2.0-py3-none-any.whl", hash = "sha256:6292011bbfa5f966521b2fb9469982c24ff4c58e240985f14564ccf35372e79a", size = 101573, upload-time = "2025-08-05T19:18:45.266Z" }, ] [[package]] name = "aiodns" -version = "3.2.0" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycares" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/84/41a6a2765abc124563f5380e76b9b24118977729e25a84112f8dfb2b33dc/aiodns-3.2.0.tar.gz", hash = "sha256:62869b23409349c21b072883ec8998316b234c9a9e36675756e8e317e8768f72", size = 7823, upload-time = "2024-03-31T11:27:30.639Z" } +sdist = { url = "https://files.pythonhosted.org/packages/17/0a/163e5260cecc12de6abc259d158d9da3b8ec062ab863107dcdb1166cdcef/aiodns-3.5.0.tar.gz", hash = "sha256:11264edbab51896ecf546c18eb0dd56dff0428c6aa6d2cd87e643e07300eb310", size = 14380, upload-time = "2025-06-13T16:21:53.595Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/14/13c65b1bd59f7e707e0cc0964fbab45c003f90292ed267d159eeeeaa2224/aiodns-3.2.0-py3-none-any.whl", hash = "sha256:e443c0c27b07da3174a109fd9e736d69058d808f144d3c9d56dbd1776964c5f5", size = 5735, upload-time = "2024-03-31T11:27:28.615Z" }, + { url = "https://files.pythonhosted.org/packages/f6/2c/711076e5f5d0707b8ec55a233c8bfb193e0981a800cd1b3b123e8ff61ca1/aiodns-3.5.0-py3-none-any.whl", hash = "sha256:6d0404f7d5215849233f6ee44854f2bb2481adf71b336b2279016ea5990ca5c5", size = 8068, upload-time = "2025-06-13T16:21:52.45Z" }, ] [[package]] @@ -42,22 +41,21 @@ wheels = [ [[package]] name = "aiohasupervisor" -version = "0.3.0" +version = "0.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "mashumaro" }, { name = "orjson" }, - { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/23/eceea174c1d827adea8a8b23f1428454157288fd58e6a9231e8861a45383/aiohasupervisor-0.3.0.tar.gz", hash = "sha256:91bf0b051f28582196f900a31c9bcbebec6de9e3ed1a32a2947a892c04748ce2", size = 40542, upload-time = "2025-02-05T14:41:08.946Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/13/e9c818c4be157db6383d6e0f5c56df4764553c241bc566cd819f42bd398c/aiohasupervisor-0.3.2.tar.gz", hash = "sha256:eb291b600cc5cf05072e4bd16df5655cfaea3b9f3b964844896b38230e529a7c", size = 42599, upload-time = "2025-08-26T14:47:47.357Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/09/98c83e4a20ae951d49720caeb6daf784293498fab0450af5b2236ca0c079/aiohasupervisor-0.3.0-py3-none-any.whl", hash = "sha256:f85b45c80ee24b381523e5a84a39f962f25e72c90026a3dcef2becea1d7f5501", size = 38550, upload-time = "2025-02-05T14:41:06.838Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e4/6f62ce34142558cb748c20976dfd8696b8bb4ed71653d43795f3de26a07d/aiohasupervisor-0.3.2-py3-none-any.whl", hash = "sha256:93599f698e7daf238e8040053d455104bac149f9e59fda757c6378708fbd1629", size = 39220, upload-time = "2025-08-26T14:47:46.262Z" }, ] [[package]] name = "aiohttp" -version = "3.11.16" +version = "3.12.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -68,24 +66,25 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f1/d9/1c4721d143e14af753f2bf5e3b681883e1f24b592c0482df6fa6e33597fa/aiohttp-3.11.16.tar.gz", hash = "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", size = 7676826, upload-time = "2025-04-02T02:17:44.74Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/52/52/7c712b2d9fb4d5e5fd6d12f9ab76e52baddfee71e3c8203ca7a7559d7f51/aiohttp-3.11.16-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", size = 698005, upload-time = "2025-04-02T02:16:37.923Z" }, - { url = "https://files.pythonhosted.org/packages/51/3e/61057814f7247666d43ac538abcd6335b022869ade2602dab9bf33f607d2/aiohttp-3.11.16-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", size = 461106, upload-time = "2025-04-02T02:16:39.961Z" }, - { url = "https://files.pythonhosted.org/packages/4f/85/6b79fb0ea6e913d596d5b949edc2402b20803f51b1a59e1bbc5bb7ba7569/aiohttp-3.11.16-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", size = 453394, upload-time = "2025-04-02T02:16:41.562Z" }, - { url = "https://files.pythonhosted.org/packages/4b/04/e1bb3fcfbd2c26753932c759593a32299aff8625eaa0bf8ff7d9c0c34a36/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", size = 1666643, upload-time = "2025-04-02T02:16:43.62Z" }, - { url = "https://files.pythonhosted.org/packages/0e/27/97bc0fdd1f439b8f060beb3ba8fb47b908dc170280090801158381ad7942/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", size = 1721948, upload-time = "2025-04-02T02:16:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/2c/4f/bc4c5119e75c05ef15c5670ef1563bbe25d4ed4893b76c57b0184d815e8b/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", size = 1774454, upload-time = "2025-04-02T02:16:48.562Z" }, - { url = "https://files.pythonhosted.org/packages/73/5b/54b42b2150bb26fdf795464aa55ceb1a49c85f84e98e6896d211eabc6670/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", size = 1677785, upload-time = "2025-04-02T02:16:50.367Z" }, - { url = "https://files.pythonhosted.org/packages/10/ee/a0fe68916d3f82eae199b8535624cf07a9c0a0958c7a76e56dd21140487a/aiohttp-3.11.16-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", size = 1608456, upload-time = "2025-04-02T02:16:52.158Z" }, - { url = "https://files.pythonhosted.org/packages/8b/48/83afd779242b7cf7e1ceed2ff624a86d3221e17798061cf9a79e0b246077/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", size = 1622424, upload-time = "2025-04-02T02:16:54.386Z" }, - { url = "https://files.pythonhosted.org/packages/6f/27/452f1d5fca1f516f9f731539b7f5faa9e9d3bf8a3a6c3cd7c4b031f20cbd/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", size = 1660943, upload-time = "2025-04-02T02:16:56.887Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e1/5c7d63143b8d00c83b958b9e78e7048c4a69903c760c1e329bf02bac57a1/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", size = 1622797, upload-time = "2025-04-02T02:16:58.676Z" }, - { url = "https://files.pythonhosted.org/packages/46/9e/2ac29cca2746ee8e449e73cd2fcb3d454467393ec03a269d50e49af743f1/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", size = 1687162, upload-time = "2025-04-02T02:17:01.076Z" }, - { url = "https://files.pythonhosted.org/packages/ad/6b/eaa6768e02edebaf37d77f4ffb74dd55f5cbcbb6a0dbf798ccec7b0ac23b/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", size = 1718518, upload-time = "2025-04-02T02:17:03.388Z" }, - { url = "https://files.pythonhosted.org/packages/e5/18/dda87cbad29472a51fa058d6d8257dfce168289adaeb358b86bd93af3b20/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", size = 1675254, upload-time = "2025-04-02T02:17:05.579Z" }, - { url = "https://files.pythonhosted.org/packages/32/d9/d2fb08c614df401d92c12fcbc60e6e879608d5e8909ef75c5ad8d4ad8aa7/aiohttp-3.11.16-cp313-cp313-win32.whl", hash = "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", size = 410698, upload-time = "2025-04-02T02:17:07.499Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ed/853e36d5a33c24544cfa46585895547de152dfef0b5c79fa675f6e4b7b87/aiohttp-3.11.16-cp313-cp313-win_amd64.whl", hash = "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", size = 436395, upload-time = "2025-04-02T02:17:09.566Z" }, + { url = "https://files.pythonhosted.org/packages/f2/33/918091abcf102e39d15aba2476ad9e7bd35ddb190dcdd43a854000d3da0d/aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315", size = 696741, upload-time = "2025-07-29T05:51:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2a/7495a81e39a998e400f3ecdd44a62107254803d1681d9189be5c2e4530cd/aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd", size = 474407, upload-time = "2025-07-29T05:51:21.165Z" }, + { url = "https://files.pythonhosted.org/packages/49/fc/a9576ab4be2dcbd0f73ee8675d16c707cfc12d5ee80ccf4015ba543480c9/aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4", size = 466703, upload-time = "2025-07-29T05:51:22.948Z" }, + { url = "https://files.pythonhosted.org/packages/09/2f/d4bcc8448cf536b2b54eed48f19682031ad182faa3a3fee54ebe5b156387/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7", size = 1705532, upload-time = "2025-07-29T05:51:25.211Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f3/59406396083f8b489261e3c011aa8aee9df360a96ac8fa5c2e7e1b8f0466/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d", size = 1686794, upload-time = "2025-07-29T05:51:27.145Z" }, + { url = "https://files.pythonhosted.org/packages/dc/71/164d194993a8d114ee5656c3b7ae9c12ceee7040d076bf7b32fb98a8c5c6/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b", size = 1738865, upload-time = "2025-07-29T05:51:29.366Z" }, + { url = "https://files.pythonhosted.org/packages/1c/00/d198461b699188a93ead39cb458554d9f0f69879b95078dce416d3209b54/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d", size = 1788238, upload-time = "2025-07-29T05:51:31.285Z" }, + { url = "https://files.pythonhosted.org/packages/85/b8/9e7175e1fa0ac8e56baa83bf3c214823ce250d0028955dfb23f43d5e61fd/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d", size = 1710566, upload-time = "2025-07-29T05:51:33.219Z" }, + { url = "https://files.pythonhosted.org/packages/59/e4/16a8eac9df39b48ae102ec030fa9f726d3570732e46ba0c592aeeb507b93/aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645", size = 1624270, upload-time = "2025-07-29T05:51:35.195Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/cd84dee7b6ace0740908fd0af170f9fab50c2a41ccbc3806aabcb1050141/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461", size = 1677294, upload-time = "2025-07-29T05:51:37.215Z" }, + { url = "https://files.pythonhosted.org/packages/ce/42/d0f1f85e50d401eccd12bf85c46ba84f947a84839c8a1c2c5f6e8ab1eb50/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9", size = 1708958, upload-time = "2025-07-29T05:51:39.328Z" }, + { url = "https://files.pythonhosted.org/packages/d5/6b/f6fa6c5790fb602538483aa5a1b86fcbad66244997e5230d88f9412ef24c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d", size = 1651553, upload-time = "2025-07-29T05:51:41.356Z" }, + { url = "https://files.pythonhosted.org/packages/04/36/a6d36ad545fa12e61d11d1932eef273928b0495e6a576eb2af04297fdd3c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693", size = 1727688, upload-time = "2025-07-29T05:51:43.452Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c8/f195e5e06608a97a4e52c5d41c7927301bf757a8e8bb5bbf8cef6c314961/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64", size = 1761157, upload-time = "2025-07-29T05:51:45.643Z" }, + { url = "https://files.pythonhosted.org/packages/05/6a/ea199e61b67f25ba688d3ce93f63b49b0a4e3b3d380f03971b4646412fc6/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51", size = 1710050, upload-time = "2025-07-29T05:51:48.203Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2e/ffeb7f6256b33635c29dbed29a22a723ff2dd7401fff42ea60cf2060abfb/aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0", size = 422647, upload-time = "2025-07-29T05:51:50.718Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8e/78ee35774201f38d5e1ba079c9958f7629b1fd079459aea9467441dbfbf5/aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84", size = 449067, upload-time = "2025-07-29T05:51:52.549Z" }, ] [[package]] @@ -104,26 +103,26 @@ wheels = [ [[package]] name = "aiohttp-cors" -version = "0.7.0" +version = "0.8.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/9e/6cdce7c3f346d8fd487adf68761728ad8cd5fbc296a7b07b92518350d31f/aiohttp-cors-0.7.0.tar.gz", hash = "sha256:4d39c6d7100fd9764ed1caf8cebf0eb01bf5e3f24e2e073fda6234bc48b19f5d", size = 35966, upload-time = "2018-03-06T15:45:42.936Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/d89e846a5444b3d5eb8985a6ddb0daef3774928e1bfbce8e84ec97b0ffa7/aiohttp_cors-0.8.1.tar.gz", hash = "sha256:ccacf9cb84b64939ea15f859a146af1f662a6b1d68175754a07315e305fb1403", size = 38626, upload-time = "2025-03-31T14:16:20.048Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/e7/e436a0c0eb5127d8b491a9b83ecd2391c6ff7dcd5548dfaec2080a2340fd/aiohttp_cors-0.7.0-py3-none-any.whl", hash = "sha256:0451ba59fdf6909d0e2cd21e4c0a43752bc0703d33fc78ae94d9d9321710193e", size = 27564, upload-time = "2018-03-06T15:45:42.034Z" }, + { url = "https://files.pythonhosted.org/packages/98/3b/40a68de458904bcc143622015fff2352b6461cd92fd66d3527bf1c6f5716/aiohttp_cors-0.8.1-py3-none-any.whl", hash = "sha256:3180cf304c5c712d626b9162b195b1db7ddf976a2a25172b35bb2448b890a80d", size = 25231, upload-time = "2025-03-31T14:16:18.478Z" }, ] [[package]] name = "aiohttp-fast-zlib" -version = "0.2.3" +version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d7/73/c93543264f745202a6fe78ad8ddb7c13a9d3e3ea47cde26501d683bd46a4/aiohttp_fast_zlib-0.2.3.tar.gz", hash = "sha256:d7e34621f2ac47155d9ad5d78f15ffb066a4ee849cb3d55df0077395ab4b3eff", size = 8591, upload-time = "2025-02-22T17:52:51.832Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/a6/982f3a013b42e914a2420631afcaecb729c49525cc6cc58e15d27ee4cb4b/aiohttp_fast_zlib-0.3.0.tar.gz", hash = "sha256:963a09de571b67fa0ef9cb44c5a32ede5cb1a51bc79fc21181b1cddd56b58b28", size = 8770, upload-time = "2025-06-07T12:41:49.161Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/55/9aebf9f5dac1a34bb0a4f300d2ec4692f86df44e458f3061a659dec2b98f/aiohttp_fast_zlib-0.2.3-py3-none-any.whl", hash = "sha256:41a93670f88042faff3ebbd039fd2fc37a0c956193c20eb758be45b1655a7e04", size = 8421, upload-time = "2025-02-22T17:52:49.971Z" }, + { url = "https://files.pythonhosted.org/packages/b7/11/ea9ecbcd6cf68c5de690fd39b66341405ab091aa0c3598277e687aa65901/aiohttp_fast_zlib-0.3.0-py3-none-any.whl", hash = "sha256:d4cb20760a3e1137c93cb42c13871cbc9cd1fdc069352f2712cd650d6c0e537e", size = 8615, upload-time = "2025-06-07T12:41:47.454Z" }, ] [[package]] @@ -239,11 +238,11 @@ wheels = [ [[package]] name = "attrs" -version = "25.1.0" +version = "25.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562, upload-time = "2025-01-25T11:30:12.508Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152, upload-time = "2025-01-25T11:30:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, ] [[package]] @@ -288,11 +287,11 @@ wheels = [ [[package]] name = "awesomeversion" -version = "24.6.0" +version = "25.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/e9/1baaf8619a3d66b467ba105976897e67b36dbad93b619753768357dbd475/awesomeversion-24.6.0.tar.gz", hash = "sha256:aee7ccbaed6f8d84e0f0364080c7734a0166d77ea6ccfcc4900b38917f1efc71", size = 11997, upload-time = "2024-06-24T11:09:27.958Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/95/bd19ef0ef6735bd7131c0310f71432ea5fdf3dc2b3245a262d1f34bae55e/awesomeversion-25.5.0.tar.gz", hash = "sha256:d64c9f3579d2f60a5aa506a9dd0b38a74ab5f45e04800f943a547c1102280f31", size = 11693, upload-time = "2025-05-29T12:38:02.352Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/a5/258ffce7048e8be24c6f402bcbf5d1b3933d5d63421d000a55e74248481b/awesomeversion-24.6.0-py3-none-any.whl", hash = "sha256:6768415b8954b379a25cebf21ed4f682cab10aebf3f82a6640aaaa15ec6821f2", size = 14716, upload-time = "2024-06-24T11:09:26.133Z" }, + { url = "https://files.pythonhosted.org/packages/dd/99/dc26ce0845a99f90fd99464a1d9124d5eacaa8bac92072af059cf002def4/awesomeversion-25.5.0-py3-none-any.whl", hash = "sha256:34a676ae10e10d3a96829fcc890a1d377fe1a7a2b98ee19951631951c2aebff6", size = 13998, upload-time = "2025-05-29T12:38:01.127Z" }, ] [[package]] @@ -319,32 +318,52 @@ wheels = [ [[package]] name = "bcrypt" -version = "4.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/7e/d95e7d96d4828e965891af92e43b52a4cd3395dc1c1ef4ee62748d0471d0/bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", size = 24294, upload-time = "2024-07-22T18:09:10.445Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/81/4e8f5bc0cd947e91fb720e1737371922854da47a94bc9630454e7b2845f8/bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", size = 471568, upload-time = "2024-07-22T18:08:55.603Z" }, - { url = "https://files.pythonhosted.org/packages/05/d2/1be1e16aedec04bcf8d0156e01b987d16a2063d38e64c3f28030a3427d61/bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", size = 277372, upload-time = "2024-07-22T18:08:51.446Z" }, - { url = "https://files.pythonhosted.org/packages/e3/96/7a654027638ad9b7589effb6db77eb63eba64319dfeaf9c0f4ca953e5f76/bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", size = 273488, upload-time = "2024-07-22T18:09:02.005Z" }, - { url = "https://files.pythonhosted.org/packages/46/54/dc7b58abeb4a3d95bab653405935e27ba32f21b812d8ff38f271fb6f7f55/bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", size = 277759, upload-time = "2024-07-22T18:08:50.017Z" }, - { url = "https://files.pythonhosted.org/packages/ac/be/da233c5f11fce3f8adec05e8e532b299b64833cc962f49331cdd0e614fa9/bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", size = 273796, upload-time = "2024-07-22T18:09:07.605Z" }, - { url = "https://files.pythonhosted.org/packages/b0/b8/8b4add88d55a263cf1c6b8cf66c735280954a04223fcd2880120cc767ac3/bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", size = 311082, upload-time = "2024-07-22T18:08:35.765Z" }, - { url = "https://files.pythonhosted.org/packages/7b/76/2aa660679abbdc7f8ee961552e4bb6415a81b303e55e9374533f22770203/bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", size = 305912, upload-time = "2024-07-22T18:08:40.049Z" }, - { url = "https://files.pythonhosted.org/packages/00/03/2af7c45034aba6002d4f2b728c1a385676b4eab7d764410e34fd768009f2/bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", size = 325185, upload-time = "2024-07-22T18:08:41.833Z" }, - { url = "https://files.pythonhosted.org/packages/dc/5d/6843443ce4ab3af40bddb6c7c085ed4a8418b3396f7a17e60e6d9888416c/bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", size = 335188, upload-time = "2024-07-22T18:08:29.25Z" }, - { url = "https://files.pythonhosted.org/packages/cb/4c/ff8ca83d816052fba36def1d24e97d9a85739b9bbf428c0d0ecd296a07c8/bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", size = 156481, upload-time = "2024-07-22T18:09:00.303Z" }, - { url = "https://files.pythonhosted.org/packages/65/f1/e09626c88a56cda488810fb29d5035f1662873777ed337880856b9d204ae/bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", size = 151336, upload-time = "2024-07-22T18:08:48.473Z" }, - { url = "https://files.pythonhosted.org/packages/96/86/8c6a84daed4dd878fbab094400c9174c43d9b838ace077a2f8ee8bc3ae12/bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", size = 472414, upload-time = "2024-07-22T18:08:32.176Z" }, - { url = "https://files.pythonhosted.org/packages/f6/05/e394515f4e23c17662e5aeb4d1859b11dc651be01a3bd03c2e919a155901/bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", size = 277599, upload-time = "2024-07-22T18:08:53.974Z" }, - { url = "https://files.pythonhosted.org/packages/4b/3b/ad784eac415937c53da48983756105d267b91e56aa53ba8a1b2014b8d930/bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", size = 273491, upload-time = "2024-07-22T18:08:45.231Z" }, - { url = "https://files.pythonhosted.org/packages/cc/14/b9ff8e0218bee95e517b70e91130effb4511e8827ac1ab00b4e30943a3f6/bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", size = 277934, upload-time = "2024-07-22T18:09:09.189Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d0/31938bb697600a04864246acde4918c4190a938f891fd11883eaaf41327a/bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", size = 273804, upload-time = "2024-07-22T18:09:04.618Z" }, - { url = "https://files.pythonhosted.org/packages/e7/c3/dae866739989e3f04ae304e1201932571708cb292a28b2f1b93283e2dcd8/bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", size = 311275, upload-time = "2024-07-22T18:08:43.317Z" }, - { url = "https://files.pythonhosted.org/packages/5d/2c/019bc2c63c6125ddf0483ee7d914a405860327767d437913942b476e9c9b/bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", size = 306355, upload-time = "2024-07-22T18:09:06.053Z" }, - { url = "https://files.pythonhosted.org/packages/75/fe/9e137727f122bbe29771d56afbf4e0dbc85968caa8957806f86404a5bfe1/bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", size = 325381, upload-time = "2024-07-22T18:08:33.904Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d4/586b9c18a327561ea4cd336ff4586cca1a7aa0f5ee04e23a8a8bb9ca64f1/bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", size = 335685, upload-time = "2024-07-22T18:08:56.897Z" }, - { url = "https://files.pythonhosted.org/packages/24/55/1a7127faf4576138bb278b91e9c75307490178979d69c8e6e273f74b974f/bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", size = 155857, upload-time = "2024-07-22T18:08:30.827Z" }, - { url = "https://files.pythonhosted.org/packages/1c/2a/c74052e54162ec639266d91539cca7cbf3d1d3b8b36afbfeaee0ea6a1702/bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", size = 151717, upload-time = "2024-07-22T18:08:52.781Z" }, +version = "4.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/5d/6d7433e0f3cd46ce0b43cd65e1db465ea024dbb8216fb2404e919c2ad77b/bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18", size = 25697, upload-time = "2025-02-28T01:24:09.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/2c/3d44e853d1fe969d229bd58d39ae6902b3d924af0e2b5a60d17d4b809ded/bcrypt-4.3.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281", size = 483719, upload-time = "2025-02-28T01:22:34.539Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e2/58ff6e2a22eca2e2cff5370ae56dba29d70b1ea6fc08ee9115c3ae367795/bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb", size = 272001, upload-time = "2025-02-28T01:22:38.078Z" }, + { url = "https://files.pythonhosted.org/packages/37/1f/c55ed8dbe994b1d088309e366749633c9eb90d139af3c0a50c102ba68a1a/bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180", size = 277451, upload-time = "2025-02-28T01:22:40.787Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1c/794feb2ecf22fe73dcfb697ea7057f632061faceb7dcf0f155f3443b4d79/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f", size = 272792, upload-time = "2025-02-28T01:22:43.144Z" }, + { url = "https://files.pythonhosted.org/packages/13/b7/0b289506a3f3598c2ae2bdfa0ea66969812ed200264e3f61df77753eee6d/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09", size = 289752, upload-time = "2025-02-28T01:22:45.56Z" }, + { url = "https://files.pythonhosted.org/packages/dc/24/d0fb023788afe9e83cc118895a9f6c57e1044e7e1672f045e46733421fe6/bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d", size = 277762, upload-time = "2025-02-28T01:22:47.023Z" }, + { url = "https://files.pythonhosted.org/packages/e4/38/cde58089492e55ac4ef6c49fea7027600c84fd23f7520c62118c03b4625e/bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd", size = 272384, upload-time = "2025-02-28T01:22:49.221Z" }, + { url = "https://files.pythonhosted.org/packages/de/6a/d5026520843490cfc8135d03012a413e4532a400e471e6188b01b2de853f/bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af", size = 277329, upload-time = "2025-02-28T01:22:51.603Z" }, + { url = "https://files.pythonhosted.org/packages/b3/a3/4fc5255e60486466c389e28c12579d2829b28a527360e9430b4041df4cf9/bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231", size = 305241, upload-time = "2025-02-28T01:22:53.283Z" }, + { url = "https://files.pythonhosted.org/packages/c7/15/2b37bc07d6ce27cc94e5b10fd5058900eb8fb11642300e932c8c82e25c4a/bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c", size = 309617, upload-time = "2025-02-28T01:22:55.461Z" }, + { url = "https://files.pythonhosted.org/packages/5f/1f/99f65edb09e6c935232ba0430c8c13bb98cb3194b6d636e61d93fe60ac59/bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f", size = 335751, upload-time = "2025-02-28T01:22:57.81Z" }, + { url = "https://files.pythonhosted.org/packages/00/1b/b324030c706711c99769988fcb694b3cb23f247ad39a7823a78e361bdbb8/bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d", size = 355965, upload-time = "2025-02-28T01:22:59.181Z" }, + { url = "https://files.pythonhosted.org/packages/aa/dd/20372a0579dd915dfc3b1cd4943b3bca431866fcb1dfdfd7518c3caddea6/bcrypt-4.3.0-cp313-cp313t-win32.whl", hash = "sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4", size = 155316, upload-time = "2025-02-28T01:23:00.763Z" }, + { url = "https://files.pythonhosted.org/packages/6d/52/45d969fcff6b5577c2bf17098dc36269b4c02197d551371c023130c0f890/bcrypt-4.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669", size = 147752, upload-time = "2025-02-28T01:23:02.908Z" }, + { url = "https://files.pythonhosted.org/packages/11/22/5ada0b9af72b60cbc4c9a399fdde4af0feaa609d27eb0adc61607997a3fa/bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d", size = 498019, upload-time = "2025-02-28T01:23:05.838Z" }, + { url = "https://files.pythonhosted.org/packages/b8/8c/252a1edc598dc1ce57905be173328eda073083826955ee3c97c7ff5ba584/bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b", size = 279174, upload-time = "2025-02-28T01:23:07.274Z" }, + { url = "https://files.pythonhosted.org/packages/29/5b/4547d5c49b85f0337c13929f2ccbe08b7283069eea3550a457914fc078aa/bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e", size = 283870, upload-time = "2025-02-28T01:23:09.151Z" }, + { url = "https://files.pythonhosted.org/packages/be/21/7dbaf3fa1745cb63f776bb046e481fbababd7d344c5324eab47f5ca92dd2/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59", size = 279601, upload-time = "2025-02-28T01:23:11.461Z" }, + { url = "https://files.pythonhosted.org/packages/6d/64/e042fc8262e971347d9230d9abbe70d68b0a549acd8611c83cebd3eaec67/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753", size = 297660, upload-time = "2025-02-28T01:23:12.989Z" }, + { url = "https://files.pythonhosted.org/packages/50/b8/6294eb84a3fef3b67c69b4470fcdd5326676806bf2519cda79331ab3c3a9/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761", size = 284083, upload-time = "2025-02-28T01:23:14.5Z" }, + { url = "https://files.pythonhosted.org/packages/62/e6/baff635a4f2c42e8788fe1b1633911c38551ecca9a749d1052d296329da6/bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb", size = 279237, upload-time = "2025-02-28T01:23:16.686Z" }, + { url = "https://files.pythonhosted.org/packages/39/48/46f623f1b0c7dc2e5de0b8af5e6f5ac4cc26408ac33f3d424e5ad8da4a90/bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d", size = 283737, upload-time = "2025-02-28T01:23:18.897Z" }, + { url = "https://files.pythonhosted.org/packages/49/8b/70671c3ce9c0fca4a6cc3cc6ccbaa7e948875a2e62cbd146e04a4011899c/bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f", size = 312741, upload-time = "2025-02-28T01:23:21.041Z" }, + { url = "https://files.pythonhosted.org/packages/27/fb/910d3a1caa2d249b6040a5caf9f9866c52114d51523ac2fb47578a27faee/bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732", size = 316472, upload-time = "2025-02-28T01:23:23.183Z" }, + { url = "https://files.pythonhosted.org/packages/dc/cf/7cf3a05b66ce466cfb575dbbda39718d45a609daa78500f57fa9f36fa3c0/bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef", size = 343606, upload-time = "2025-02-28T01:23:25.361Z" }, + { url = "https://files.pythonhosted.org/packages/e3/b8/e970ecc6d7e355c0d892b7f733480f4aa8509f99b33e71550242cf0b7e63/bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304", size = 362867, upload-time = "2025-02-28T01:23:26.875Z" }, + { url = "https://files.pythonhosted.org/packages/a9/97/8d3118efd8354c555a3422d544163f40d9f236be5b96c714086463f11699/bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51", size = 160589, upload-time = "2025-02-28T01:23:28.381Z" }, + { url = "https://files.pythonhosted.org/packages/29/07/416f0b99f7f3997c69815365babbc2e8754181a4b1899d921b3c7d5b6f12/bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62", size = 152794, upload-time = "2025-02-28T01:23:30.187Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c1/3fa0e9e4e0bfd3fd77eb8b52ec198fd6e1fd7e9402052e43f23483f956dd/bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3", size = 498969, upload-time = "2025-02-28T01:23:31.945Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d4/755ce19b6743394787fbd7dff6bf271b27ee9b5912a97242e3caf125885b/bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24", size = 279158, upload-time = "2025-02-28T01:23:34.161Z" }, + { url = "https://files.pythonhosted.org/packages/9b/5d/805ef1a749c965c46b28285dfb5cd272a7ed9fa971f970435a5133250182/bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef", size = 284285, upload-time = "2025-02-28T01:23:35.765Z" }, + { url = "https://files.pythonhosted.org/packages/ab/2b/698580547a4a4988e415721b71eb45e80c879f0fb04a62da131f45987b96/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b", size = 279583, upload-time = "2025-02-28T01:23:38.021Z" }, + { url = "https://files.pythonhosted.org/packages/f2/87/62e1e426418204db520f955ffd06f1efd389feca893dad7095bf35612eec/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676", size = 297896, upload-time = "2025-02-28T01:23:39.575Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c6/8fedca4c2ada1b6e889c52d2943b2f968d3427e5d65f595620ec4c06fa2f/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1", size = 284492, upload-time = "2025-02-28T01:23:40.901Z" }, + { url = "https://files.pythonhosted.org/packages/4d/4d/c43332dcaaddb7710a8ff5269fcccba97ed3c85987ddaa808db084267b9a/bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe", size = 279213, upload-time = "2025-02-28T01:23:42.653Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/1e36379e169a7df3a14a1c160a49b7b918600a6008de43ff20d479e6f4b5/bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0", size = 284162, upload-time = "2025-02-28T01:23:43.964Z" }, + { url = "https://files.pythonhosted.org/packages/1c/0a/644b2731194b0d7646f3210dc4d80c7fee3ecb3a1f791a6e0ae6bb8684e3/bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f", size = 312856, upload-time = "2025-02-28T01:23:46.011Z" }, + { url = "https://files.pythonhosted.org/packages/dc/62/2a871837c0bb6ab0c9a88bf54de0fc021a6a08832d4ea313ed92a669d437/bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23", size = 316726, upload-time = "2025-02-28T01:23:47.575Z" }, + { url = "https://files.pythonhosted.org/packages/0c/a1/9898ea3faac0b156d457fd73a3cb9c2855c6fd063e44b8522925cdd8ce46/bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe", size = 343664, upload-time = "2025-02-28T01:23:49.059Z" }, + { url = "https://files.pythonhosted.org/packages/40/f2/71b4ed65ce38982ecdda0ff20c3ad1b15e71949c78b2c053df53629ce940/bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505", size = 363128, upload-time = "2025-02-28T01:23:50.399Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/12f6a58eca6dea4be992d6c681b7ec9410a1d9f5cf368c61437e31daa879/bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a", size = 160598, upload-time = "2025-02-28T01:23:51.775Z" }, + { url = "https://files.pythonhosted.org/packages/a9/cf/45fb5261ece3e6b9817d3d82b2f343a505fd58674a92577923bc500bd1aa/bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b", size = 152799, upload-time = "2025-02-28T01:23:53.139Z" }, ] [[package]] @@ -590,37 +609,37 @@ wheels = [ [[package]] name = "cryptography" -version = "44.0.1" +version = "45.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/67/545c79fe50f7af51dbad56d16b23fe33f63ee6a5d956b3cb68ea110cbe64/cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14", size = 710819, upload-time = "2025-02-11T15:50:58.39Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/27/5e3524053b4c8889da65cf7814a9d0d8514a05194a25e1e34f46852ee6eb/cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009", size = 6642022, upload-time = "2025-02-11T15:49:32.752Z" }, - { url = "https://files.pythonhosted.org/packages/34/b9/4d1fa8d73ae6ec350012f89c3abfbff19fc95fe5420cf972e12a8d182986/cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f", size = 3943865, upload-time = "2025-02-11T15:49:36.659Z" }, - { url = "https://files.pythonhosted.org/packages/6e/57/371a9f3f3a4500807b5fcd29fec77f418ba27ffc629d88597d0d1049696e/cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2", size = 4162562, upload-time = "2025-02-11T15:49:39.541Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1d/5b77815e7d9cf1e3166988647f336f87d5634a5ccecec2ffbe08ef8dd481/cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911", size = 3951923, upload-time = "2025-02-11T15:49:42.461Z" }, - { url = "https://files.pythonhosted.org/packages/28/01/604508cd34a4024467cd4105887cf27da128cba3edd435b54e2395064bfb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69", size = 3685194, upload-time = "2025-02-11T15:49:45.226Z" }, - { url = "https://files.pythonhosted.org/packages/c6/3d/d3c55d4f1d24580a236a6753902ef6d8aafd04da942a1ee9efb9dc8fd0cb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026", size = 4187790, upload-time = "2025-02-11T15:49:48.215Z" }, - { url = "https://files.pythonhosted.org/packages/ea/a6/44d63950c8588bfa8594fd234d3d46e93c3841b8e84a066649c566afb972/cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd", size = 3951343, upload-time = "2025-02-11T15:49:50.313Z" }, - { url = "https://files.pythonhosted.org/packages/c1/17/f5282661b57301204cbf188254c1a0267dbd8b18f76337f0a7ce1038888c/cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0", size = 4187127, upload-time = "2025-02-11T15:49:52.051Z" }, - { url = "https://files.pythonhosted.org/packages/f3/68/abbae29ed4f9d96596687f3ceea8e233f65c9645fbbec68adb7c756bb85a/cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf", size = 4070666, upload-time = "2025-02-11T15:49:56.56Z" }, - { url = "https://files.pythonhosted.org/packages/0f/10/cf91691064a9e0a88ae27e31779200b1505d3aee877dbe1e4e0d73b4f155/cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864", size = 4288811, upload-time = "2025-02-11T15:49:59.248Z" }, - { url = "https://files.pythonhosted.org/packages/38/78/74ea9eb547d13c34e984e07ec8a473eb55b19c1451fe7fc8077c6a4b0548/cryptography-44.0.1-cp37-abi3-win32.whl", hash = "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a", size = 2771882, upload-time = "2025-02-11T15:50:01.478Z" }, - { url = "https://files.pythonhosted.org/packages/cf/6c/3907271ee485679e15c9f5e93eac6aa318f859b0aed8d369afd636fafa87/cryptography-44.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00", size = 3206989, upload-time = "2025-02-11T15:50:03.312Z" }, - { url = "https://files.pythonhosted.org/packages/9f/f1/676e69c56a9be9fd1bffa9bc3492366901f6e1f8f4079428b05f1414e65c/cryptography-44.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008", size = 6643714, upload-time = "2025-02-11T15:50:05.555Z" }, - { url = "https://files.pythonhosted.org/packages/ba/9f/1775600eb69e72d8f9931a104120f2667107a0ee478f6ad4fe4001559345/cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862", size = 3943269, upload-time = "2025-02-11T15:50:08.54Z" }, - { url = "https://files.pythonhosted.org/packages/25/ba/e00d5ad6b58183829615be7f11f55a7b6baa5a06910faabdc9961527ba44/cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3", size = 4166461, upload-time = "2025-02-11T15:50:11.419Z" }, - { url = "https://files.pythonhosted.org/packages/b3/45/690a02c748d719a95ab08b6e4decb9d81e0ec1bac510358f61624c86e8a3/cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7", size = 3950314, upload-time = "2025-02-11T15:50:14.181Z" }, - { url = "https://files.pythonhosted.org/packages/e6/50/bf8d090911347f9b75adc20f6f6569ed6ca9b9bff552e6e390f53c2a1233/cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a", size = 3686675, upload-time = "2025-02-11T15:50:16.3Z" }, - { url = "https://files.pythonhosted.org/packages/e1/e7/cfb18011821cc5f9b21efb3f94f3241e3a658d267a3bf3a0f45543858ed8/cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c", size = 4190429, upload-time = "2025-02-11T15:50:19.302Z" }, - { url = "https://files.pythonhosted.org/packages/07/ef/77c74d94a8bfc1a8a47b3cafe54af3db537f081742ee7a8a9bd982b62774/cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62", size = 3950039, upload-time = "2025-02-11T15:50:22.257Z" }, - { url = "https://files.pythonhosted.org/packages/6d/b9/8be0ff57c4592382b77406269b1e15650c9f1a167f9e34941b8515b97159/cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41", size = 4189713, upload-time = "2025-02-11T15:50:24.261Z" }, - { url = "https://files.pythonhosted.org/packages/78/e1/4b6ac5f4100545513b0847a4d276fe3c7ce0eacfa73e3b5ebd31776816ee/cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b", size = 4071193, upload-time = "2025-02-11T15:50:26.18Z" }, - { url = "https://files.pythonhosted.org/packages/3d/cb/afff48ceaed15531eab70445abe500f07f8f96af2bb35d98af6bfa89ebd4/cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7", size = 4289566, upload-time = "2025-02-11T15:50:28.221Z" }, - { url = "https://files.pythonhosted.org/packages/30/6f/4eca9e2e0f13ae459acd1ca7d9f0257ab86e68f44304847610afcb813dc9/cryptography-44.0.1-cp39-abi3-win32.whl", hash = "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9", size = 2772371, upload-time = "2025-02-11T15:50:29.997Z" }, - { url = "https://files.pythonhosted.org/packages/d2/05/5533d30f53f10239616a357f080892026db2d550a40c393d0a8a7af834a9/cryptography-44.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f", size = 3207303, upload-time = "2025-02-11T15:50:32.258Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/13/1f/9fa001e74a1993a9cadd2333bb889e50c66327b8594ac538ab8a04f915b7/cryptography-45.0.3.tar.gz", hash = "sha256:ec21313dd335c51d7877baf2972569f40a4291b76a0ce51391523ae358d05899", size = 744738, upload-time = "2025-05-25T14:17:24.777Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/b2/2345dc595998caa6f68adf84e8f8b50d18e9fc4638d32b22ea8daedd4b7a/cryptography-45.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:7573d9eebaeceeb55285205dbbb8753ac1e962af3d9640791d12b36864065e71", size = 7056239, upload-time = "2025-05-25T14:16:12.22Z" }, + { url = "https://files.pythonhosted.org/packages/71/3d/ac361649a0bfffc105e2298b720d8b862330a767dab27c06adc2ddbef96a/cryptography-45.0.3-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d377dde61c5d67eb4311eace661c3efda46c62113ff56bf05e2d679e02aebb5b", size = 4205541, upload-time = "2025-05-25T14:16:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/70/3e/c02a043750494d5c445f769e9c9f67e550d65060e0bfce52d91c1362693d/cryptography-45.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae1e637f527750811588e4582988932c222f8251f7b7ea93739acb624e1487f", size = 4433275, upload-time = "2025-05-25T14:16:16.421Z" }, + { url = "https://files.pythonhosted.org/packages/40/7a/9af0bfd48784e80eef3eb6fd6fde96fe706b4fc156751ce1b2b965dada70/cryptography-45.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ca932e11218bcc9ef812aa497cdf669484870ecbcf2d99b765d6c27a86000942", size = 4209173, upload-time = "2025-05-25T14:16:18.163Z" }, + { url = "https://files.pythonhosted.org/packages/31/5f/d6f8753c8708912df52e67969e80ef70b8e8897306cd9eb8b98201f8c184/cryptography-45.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af3f92b1dc25621f5fad065288a44ac790c5798e986a34d393ab27d2b27fcff9", size = 3898150, upload-time = "2025-05-25T14:16:20.34Z" }, + { url = "https://files.pythonhosted.org/packages/8b/50/f256ab79c671fb066e47336706dc398c3b1e125f952e07d54ce82cf4011a/cryptography-45.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f8f8f0b73b885ddd7f3d8c2b2234a7d3ba49002b0223f58cfde1bedd9563c56", size = 4466473, upload-time = "2025-05-25T14:16:22.605Z" }, + { url = "https://files.pythonhosted.org/packages/62/e7/312428336bb2df0848d0768ab5a062e11a32d18139447a76dfc19ada8eed/cryptography-45.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9cc80ce69032ffa528b5e16d217fa4d8d4bb7d6ba8659c1b4d74a1b0f4235fca", size = 4211890, upload-time = "2025-05-25T14:16:24.738Z" }, + { url = "https://files.pythonhosted.org/packages/e7/53/8a130e22c1e432b3c14896ec5eb7ac01fb53c6737e1d705df7e0efb647c6/cryptography-45.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c824c9281cb628015bfc3c59335163d4ca0540d49de4582d6c2637312907e4b1", size = 4466300, upload-time = "2025-05-25T14:16:26.768Z" }, + { url = "https://files.pythonhosted.org/packages/ba/75/6bb6579688ef805fd16a053005fce93944cdade465fc92ef32bbc5c40681/cryptography-45.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5833bb4355cb377ebd880457663a972cd044e7f49585aee39245c0d592904578", size = 4332483, upload-time = "2025-05-25T14:16:28.316Z" }, + { url = "https://files.pythonhosted.org/packages/2f/11/2538f4e1ce05c6c4f81f43c1ef2bd6de7ae5e24ee284460ff6c77e42ca77/cryptography-45.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bb5bf55dcb69f7067d80354d0a348368da907345a2c448b0babc4215ccd3497", size = 4573714, upload-time = "2025-05-25T14:16:30.474Z" }, + { url = "https://files.pythonhosted.org/packages/f5/bb/e86e9cf07f73a98d84a4084e8fd420b0e82330a901d9cac8149f994c3417/cryptography-45.0.3-cp311-abi3-win32.whl", hash = "sha256:3ad69eeb92a9de9421e1f6685e85a10fbcfb75c833b42cc9bc2ba9fb00da4710", size = 2934752, upload-time = "2025-05-25T14:16:32.204Z" }, + { url = "https://files.pythonhosted.org/packages/c7/75/063bc9ddc3d1c73e959054f1fc091b79572e716ef74d6caaa56e945b4af9/cryptography-45.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:97787952246a77d77934d41b62fb1b6f3581d83f71b44796a4158d93b8f5c490", size = 3412465, upload-time = "2025-05-25T14:16:33.888Z" }, + { url = "https://files.pythonhosted.org/packages/71/9b/04ead6015229a9396890d7654ee35ef630860fb42dc9ff9ec27f72157952/cryptography-45.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:c92519d242703b675ccefd0f0562eb45e74d438e001f8ab52d628e885751fb06", size = 7031892, upload-time = "2025-05-25T14:16:36.214Z" }, + { url = "https://files.pythonhosted.org/packages/46/c7/c7d05d0e133a09fc677b8a87953815c522697bdf025e5cac13ba419e7240/cryptography-45.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5edcb90da1843df85292ef3a313513766a78fbbb83f584a5a58fb001a5a9d57", size = 4196181, upload-time = "2025-05-25T14:16:37.934Z" }, + { url = "https://files.pythonhosted.org/packages/08/7a/6ad3aa796b18a683657cef930a986fac0045417e2dc428fd336cfc45ba52/cryptography-45.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38deed72285c7ed699864f964a3f4cf11ab3fb38e8d39cfcd96710cd2b5bb716", size = 4423370, upload-time = "2025-05-25T14:16:39.502Z" }, + { url = "https://files.pythonhosted.org/packages/4f/58/ec1461bfcb393525f597ac6a10a63938d18775b7803324072974b41a926b/cryptography-45.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5555365a50efe1f486eed6ac7062c33b97ccef409f5970a0b6f205a7cfab59c8", size = 4197839, upload-time = "2025-05-25T14:16:41.322Z" }, + { url = "https://files.pythonhosted.org/packages/d4/3d/5185b117c32ad4f40846f579369a80e710d6146c2baa8ce09d01612750db/cryptography-45.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e4253ed8f5948a3589b3caee7ad9a5bf218ffd16869c516535325fece163dcc", size = 3886324, upload-time = "2025-05-25T14:16:43.041Z" }, + { url = "https://files.pythonhosted.org/packages/67/85/caba91a57d291a2ad46e74016d1f83ac294f08128b26e2a81e9b4f2d2555/cryptography-45.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cfd84777b4b6684955ce86156cfb5e08d75e80dc2585e10d69e47f014f0a5342", size = 4450447, upload-time = "2025-05-25T14:16:44.759Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d1/164e3c9d559133a38279215c712b8ba38e77735d3412f37711b9f8f6f7e0/cryptography-45.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:a2b56de3417fd5f48773ad8e91abaa700b678dc7fe1e0c757e1ae340779acf7b", size = 4200576, upload-time = "2025-05-25T14:16:46.438Z" }, + { url = "https://files.pythonhosted.org/packages/71/7a/e002d5ce624ed46dfc32abe1deff32190f3ac47ede911789ee936f5a4255/cryptography-45.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:57a6500d459e8035e813bd8b51b671977fb149a8c95ed814989da682314d0782", size = 4450308, upload-time = "2025-05-25T14:16:48.228Z" }, + { url = "https://files.pythonhosted.org/packages/87/ad/3fbff9c28cf09b0a71e98af57d74f3662dea4a174b12acc493de00ea3f28/cryptography-45.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f22af3c78abfbc7cbcdf2c55d23c3e022e1a462ee2481011d518c7fb9c9f3d65", size = 4325125, upload-time = "2025-05-25T14:16:49.844Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b4/51417d0cc01802304c1984d76e9592f15e4801abd44ef7ba657060520bf0/cryptography-45.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:232954730c362638544758a8160c4ee1b832dc011d2c41a306ad8f7cccc5bb0b", size = 4560038, upload-time = "2025-05-25T14:16:51.398Z" }, + { url = "https://files.pythonhosted.org/packages/80/38/d572f6482d45789a7202fb87d052deb7a7b136bf17473ebff33536727a2c/cryptography-45.0.3-cp37-abi3-win32.whl", hash = "sha256:cb6ab89421bc90e0422aca911c69044c2912fc3debb19bb3c1bfe28ee3dff6ab", size = 2924070, upload-time = "2025-05-25T14:16:53.472Z" }, + { url = "https://files.pythonhosted.org/packages/91/5a/61f39c0ff4443651cc64e626fa97ad3099249152039952be8f344d6b0c86/cryptography-45.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:d54ae41e6bd70ea23707843021c778f151ca258081586f0cfa31d936ae43d1b2", size = 3395005, upload-time = "2025-05-25T14:16:55.134Z" }, ] [[package]] @@ -660,26 +679,26 @@ wheels = [ [[package]] name = "fnv-hash-fast" -version = "1.4.0" +version = "1.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fnvhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ec/36/fa1cab334dc1228235d76a22bdeab67b6895e08eb1870821c500e86b240b/fnv_hash_fast-1.4.0.tar.gz", hash = "sha256:12a2a437263f08815bd2d5759c12e881408718bb82cfffceb0341575f2c43f0a", size = 5661, upload-time = "2025-03-05T01:09:25.465Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/85/ebcbccceb212bdc9b0d964609e319469075df2a7393dcad7048a333507b6/fnv_hash_fast-1.5.0.tar.gz", hash = "sha256:c3f0d077a5e0eee6bc12938a6f560b6394b5736f3e30db83b2eca8e0fb948a74", size = 5670, upload-time = "2025-04-23T02:04:49.804Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/05/178cf5b827f0d54caa3fbb28e6e7493ad5e0d75a165b57f8c2fe9fcd3519/fnv_hash_fast-1.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7f1bbfe718df3aa10aafa2c40cf6bb9581a267c914a4005fc0f5e3ce21a01a12", size = 18552, upload-time = "2025-03-05T01:15:50.836Z" }, - { url = "https://files.pythonhosted.org/packages/b6/5b/88866809455c974b5cf8c8c18c2ad293df796083703c0da8ec6c4e50135f/fnv_hash_fast-1.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:25dd05a0e7f8381b2d881b122400862da4f855b80fa9d6f5a20cda0706fde9b7", size = 18585, upload-time = "2025-03-05T01:15:52.297Z" }, - { url = "https://files.pythonhosted.org/packages/da/60/effbe5965ab6da6e6805ca18729f588bee486b8e4127b8bf52037908a3a3/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1038ab67c143f1119b2cad9fb3d909439e88f72f3b137015eb642ad91245734", size = 21761, upload-time = "2025-03-05T01:15:54.267Z" }, - { url = "https://files.pythonhosted.org/packages/a9/87/d80f730b9f535cec9a6db8c11e9e38413e0a398d9e7f2e0abde80b3587b3/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c5ae87deee0204f2aaabfc861bf322f0f1dea078c847e10e35bc67c7becfefd6", size = 23126, upload-time = "2025-03-05T01:15:55.387Z" }, - { url = "https://files.pythonhosted.org/packages/ce/70/0c795f5a92a58f6d105078c632a9a5cf1de4bcdd42d3fec20592ed7c59f4/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a07b27755378f08e399fc124f724f3af58f8f54167f6fd525068e51ba7e9e9f", size = 22152, upload-time = "2025-03-05T01:15:56.579Z" }, - { url = "https://files.pythonhosted.org/packages/9f/72/14a8bb3844037cc6afe0ba147020ba2d450f44d29a32a0d2863583822ee2/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37cb8e67d8d4df670a699d928a4ed74b7284724d73df736a8ff9f57178e6a720", size = 19755, upload-time = "2025-03-05T01:15:57.696Z" }, - { url = "https://files.pythonhosted.org/packages/c6/f8/7cce1f63cd07c0c3d998ddd5f193b56247edd0ccb049c7549d05f559c889/fnv_hash_fast-1.4.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:5fa7945986ae71c68eef522335d33a671ed2c33952272ea4360d0c44331f90eb", size = 21792, upload-time = "2025-03-05T01:09:23.45Z" }, - { url = "https://files.pythonhosted.org/packages/1a/86/5e3d38f4ef3c7c862ba8cbda1d64b48b8ba314d937fe967815ee8e1d85bb/fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e6dd8f20122d0fba69171858438eb74f1f12f4630178ab0db9d05bd0dfc68054", size = 22437, upload-time = "2025-03-05T01:15:58.782Z" }, - { url = "https://files.pythonhosted.org/packages/89/85/bb90b080e30c4e082e3120874e218956a0b8a78c5913139b38c8056be4da/fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c410adea6d70c8663a168b1f499bb3cb9ff743675921aa8b6fb99e07cd83eb45", size = 20259, upload-time = "2025-03-05T01:15:59.894Z" }, - { url = "https://files.pythonhosted.org/packages/83/00/788bb2e0f369c543a8bdbc5621a7070f31b13ee6992420e198636b42276a/fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:579e5ba4265f4fc41dbe6fbe12d133d22aa7948455ef8a16fbe7bc5d1666d6d8", size = 24059, upload-time = "2025-03-05T01:16:01.121Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9d/ede35e832d6801ae8373abc8926c631cb6739e7d5e432366be44a9bf98d2/fnv_hash_fast-1.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c9568b00ab3e91af8a8409c2955b5d781f9a338c0c00428e788ff77f3baac3ec", size = 22927, upload-time = "2025-03-05T01:16:02.228Z" }, - { url = "https://files.pythonhosted.org/packages/df/5c/2aa4c0b1b1648d80567499062bfe0414384df2487e794885d5ff4dc235a4/fnv_hash_fast-1.4.0-cp313-cp313-win32.whl", hash = "sha256:c04e54d919b5e0ef2cb6a2de0fbabb3d075ee2609324a678d2471c87542bbacb", size = 18938, upload-time = "2025-03-05T01:16:04.28Z" }, - { url = "https://files.pythonhosted.org/packages/d3/7a/a666e222003f52941aa4b620f2658cc1f665a84657886e584a69613bfb58/fnv_hash_fast-1.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:5eec9b18aee7ed014ba0b8a2cf59d5c2f2d83af683c4ad87e9c03dd2f4f5d573", size = 20453, upload-time = "2025-03-05T01:16:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/29/8e/eb6fcf4ff3d70919cc8eed1383c68682b5831b1e89d951e6922d650edeee/fnv_hash_fast-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0294a449e672583589e8e5cce9d60dfc5e29db3fb05737ccae98deba28b7d77f", size = 18597, upload-time = "2025-04-23T02:10:26.498Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f3/e5db61ba58224fd5a47fa7a16be8ee0ad1c09deadac2f73363aefa7342a9/fnv_hash_fast-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:643002874f4620c408fdf881041e7d8b23683e56b1d588604a3640758c4e6dfe", size = 18568, upload-time = "2025-04-23T02:10:27.508Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1d/8fe9a5237dd43a0a8f236413fe0e0e33b0f4f91170e6cf9f9242ff940855/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13904ceb14e09c5d6092eca8f6e1a65ea8bb606328b4b86d055365f23657ca58", size = 21736, upload-time = "2025-04-23T02:10:28.825Z" }, + { url = "https://files.pythonhosted.org/packages/d7/d5/5629db362f2f515429228b564e51a404c0b7b6cad04f4896161bfb5bb974/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:5747cc25ee940eaa70c05d0b3d0a49808e952b7dd8388453980b94ea9e95e837", size = 23091, upload-time = "2025-04-23T02:10:29.875Z" }, + { url = "https://files.pythonhosted.org/packages/c0/0c/4ba49df5da5b345cb456ea1934569472555a9c4ead4a5ae899494b52e385/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9640989256fcb9e95a383ebde372b79bb4b7e14d296e5242fb32c422a6d83480", size = 22098, upload-time = "2025-04-23T02:10:31.066Z" }, + { url = "https://files.pythonhosted.org/packages/00/3d/99d8c58f550bff0da4e51f71643fa0b2b16ef47e4e8746b0698221e01451/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e3b79e3fada2925810efd1605f265f0335cafe48f1389c96c51261b3e2e05ff", size = 19733, upload-time = "2025-04-23T02:10:32.87Z" }, + { url = "https://files.pythonhosted.org/packages/ee/00/20389a610628b5d294811fabe1bca408a4f5fe4cb5745ae05f52c77ef1b6/fnv_hash_fast-1.5.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:ccd18302d1a2d800f6403be7d8cb02293f2e39363bc64cd843ed040396d36f1a", size = 21731, upload-time = "2025-04-23T02:04:48.356Z" }, + { url = "https://files.pythonhosted.org/packages/41/29/0c7a0c4bd2c06d7c917d38b81a084e53176ef514d5fd9d40163be1b78d78/fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:14c7672ae4cfaf8f88418dc23ef50977f4603c602932038ae52fae44b1b03aec", size = 22374, upload-time = "2025-04-23T02:10:33.88Z" }, + { url = "https://files.pythonhosted.org/packages/ca/12/5efe53c767def55ab00ab184b4fe04591ddabffbe6daf08476dfe18dc8fb/fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:90fff41560a95d5262f2237259a94d0c8c662e131b13540e9db51dbec1a14912", size = 20260, upload-time = "2025-04-23T02:10:34.943Z" }, + { url = "https://files.pythonhosted.org/packages/81/00/83261b804ee585ec1de0da3226185e2934ec7a1747b6a871bb2cbd777e51/fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9b52650bd9107cfe8a81087b6bd9fa995f0ba23dafa1a7cb343aed99c136062", size = 23974, upload-time = "2025-04-23T02:10:35.943Z" }, + { url = "https://files.pythonhosted.org/packages/84/1a/72d8716adfe349eb3762e923df6e25346311469dfd3dbca4fc05d8176ced/fnv_hash_fast-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a4b3fa3e5e3273872d021bc2d6ef26db273bdd82a1bedd49b3f798dbcb34bba", size = 22844, upload-time = "2025-04-23T02:10:36.925Z" }, + { url = "https://files.pythonhosted.org/packages/8d/65/0dd16e6b1f6d163b56b34e8c6c1af41086e8d3e5fc3b77701d24c5f5cdde/fnv_hash_fast-1.5.0-cp313-cp313-win32.whl", hash = "sha256:381175ad08ee8b0c69c14283a60a20d953c24bc19e2d80e5932eb590211c50dc", size = 18983, upload-time = "2025-04-23T02:10:37.918Z" }, + { url = "https://files.pythonhosted.org/packages/8d/8d/179abdc6304491ea72f276e1c85f5c15269f680d1cfeda07cb9963e4a03c/fnv_hash_fast-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:db8e61e38d5eddf4a4115e82bbee35f0b1b1d5affe8736f78ffc833751746cf2", size = 20507, upload-time = "2025-04-23T02:10:38.967Z" }, ] [[package]] @@ -790,24 +809,12 @@ library = [ [package.metadata.requires-dev] dev = [ { name = "colorlog" }, - { name = "homeassistant", specifier = "==2025.4.0" }, + { name = "homeassistant", specifier = "==2025.9.0" }, { name = "ruff" }, ] docs = [{ name = "mkdocs-material" }] library = [{ name = "pytablewriter", specifier = "==0.61.0" }] -[[package]] -name = "ha-ffmpeg" -version = "3.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "async-timeout" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1e/3b/bd1284a9bc39cc119b0da551a81be6cf30dc3cfb369ce8c62fb648d7a2ea/ha_ffmpeg-3.2.2.tar.gz", hash = "sha256:80e4a77b3eda73df456ec9cc3295a898ed7cbb8cd2d59798f10e8c10a8e6c401", size = 7608, upload-time = "2024-11-08T13:32:14.181Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/66/7863e5a3713bb71c02f050f14a751b02e7a2d50eaf2109c96a1202e65d8b/ha_ffmpeg-3.2.2-py3-none-any.whl", hash = "sha256:4fd4a4f4cdaf3243d2737942f3f41f141e4437d2af1167655815dc03283b1652", size = 8749, upload-time = "2024-11-08T13:32:12.69Z" }, -] - [[package]] name = "habluetooth" version = "5.7.0" @@ -839,7 +846,7 @@ wheels = [ [[package]] name = "hass-nabucasa" -version = "0.94.0" +version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "acme" }, @@ -849,27 +856,17 @@ dependencies = [ { name = "attrs" }, { name = "ciso8601" }, { name = "cryptography" }, + { name = "josepy" }, { name = "pycognito" }, { name = "pyjwt" }, + { name = "sentence-stream" }, { name = "snitun" }, { name = "webrtc-models" }, + { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/33/ac792655794278f3d429b821a5a6f4628eb9de75fdacc222da0a13cfc9a0/hass_nabucasa-0.94.0.tar.gz", hash = "sha256:2ae8ca877dbd7c128fd49f64383e69bd86a395ed175cf73d6f33478d07491947", size = 72357, upload-time = "2025-03-03T10:54:57.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/cd/fabe44c4513600e153082e15a0b98c69d728e8fa0ed5bac7658b330f8979/hass_nabucasa-0.94.0-py3-none-any.whl", hash = "sha256:5acbe999373b81e7f6cc8d2f5918fe9db0a9e18e52e6ddb19d7857818c039c46", size = 61929, upload-time = "2025-03-03T10:54:55.93Z" }, -] - -[[package]] -name = "hassil" -version = "2.2.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyyaml" }, - { name = "unicode-rbnf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c9/f4/bf2f642321114c4ca4586efb194274905388a09b1c95e52529eba2fd4d51/hassil-2.2.3.tar.gz", hash = "sha256:8516ebde2caf72362ea566cd677cb382138be3f5d36889fee21bb313bfd7d0d8", size = 46867, upload-time = "2025-02-04T17:36:22.142Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/bc/e75262103f27b0736f4bfb12637787684268c1ceec9686d549fb40c36b3a/hass_nabucasa-1.1.0.tar.gz", hash = "sha256:c9714b54ed94c8e32a8a2eec2b3e42e57739c8fa85eda164b08b292f1f311246", size = 90993, upload-time = "2025-09-03T08:40:04.711Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/ae/684cf7117bdd757bb7d92c20deb528db2d42a3d018fc788f1c415421d809/hassil-2.2.3-py3-none-any.whl", hash = "sha256:d22032c5268e6bdfc7fb60fa8f52f3a955d5ca982ccbfe535ed074c593e66bdf", size = 42097, upload-time = "2025-02-04T17:36:21.09Z" }, + { url = "https://files.pythonhosted.org/packages/54/35/adba64783adaeaf4108e51d7c869397e3e1fafda7777ec54274b4fff1e05/hass_nabucasa-1.1.0-py3-none-any.whl", hash = "sha256:d10498e0f61d19369e12eba121c391cc5a79f7b71d6d3295ca0e8ff7ecfb96f6", size = 73127, upload-time = "2025-09-03T08:40:03.286Z" }, ] [[package]] @@ -884,18 +881,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/85/9b/9904cec885cc32c45e8c22cd7e19d9c342e30074fdb7c58f3d5b33ea1adb/home_assistant_bluetooth-1.13.1-py3-none-any.whl", hash = "sha256:cdf13b5b45f7744165677831e309ee78fbaf0c2866c6b5931e14d1e4e7dae5d7", size = 7915, upload-time = "2025-02-04T16:11:13.163Z" }, ] -[[package]] -name = "home-assistant-intents" -version = "2025.3.28" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4b/f1/9c13e5535bbcf4801f81d88f452581b113246e485d8ff9f9d64faffcf50f/home_assistant_intents-2025.3.28.tar.gz", hash = "sha256:3b93717525ae738f9163a2215bb0628321b86bd8418bfd64e1d5ce571b84fef4", size = 451905, upload-time = "2025-03-28T14:26:00.919Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/e5/627c5cb34ed05bbe3227834702327fab6cbed6c5d6f0c6f053a85cc2b10f/home_assistant_intents-2025.3.28-py3-none-any.whl", hash = "sha256:14f589a5a188f8b0c52f06ff8998c171fda25f8729de7a4011636295d90e7295", size = 470049, upload-time = "2025-03-28T14:25:59.107Z" }, -] - [[package]] name = "homeassistant" -version = "2025.4.0" +version = "2025.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiodns" }, @@ -918,28 +906,20 @@ dependencies = [ { name = "cronsim" }, { name = "cryptography" }, { name = "fnv-hash-fast" }, - { name = "ha-ffmpeg" }, { name = "hass-nabucasa" }, - { name = "hassil" }, { name = "home-assistant-bluetooth" }, - { name = "home-assistant-intents" }, { name = "httpx" }, { name = "ifaddr" }, { name = "jinja2" }, { name = "lru-dict" }, - { name = "mutagen" }, - { name = "numpy" }, { name = "orjson" }, { name = "packaging" }, { name = "pillow" }, { name = "propcache" }, { name = "psutil-home-assistant" }, { name = "pyjwt" }, - { name = "pymicro-vad" }, { name = "pyopenssl" }, - { name = "pyspeex-noise" }, { name = "python-slugify" }, - { name = "pyturbojpeg" }, { name = "pyyaml" }, { name = "requests" }, { name = "securetar" }, @@ -957,9 +937,9 @@ dependencies = [ { name = "yarl" }, { name = "zeroconf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f2/f1/4163474410566c1b5a0888740f87d414bd84263fa17360a3c3938cb4e65e/homeassistant-2025.4.0.tar.gz", hash = "sha256:c1f9702e4a935da061d5f95254d25c039282862a510b3643ee76fb55a2b610f3", size = 25040180, upload-time = "2025-04-02T17:19:14.907Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/d1/c3c7c042acb9adcaa51f60f8e88feee726905f2b8bf0e7f7308aa18e02ad/homeassistant-2025.9.0.tar.gz", hash = "sha256:f2afb8dc2ecedb3dc809b79a1c7099e2b0ad177631aec880904578f7716cedfc", size = 27782182, upload-time = "2025-09-03T18:30:25.159Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/5d/f346faa9fa684a0321db3800598ee62cf14b8163eab30c9fe5222ecf5425/homeassistant-2025.4.0-py3-none-any.whl", hash = "sha256:b1159c123b97fe372feadbe505cf920b87fbcd932177e5c0c86a6f6b3c6ee1b9", size = 42937231, upload-time = "2025-04-02T17:19:08.558Z" }, + { url = "https://files.pythonhosted.org/packages/40/2f/a0e924149bff1f4dbfee7d7d146811300eee649eeff83f9d4b2ad2ebd2c7/homeassistant-2025.9.0-py3-none-any.whl", hash = "sha256:51bda990b96c419f5e2a3410aa1a636e454ac5a65616ea8ec663f04956c5a725", size = 46884752, upload-time = "2025-09-03T18:30:18.917Z" }, ] [[package]] @@ -1031,15 +1011,14 @@ wheels = [ [[package]] name = "josepy" -version = "1.15.0" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, - { name = "pyopenssl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c1/8a/cd416f56cd4492878e8d62701b4ad32407c5ce541f247abf31d6e5f3b79b/josepy-1.15.0.tar.gz", hash = "sha256:46c9b13d1a5104ffbfa5853e555805c915dcde71c2cd91ce5386e84211281223", size = 59310, upload-time = "2025-01-22T23:56:23.577Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/ad/6f520aee9cc9618d33430380741e9ef859b2c560b1e7915e755c084f6bc0/josepy-2.2.0.tar.gz", hash = "sha256:74c033151337c854f83efe5305a291686cef723b4b970c43cfe7270cf4a677a9", size = 56500, upload-time = "2025-10-14T14:54:42.108Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/74/fc54f4b03cb66b0b351131fcf1797fe9d7c1e6ce9a38fd940d9bc2d9531b/josepy-1.15.0-py3-none-any.whl", hash = "sha256:878c08cedd0a892c98c6d1a90b3cb869736f9c751f68ec8901e7b05a0c040fed", size = 32774, upload-time = "2025-01-22T23:56:21.524Z" }, + { url = "https://files.pythonhosted.org/packages/f8/b2/b5caed897fbb1cc286c62c01feca977e08d99a17230ff3055b9a98eccf1d/josepy-2.2.0-py3-none-any.whl", hash = "sha256:63e9dd116d4078778c25ca88f880cc5d95f1cab0099bebe3a34c2e299f65d10b", size = 29211, upload-time = "2025-10-14T14:54:41.144Z" }, ] [[package]] @@ -1234,63 +1213,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, ] -[[package]] -name = "mutagen" -version = "1.47.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/e6/64bc71b74eef4b68e61eb921dcf72dabd9e4ec4af1e11891bbd312ccbb77/mutagen-1.47.0.tar.gz", hash = "sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99", size = 1274186, upload-time = "2023-09-03T16:33:33.411Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/7a/620f945b96be1f6ee357d211d5bf74ab1b7fe72a9f1525aafbfe3aee6875/mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719", size = 194391, upload-time = "2023-09-03T16:33:29.955Z" }, -] - -[[package]] -name = "numpy" -version = "2.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/d0/c12ddfd3a02274be06ffc71f3efc6d0e457b0409c4481596881e748cb264/numpy-2.2.2.tar.gz", hash = "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f", size = 20233295, upload-time = "2025-01-19T00:02:09.581Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/fe/df5624001f4f5c3e0b78e9017bfab7fdc18a8d3b3d3161da3d64924dd659/numpy-2.2.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc", size = 20899188, upload-time = "2025-01-18T23:31:15.292Z" }, - { url = "https://files.pythonhosted.org/packages/a9/80/d349c3b5ed66bd3cb0214be60c27e32b90a506946857b866838adbe84040/numpy-2.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369", size = 14113972, upload-time = "2025-01-18T23:31:42.323Z" }, - { url = "https://files.pythonhosted.org/packages/9d/50/949ec9cbb28c4b751edfa64503f0913cbfa8d795b4a251e7980f13a8a655/numpy-2.2.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd", size = 5114294, upload-time = "2025-01-18T23:31:54.219Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f3/399c15629d5a0c68ef2aa7621d430b2be22034f01dd7f3c65a9c9666c445/numpy-2.2.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be", size = 6648426, upload-time = "2025-01-18T23:32:06.055Z" }, - { url = "https://files.pythonhosted.org/packages/2c/03/c72474c13772e30e1bc2e558cdffd9123c7872b731263d5648b5c49dd459/numpy-2.2.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84", size = 14045990, upload-time = "2025-01-18T23:32:38.031Z" }, - { url = "https://files.pythonhosted.org/packages/83/9c/96a9ab62274ffafb023f8ee08c88d3d31ee74ca58869f859db6845494fa6/numpy-2.2.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff", size = 16096614, upload-time = "2025-01-18T23:33:12.265Z" }, - { url = "https://files.pythonhosted.org/packages/d5/34/cd0a735534c29bec7093544b3a509febc9b0df77718a9b41ffb0809c9f46/numpy-2.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0", size = 15242123, upload-time = "2025-01-18T23:33:46.412Z" }, - { url = "https://files.pythonhosted.org/packages/5e/6d/541717a554a8f56fa75e91886d9b79ade2e595918690eb5d0d3dbd3accb9/numpy-2.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de", size = 17859160, upload-time = "2025-01-18T23:34:37.857Z" }, - { url = "https://files.pythonhosted.org/packages/b9/a5/fbf1f2b54adab31510728edd06a05c1b30839f37cf8c9747cb85831aaf1b/numpy-2.2.2-cp313-cp313-win32.whl", hash = "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9", size = 6273337, upload-time = "2025-01-18T23:40:10.83Z" }, - { url = "https://files.pythonhosted.org/packages/56/e5/01106b9291ef1d680f82bc47d0c5b5e26dfed15b0754928e8f856c82c881/numpy-2.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369", size = 12609010, upload-time = "2025-01-18T23:40:31.34Z" }, - { url = "https://files.pythonhosted.org/packages/9f/30/f23d9876de0f08dceb707c4dcf7f8dd7588266745029debb12a3cdd40be6/numpy-2.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391", size = 20924451, upload-time = "2025-01-18T23:35:26.639Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ec/6ea85b2da9d5dfa1dbb4cb3c76587fc8ddcae580cb1262303ab21c0926c4/numpy-2.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39", size = 14122390, upload-time = "2025-01-18T23:36:30.596Z" }, - { url = "https://files.pythonhosted.org/packages/68/05/bfbdf490414a7dbaf65b10c78bc243f312c4553234b6d91c94eb7c4b53c2/numpy-2.2.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317", size = 5156590, upload-time = "2025-01-18T23:36:52.637Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ec/fe2e91b2642b9d6544518388a441bcd65c904cea38d9ff998e2e8ebf808e/numpy-2.2.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49", size = 6671958, upload-time = "2025-01-18T23:37:05.361Z" }, - { url = "https://files.pythonhosted.org/packages/b1/6f/6531a78e182f194d33ee17e59d67d03d0d5a1ce7f6be7343787828d1bd4a/numpy-2.2.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2", size = 14019950, upload-time = "2025-01-18T23:37:38.605Z" }, - { url = "https://files.pythonhosted.org/packages/e1/fb/13c58591d0b6294a08cc40fcc6b9552d239d773d520858ae27f39997f2ae/numpy-2.2.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7", size = 16079759, upload-time = "2025-01-18T23:38:05.757Z" }, - { url = "https://files.pythonhosted.org/packages/2c/f2/f2f8edd62abb4b289f65a7f6d1f3650273af00b91b7267a2431be7f1aec6/numpy-2.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb", size = 15226139, upload-time = "2025-01-18T23:38:38.458Z" }, - { url = "https://files.pythonhosted.org/packages/aa/29/14a177f1a90b8ad8a592ca32124ac06af5eff32889874e53a308f850290f/numpy-2.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648", size = 17856316, upload-time = "2025-01-18T23:39:11.454Z" }, - { url = "https://files.pythonhosted.org/packages/95/03/242ae8d7b97f4e0e4ab8dd51231465fb23ed5e802680d629149722e3faf1/numpy-2.2.2-cp313-cp313t-win32.whl", hash = "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4", size = 6329134, upload-time = "2025-01-18T23:39:28.128Z" }, - { url = "https://files.pythonhosted.org/packages/80/94/cd9e9b04012c015cb6320ab3bf43bc615e248dddfeb163728e800a5d96f0/numpy-2.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576", size = 12696208, upload-time = "2025-01-18T23:39:51.85Z" }, -] - [[package]] name = "orjson" -version = "3.10.16" +version = "3.11.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/c7/03913cc4332174071950acf5b0735463e3f63760c80585ef369270c2b372/orjson-3.10.16.tar.gz", hash = "sha256:d2aaa5c495e11d17b9b93205f5fa196737ee3202f000aaebf028dc9a73750f10", size = 5410415, upload-time = "2025-03-24T17:00:23.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/4d/8df5f83256a809c22c4d6792ce8d43bb503be0fb7a8e4da9025754b09658/orjson-3.11.3.tar.gz", hash = "sha256:1c0603b1d2ffcd43a411d64797a19556ef76958aef1c182f22dc30860152a98a", size = 5482394, upload-time = "2025-08-26T17:46:43.171Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/b9/ff6aa28b8c86af9526160905593a2fe8d004ac7a5e592ee0b0ff71017511/orjson-3.10.16-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:148a97f7de811ba14bc6dbc4a433e0341ffd2cc285065199fb5f6a98013744bd", size = 249289, upload-time = "2025-03-24T16:59:40.117Z" }, - { url = "https://files.pythonhosted.org/packages/6c/81/6d92a586149b52684ab8fd70f3623c91d0e6a692f30fd8c728916ab2263c/orjson-3.10.16-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1d960c1bf0e734ea36d0adc880076de3846aaec45ffad29b78c7f1b7962516b8", size = 133640, upload-time = "2025-03-24T16:59:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/c2/88/b72443f4793d2e16039ab85d0026677932b15ab968595fb7149750d74134/orjson-3.10.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a318cd184d1269f68634464b12871386808dc8b7c27de8565234d25975a7a137", size = 138286, upload-time = "2025-03-24T16:59:42.769Z" }, - { url = "https://files.pythonhosted.org/packages/c3/3c/72a22d4b28c076c4016d5a52bd644a8e4d849d3bb0373d9e377f9e3b2250/orjson-3.10.16-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df23f8df3ef9223d1d6748bea63fca55aae7da30a875700809c500a05975522b", size = 132307, upload-time = "2025-03-24T16:59:44.143Z" }, - { url = "https://files.pythonhosted.org/packages/8a/a2/f1259561bdb6ad7061ff1b95dab082fe32758c4bc143ba8d3d70831f0a06/orjson-3.10.16-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b94dda8dd6d1378f1037d7f3f6b21db769ef911c4567cbaa962bb6dc5021cf90", size = 136739, upload-time = "2025-03-24T16:59:45.995Z" }, - { url = "https://files.pythonhosted.org/packages/3d/af/c7583c4b34f33d8b8b90cfaab010ff18dd64e7074cc1e117a5f1eff20dcf/orjson-3.10.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f12970a26666a8775346003fd94347d03ccb98ab8aa063036818381acf5f523e", size = 138076, upload-time = "2025-03-24T16:59:47.776Z" }, - { url = "https://files.pythonhosted.org/packages/d7/59/d7fc7fbdd3d4a64c2eae4fc7341a5aa39cf9549bd5e2d7f6d3c07f8b715b/orjson-3.10.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15a1431a245d856bd56e4d29ea0023eb4d2c8f71efe914beb3dee8ab3f0cd7fb", size = 142643, upload-time = "2025-03-24T16:59:49.258Z" }, - { url = "https://files.pythonhosted.org/packages/92/0e/3bd8f2197d27601f16b4464ae948826da2bcf128af31230a9dbbad7ceb57/orjson-3.10.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c83655cfc247f399a222567d146524674a7b217af7ef8289c0ff53cfe8db09f0", size = 133168, upload-time = "2025-03-24T16:59:51.027Z" }, - { url = "https://files.pythonhosted.org/packages/af/a8/351fd87b664b02f899f9144d2c3dc848b33ac04a5df05234cbfb9e2a7540/orjson-3.10.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fa59ae64cb6ddde8f09bdbf7baf933c4cd05734ad84dcf4e43b887eb24e37652", size = 135271, upload-time = "2025-03-24T16:59:52.449Z" }, - { url = "https://files.pythonhosted.org/packages/ba/b0/a6d42a7d412d867c60c0337d95123517dd5a9370deea705ea1be0f89389e/orjson-3.10.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ca5426e5aacc2e9507d341bc169d8af9c3cbe88f4cd4c1cf2f87e8564730eb56", size = 412444, upload-time = "2025-03-24T16:59:53.825Z" }, - { url = "https://files.pythonhosted.org/packages/79/ec/7572cd4e20863f60996f3f10bc0a6da64a6fd9c35954189a914cec0b7377/orjson-3.10.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6fd5da4edf98a400946cd3a195680de56f1e7575109b9acb9493331047157430", size = 152737, upload-time = "2025-03-24T16:59:55.599Z" }, - { url = "https://files.pythonhosted.org/packages/a9/19/ceb9e8fed5403b2e76a8ac15f581b9d25780a3be3c9b3aa54b7777a210d5/orjson-3.10.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:980ecc7a53e567169282a5e0ff078393bac78320d44238da4e246d71a4e0e8f5", size = 137482, upload-time = "2025-03-24T16:59:57.045Z" }, - { url = "https://files.pythonhosted.org/packages/1b/78/a78bb810f3786579dbbbd94768284cbe8f2fd65167cd7020260679665c17/orjson-3.10.16-cp313-cp313-win32.whl", hash = "sha256:28f79944dd006ac540a6465ebd5f8f45dfdf0948ff998eac7a908275b4c1add6", size = 141714, upload-time = "2025-03-24T16:59:58.666Z" }, - { url = "https://files.pythonhosted.org/packages/81/9c/b66ce9245ff319df2c3278acd351a3f6145ef34b4a2d7f4b0f739368370f/orjson-3.10.16-cp313-cp313-win_amd64.whl", hash = "sha256:fe0a145e96d51971407cb8ba947e63ead2aa915db59d6631a355f5f2150b56b7", size = 133954, upload-time = "2025-03-24T17:00:00.101Z" }, + { url = "https://files.pythonhosted.org/packages/fc/79/8932b27293ad35919571f77cb3693b5906cf14f206ef17546052a241fdf6/orjson-3.11.3-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:af40c6612fd2a4b00de648aa26d18186cd1322330bd3a3cc52f87c699e995810", size = 238127, upload-time = "2025-08-26T17:45:38.146Z" }, + { url = "https://files.pythonhosted.org/packages/1c/82/cb93cd8cf132cd7643b30b6c5a56a26c4e780c7a145db6f83de977b540ce/orjson-3.11.3-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:9f1587f26c235894c09e8b5b7636a38091a9e6e7fe4531937534749c04face43", size = 127494, upload-time = "2025-08-26T17:45:39.57Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/2d9eb181a9b6bb71463a78882bcac1027fd29cf62c38a40cc02fc11d3495/orjson-3.11.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61dcdad16da5bb486d7227a37a2e789c429397793a6955227cedbd7252eb5a27", size = 123017, upload-time = "2025-08-26T17:45:40.876Z" }, + { url = "https://files.pythonhosted.org/packages/b4/14/a0e971e72d03b509190232356d54c0f34507a05050bd026b8db2bf2c192c/orjson-3.11.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11c6d71478e2cbea0a709e8a06365fa63da81da6498a53e4c4f065881d21ae8f", size = 127898, upload-time = "2025-08-26T17:45:42.188Z" }, + { url = "https://files.pythonhosted.org/packages/8e/af/dc74536722b03d65e17042cc30ae586161093e5b1f29bccda24765a6ae47/orjson-3.11.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff94112e0098470b665cb0ed06efb187154b63649403b8d5e9aedeb482b4548c", size = 130742, upload-time = "2025-08-26T17:45:43.511Z" }, + { url = "https://files.pythonhosted.org/packages/62/e6/7a3b63b6677bce089fe939353cda24a7679825c43a24e49f757805fc0d8a/orjson-3.11.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b756575aaa2a855a75192f356bbda11a89169830e1439cfb1a3e1a6dde7be", size = 132377, upload-time = "2025-08-26T17:45:45.525Z" }, + { url = "https://files.pythonhosted.org/packages/fc/cd/ce2ab93e2e7eaf518f0fd15e3068b8c43216c8a44ed82ac2b79ce5cef72d/orjson-3.11.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9416cc19a349c167ef76135b2fe40d03cea93680428efee8771f3e9fb66079d", size = 135313, upload-time = "2025-08-26T17:45:46.821Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/f98355eff0bd1a38454209bbc73372ce351ba29933cb3e2eba16c04b9448/orjson-3.11.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b822caf5b9752bc6f246eb08124c3d12bf2175b66ab74bac2ef3bbf9221ce1b2", size = 132908, upload-time = "2025-08-26T17:45:48.126Z" }, + { url = "https://files.pythonhosted.org/packages/eb/92/8f5182d7bc2a1bed46ed960b61a39af8389f0ad476120cd99e67182bfb6d/orjson-3.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:414f71e3bdd5573893bf5ecdf35c32b213ed20aa15536fe2f588f946c318824f", size = 130905, upload-time = "2025-08-26T17:45:49.414Z" }, + { url = "https://files.pythonhosted.org/packages/1a/60/c41ca753ce9ffe3d0f67b9b4c093bdd6e5fdb1bc53064f992f66bb99954d/orjson-3.11.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:828e3149ad8815dc14468f36ab2a4b819237c155ee1370341b91ea4c8672d2ee", size = 403812, upload-time = "2025-08-26T17:45:51.085Z" }, + { url = "https://files.pythonhosted.org/packages/dd/13/e4a4f16d71ce1868860db59092e78782c67082a8f1dc06a3788aef2b41bc/orjson-3.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac9e05f25627ffc714c21f8dfe3a579445a5c392a9c8ae7ba1d0e9fb5333f56e", size = 146277, upload-time = "2025-08-26T17:45:52.851Z" }, + { url = "https://files.pythonhosted.org/packages/8d/8b/bafb7f0afef9344754a3a0597a12442f1b85a048b82108ef2c956f53babd/orjson-3.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e44fbe4000bd321d9f3b648ae46e0196d21577cf66ae684a96ff90b1f7c93633", size = 135418, upload-time = "2025-08-26T17:45:54.806Z" }, + { url = "https://files.pythonhosted.org/packages/60/d4/bae8e4f26afb2c23bea69d2f6d566132584d1c3a5fe89ee8c17b718cab67/orjson-3.11.3-cp313-cp313-win32.whl", hash = "sha256:2039b7847ba3eec1f5886e75e6763a16e18c68a63efc4b029ddf994821e2e66b", size = 136216, upload-time = "2025-08-26T17:45:57.182Z" }, + { url = "https://files.pythonhosted.org/packages/88/76/224985d9f127e121c8cad882cea55f0ebe39f97925de040b75ccd4b33999/orjson-3.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:29be5ac4164aa8bdcba5fa0700a3c9c316b411d8ed9d39ef8a882541bd452fae", size = 131362, upload-time = "2025-08-26T17:45:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cf/0dce7a0be94bd36d1346be5067ed65ded6adb795fdbe3abd234c8d576d01/orjson-3.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:18bd1435cb1f2857ceb59cfb7de6f92593ef7b831ccd1b9bfb28ca530e539dce", size = 125989, upload-time = "2025-08-26T17:45:59.95Z" }, ] [[package]] @@ -1331,29 +1274,35 @@ wheels = [ [[package]] name = "pillow" -version = "11.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/af/c097e544e7bd278333db77933e535098c259609c4eb3b85381109602fb5b/pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", size = 46742715, upload-time = "2025-01-02T08:13:58.407Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/31/9ca79cafdce364fd5c980cd3416c20ce1bebd235b470d262f9d24d810184/pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc", size = 3226640, upload-time = "2025-01-02T08:11:58.329Z" }, - { url = "https://files.pythonhosted.org/packages/ac/0f/ff07ad45a1f172a497aa393b13a9d81a32e1477ef0e869d030e3c1532521/pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0", size = 3101437, upload-time = "2025-01-02T08:12:01.797Z" }, - { url = "https://files.pythonhosted.org/packages/08/2f/9906fca87a68d29ec4530be1f893149e0cb64a86d1f9f70a7cfcdfe8ae44/pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1", size = 4326605, upload-time = "2025-01-02T08:12:05.224Z" }, - { url = "https://files.pythonhosted.org/packages/b0/0f/f3547ee15b145bc5c8b336401b2d4c9d9da67da9dcb572d7c0d4103d2c69/pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec", size = 4411173, upload-time = "2025-01-02T08:12:08.281Z" }, - { url = "https://files.pythonhosted.org/packages/b1/df/bf8176aa5db515c5de584c5e00df9bab0713548fd780c82a86cba2c2fedb/pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5", size = 4369145, upload-time = "2025-01-02T08:12:11.411Z" }, - { url = "https://files.pythonhosted.org/packages/de/7c/7433122d1cfadc740f577cb55526fdc39129a648ac65ce64db2eb7209277/pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114", size = 4496340, upload-time = "2025-01-02T08:12:15.29Z" }, - { url = "https://files.pythonhosted.org/packages/25/46/dd94b93ca6bd555588835f2504bd90c00d5438fe131cf01cfa0c5131a19d/pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352", size = 4296906, upload-time = "2025-01-02T08:12:17.485Z" }, - { url = "https://files.pythonhosted.org/packages/a8/28/2f9d32014dfc7753e586db9add35b8a41b7a3b46540e965cb6d6bc607bd2/pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3", size = 4431759, upload-time = "2025-01-02T08:12:20.382Z" }, - { url = "https://files.pythonhosted.org/packages/33/48/19c2cbe7403870fbe8b7737d19eb013f46299cdfe4501573367f6396c775/pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9", size = 2291657, upload-time = "2025-01-02T08:12:23.922Z" }, - { url = "https://files.pythonhosted.org/packages/3b/ad/285c556747d34c399f332ba7c1a595ba245796ef3e22eae190f5364bb62b/pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c", size = 2626304, upload-time = "2025-01-02T08:12:28.069Z" }, - { url = "https://files.pythonhosted.org/packages/e5/7b/ef35a71163bf36db06e9c8729608f78dedf032fc8313d19bd4be5c2588f3/pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65", size = 2375117, upload-time = "2025-01-02T08:12:30.064Z" }, - { url = "https://files.pythonhosted.org/packages/79/30/77f54228401e84d6791354888549b45824ab0ffde659bafa67956303a09f/pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861", size = 3230060, upload-time = "2025-01-02T08:12:32.362Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b1/56723b74b07dd64c1010fee011951ea9c35a43d8020acd03111f14298225/pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081", size = 3106192, upload-time = "2025-01-02T08:12:34.361Z" }, - { url = "https://files.pythonhosted.org/packages/e1/cd/7bf7180e08f80a4dcc6b4c3a0aa9e0b0ae57168562726a05dc8aa8fa66b0/pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c", size = 4446805, upload-time = "2025-01-02T08:12:36.99Z" }, - { url = "https://files.pythonhosted.org/packages/97/42/87c856ea30c8ed97e8efbe672b58c8304dee0573f8c7cab62ae9e31db6ae/pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547", size = 4530623, upload-time = "2025-01-02T08:12:41.912Z" }, - { url = "https://files.pythonhosted.org/packages/ff/41/026879e90c84a88e33fb00cc6bd915ac2743c67e87a18f80270dfe3c2041/pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab", size = 4465191, upload-time = "2025-01-02T08:12:45.186Z" }, - { url = "https://files.pythonhosted.org/packages/e5/fb/a7960e838bc5df57a2ce23183bfd2290d97c33028b96bde332a9057834d3/pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9", size = 2295494, upload-time = "2025-01-02T08:12:47.098Z" }, - { url = "https://files.pythonhosted.org/packages/d7/6c/6ec83ee2f6f0fda8d4cf89045c6be4b0373ebfc363ba8538f8c999f63fcd/pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe", size = 2631595, upload-time = "2025-01-02T08:12:50.47Z" }, - { url = "https://files.pythonhosted.org/packages/cf/6c/41c21c6c8af92b9fea313aa47c75de49e2f9a467964ee33eb0135d47eb64/pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756", size = 2377651, upload-time = "2025-01-02T08:12:53.356Z" }, +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, ] [[package]] @@ -1367,43 +1316,43 @@ wheels = [ [[package]] name = "propcache" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/76/f941e63d55c0293ff7829dd21e7cf1147e90a526756869a9070f287a68c9/propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5", size = 42722, upload-time = "2025-02-20T19:03:29.191Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/0f/a79dd23a0efd6ee01ab0dc9750d8479b343bfd0c73560d59d271eb6a99d4/propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568", size = 77287, upload-time = "2025-02-20T19:01:40.897Z" }, - { url = "https://files.pythonhosted.org/packages/b8/51/76675703c90de38ac75adb8deceb3f3ad99b67ff02a0fa5d067757971ab8/propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9", size = 44923, upload-time = "2025-02-20T19:01:42.397Z" }, - { url = "https://files.pythonhosted.org/packages/01/9b/fd5ddbee66cf7686e73c516227c2fd9bf471dbfed0f48329d095ea1228d3/propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767", size = 44325, upload-time = "2025-02-20T19:01:43.976Z" }, - { url = "https://files.pythonhosted.org/packages/13/1c/6961f11eb215a683b34b903b82bde486c606516c1466bf1fa67f26906d51/propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8", size = 225116, upload-time = "2025-02-20T19:01:45.488Z" }, - { url = "https://files.pythonhosted.org/packages/ef/ea/f8410c40abcb2e40dffe9adeed017898c930974650a63e5c79b886aa9f73/propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0", size = 229905, upload-time = "2025-02-20T19:01:49.454Z" }, - { url = "https://files.pythonhosted.org/packages/ef/5a/a9bf90894001468bf8e6ea293bb00626cc9ef10f8eb7996e9ec29345c7ed/propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d", size = 233221, upload-time = "2025-02-20T19:01:51.142Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ce/fffdddd9725b690b01d345c1156b4c2cc6dca09ab5c23a6d07b8f37d6e2f/propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05", size = 227627, upload-time = "2025-02-20T19:01:53.695Z" }, - { url = "https://files.pythonhosted.org/packages/58/ae/45c89a5994a334735a3032b48e8e4a98c05d9536ddee0719913dc27da548/propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe", size = 214217, upload-time = "2025-02-20T19:01:55.309Z" }, - { url = "https://files.pythonhosted.org/packages/01/84/bc60188c3290ff8f5f4a92b9ca2d93a62e449c8daf6fd11ad517ad136926/propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1", size = 212921, upload-time = "2025-02-20T19:01:57.893Z" }, - { url = "https://files.pythonhosted.org/packages/14/b3/39d60224048feef7a96edabb8217dc3f75415457e5ebbef6814f8b2a27b5/propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92", size = 208200, upload-time = "2025-02-20T19:02:00.026Z" }, - { url = "https://files.pythonhosted.org/packages/9d/b3/0a6720b86791251273fff8a01bc8e628bc70903513bd456f86cde1e1ef84/propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787", size = 208400, upload-time = "2025-02-20T19:02:03.997Z" }, - { url = "https://files.pythonhosted.org/packages/e9/4f/bb470f3e687790547e2e78105fb411f54e0cdde0d74106ccadd2521c6572/propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545", size = 218116, upload-time = "2025-02-20T19:02:06.042Z" }, - { url = "https://files.pythonhosted.org/packages/34/71/277f7f9add469698ac9724c199bfe06f85b199542121a71f65a80423d62a/propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e", size = 222911, upload-time = "2025-02-20T19:02:08.748Z" }, - { url = "https://files.pythonhosted.org/packages/92/e3/a7b9782aef5a2fc765b1d97da9ec7aed2f25a4e985703608e73232205e3f/propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626", size = 216563, upload-time = "2025-02-20T19:02:11.322Z" }, - { url = "https://files.pythonhosted.org/packages/ab/76/0583ca2c551aa08ffcff87b2c6849c8f01c1f6fb815a5226f0c5c202173e/propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374", size = 39763, upload-time = "2025-02-20T19:02:12.977Z" }, - { url = "https://files.pythonhosted.org/packages/80/ec/c6a84f9a36f608379b95f0e786c111d5465926f8c62f12be8cdadb02b15c/propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a", size = 43650, upload-time = "2025-02-20T19:02:15.041Z" }, - { url = "https://files.pythonhosted.org/packages/ee/95/7d32e3560f5bf83fc2f2a4c1b0c181d327d53d5f85ebd045ab89d4d97763/propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf", size = 82140, upload-time = "2025-02-20T19:02:16.562Z" }, - { url = "https://files.pythonhosted.org/packages/86/89/752388f12e6027a5e63f5d075f15291ded48e2d8311314fff039da5a9b11/propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0", size = 47296, upload-time = "2025-02-20T19:02:17.974Z" }, - { url = "https://files.pythonhosted.org/packages/1b/4c/b55c98d586c69180d3048984a57a5ea238bdeeccf82dbfcd598e935e10bb/propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829", size = 46724, upload-time = "2025-02-20T19:02:19.588Z" }, - { url = "https://files.pythonhosted.org/packages/0f/b6/67451a437aed90c4e951e320b5b3d7eb584ade1d5592f6e5e8f678030989/propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa", size = 291499, upload-time = "2025-02-20T19:02:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ff/e4179facd21515b24737e1e26e02615dfb5ed29416eed4cf5bc6ac5ce5fb/propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6", size = 293911, upload-time = "2025-02-20T19:02:24.248Z" }, - { url = "https://files.pythonhosted.org/packages/76/8d/94a8585992a064a23bd54f56c5e58c3b8bf0c0a06ae10e56f2353ae16c3d/propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db", size = 293301, upload-time = "2025-02-20T19:02:26.034Z" }, - { url = "https://files.pythonhosted.org/packages/b0/b8/2c860c92b4134f68c7716c6f30a0d723973f881c32a6d7a24c4ddca05fdf/propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54", size = 281947, upload-time = "2025-02-20T19:02:27.838Z" }, - { url = "https://files.pythonhosted.org/packages/cd/72/b564be7411b525d11757b713c757c21cd4dc13b6569c3b2b8f6d3c96fd5e/propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121", size = 268072, upload-time = "2025-02-20T19:02:29.594Z" }, - { url = "https://files.pythonhosted.org/packages/37/68/d94649e399e8d7fc051e5a4f2334efc567993525af083db145a70690a121/propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e", size = 275190, upload-time = "2025-02-20T19:02:32.255Z" }, - { url = "https://files.pythonhosted.org/packages/d8/3c/446e125f5bbbc1922964dd67cb541c01cdb678d811297b79a4ff6accc843/propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e", size = 254145, upload-time = "2025-02-20T19:02:33.932Z" }, - { url = "https://files.pythonhosted.org/packages/f4/80/fd3f741483dc8e59f7ba7e05eaa0f4e11677d7db2077522b92ff80117a2a/propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a", size = 257163, upload-time = "2025-02-20T19:02:35.675Z" }, - { url = "https://files.pythonhosted.org/packages/dc/cf/6292b5ce6ed0017e6a89024a827292122cc41b6259b30ada0c6732288513/propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac", size = 280249, upload-time = "2025-02-20T19:02:38.406Z" }, - { url = "https://files.pythonhosted.org/packages/e8/f0/fd9b8247b449fe02a4f96538b979997e229af516d7462b006392badc59a1/propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e", size = 288741, upload-time = "2025-02-20T19:02:40.149Z" }, - { url = "https://files.pythonhosted.org/packages/64/71/cf831fdc2617f86cfd7f414cfc487d018e722dac8acc098366ce9bba0941/propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf", size = 277061, upload-time = "2025-02-20T19:02:42.309Z" }, - { url = "https://files.pythonhosted.org/packages/42/78/9432542a35d944abeca9e02927a0de38cd7a298466d8ffa171536e2381c3/propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863", size = 42252, upload-time = "2025-02-20T19:02:44.447Z" }, - { url = "https://files.pythonhosted.org/packages/6f/45/960365f4f8978f48ebb56b1127adf33a49f2e69ecd46ac1f46d6cf78a79d/propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46", size = 46425, upload-time = "2025-02-20T19:02:48.071Z" }, - { url = "https://files.pythonhosted.org/packages/b5/35/6c4c6fc8774a9e3629cd750dc24a7a4fb090a25ccd5c3246d127b70f9e22/propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043", size = 12101, upload-time = "2025-02-20T19:03:27.202Z" }, +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, + { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, + { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, + { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, + { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, + { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, + { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, + { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, + { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, + { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, + { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, + { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, + { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, + { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, + { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, ] [[package]] @@ -1522,12 +1471,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e4/06/43084e6cbd4b3bc0e80f6be743b2e79fbc6eed8de9ad8c629939fa55d972/pymdown_extensions-10.16.1-py3-none-any.whl", hash = "sha256:d6ba157a6c03146a7fb122b2b9a121300056384eafeec9c9f9e584adfdb2a32d", size = 266178, upload-time = "2025-07-28T16:19:31.401Z" }, ] -[[package]] -name = "pymicro-vad" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/0f/a92acea368e2b37fbc706f6d049f04557497d981316a2f428b26f14666a9/pymicro_vad-1.0.1.tar.gz", hash = "sha256:60e0508b338b694c7ad71c633c0da6fcd2678a88abb8e948b80fa68934965111", size = 135575, upload-time = "2024-07-31T20:04:04.619Z" } - [[package]] name = "pyobjc-core" version = "12.0" @@ -1581,14 +1524,14 @@ wheels = [ [[package]] name = "pyopenssl" -version = "25.0.0" +version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/26/e25b4a374b4639e0c235527bbe31c0524f26eda701d79456a7e1877f4cc5/pyopenssl-25.0.0.tar.gz", hash = "sha256:cd2cef799efa3936bb08e8ccb9433a575722b9dd986023f1cabc4ae64e9dac16", size = 179573, upload-time = "2025-01-12T17:22:48.897Z" } +sdist = { url = "https://files.pythonhosted.org/packages/04/8c/cd89ad05804f8e3c17dea8f178c3f40eeab5694c30e0c9f5bcd49f576fc3/pyopenssl-25.1.0.tar.gz", hash = "sha256:8d031884482e0c67ee92bf9a4d8cceb08d92aba7136432ffb0703c5280fc205b", size = 179937, upload-time = "2025-05-17T16:28:31.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/d7/eb76863d2060dcbe7c7e6cccfd95ac02ea0b9acc37745a0d99ff6457aefb/pyOpenSSL-25.0.0-py3-none-any.whl", hash = "sha256:424c247065e46e76a37411b9ab1782541c23bb658bf003772c3405fbaa128e90", size = 56453, upload-time = "2025-01-12T17:22:43.44Z" }, + { url = "https://files.pythonhosted.org/packages/80/28/2659c02301b9500751f8d42f9a6632e1508aa5120de5e43042b8b30f8d5d/pyopenssl-25.1.0-py3-none-any.whl", hash = "sha256:2b11f239acc47ac2e5aca04fd7fa829800aeee22a2eb30d744572a157bd8a1ab", size = 56771, upload-time = "2025-05-17T16:28:29.197Z" }, ] [[package]] @@ -1606,12 +1549,6 @@ version = "0.1.6.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/08/64/a99f27d3b4347486c7bfc0aa516016c46dc4c0f380ffccbd742a61af1eda/PyRIC-0.1.6.3.tar.gz", hash = "sha256:b539b01cafebd2406c00097f94525ea0f8ecd1dd92f7731f43eac0ef16c2ccc9", size = 870401, upload-time = "2016-12-04T07:54:48.374Z" } -[[package]] -name = "pyspeex-noise" -version = "1.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/1d/7d2ebb8f73c2b2e929b4ba5370b35dbc91f37268ea53f4b6acd9afa532cb/pyspeex_noise-1.0.2.tar.gz", hash = "sha256:56a888ca2ef7fdea2316aa7fad3636d2fcf5f4450f3a0db58caa7c10a614b254", size = 49882, upload-time = "2024-08-27T17:00:34.859Z" } - [[package]] name = "pytablewriter" version = "0.61.0" @@ -1654,15 +1591,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051, upload-time = "2024-02-08T18:32:43.911Z" }, ] -[[package]] -name = "pyturbojpeg" -version = "1.7.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8b/ba/37c075c7cc86b89a22db4ac46c2e4f444666f9a43975a512b7cf70ced2fd/PyTurboJPEG-1.7.5.tar.gz", hash = "sha256:5dd5f40dbf4159f41b6abaa123733910e8b1182df562b6ddb768991868b487d3", size = 12065, upload-time = "2024-07-28T08:34:03.778Z" } - [[package]] name = "pytz" version = "2025.2" @@ -1701,9 +1629,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, ] +[[package]] +name = "regex" +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, +] + [[package]] name = "requests" -version = "2.32.3" +version = "2.32.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1711,9 +1662,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, ] [[package]] @@ -1766,6 +1717,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/e0/b93a18e9bb7f7d2573a9c6819d42d996851edde0b0406d017067d7d23a0a/securetar-2025.2.1-py3-none-any.whl", hash = "sha256:760ad9d93579d5923f3d0da86e0f185d0f844cf01795a8754539827bb6a1bab4", size = 11545, upload-time = "2025-02-25T14:17:50.832Z" }, ] +[[package]] +name = "sentence-stream" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/61/51918209769d7373c9bcaecac6222fb494b1d1f272e818e515e5129ef89c/sentence_stream-1.1.0.tar.gz", hash = "sha256:a512604a9f43d4132e29ad04664e8b1778f4a20265799ac86e8d62d181009483", size = 9262, upload-time = "2025-07-24T15:37:37.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/c8/8e39ad90b52372ed3bd1254450ef69f55f7920a838f906e29a414ffcf4b2/sentence_stream-1.1.0-py3-none-any.whl", hash = "sha256:3fceb47673ff16f5e301d7d0935db18413f8f1143ba4aea7ea2d9f808c5f1436", size = 7989, upload-time = "2025-07-24T15:37:36.606Z" }, +] + [[package]] name = "setuptools" version = "80.9.0" @@ -1795,38 +1758,36 @@ wheels = [ [[package]] name = "snitun" -version = "0.40.0" +version = "0.44.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, - { name = "async-timeout" }, - { name = "attrs" }, { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9a/5d/c39d5dee7119017efa571e7ce09fcb4f098734cb367adab59bed497ae0e9/snitun-0.40.0.tar.gz", hash = "sha256:f5a70b3aab07524f196d27baf7a8f8774b3b00c442e91392539dd11dbd033c9c", size = 33111, upload-time = "2024-12-18T12:43:16.948Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/83/acef455bd45428b512148db8c67ffdbb5e3460ab4e036dd896de15db0e7b/snitun-0.44.0.tar.gz", hash = "sha256:b9f693568ea6a7da6a9fa459597a404c1657bfb9259eb076005a8eb1247df087", size = 41098, upload-time = "2025-07-22T21:42:19.373Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/07/9982bd349e7a1aef3f8077ccfcf7ee9b447bd70ccab8121ad786334a882a/snitun-0.40.0-py3-none-any.whl", hash = "sha256:dedb58d3042d13311142b55337ad6ce6ed339e43da9dca4c4c2c83df77c64ac0", size = 39122, upload-time = "2024-12-18T12:43:12.756Z" }, + { url = "https://files.pythonhosted.org/packages/c8/77/6b58e87ea1ced25cd90bb90e1def088485fae8e35771255943a4bd9c72ab/snitun-0.44.0-py3-none-any.whl", hash = "sha256:8c351ed936c9768d68b1dc5a33ad91c1b8d57cad09f29e73e0b19df0e573c08b", size = 48365, upload-time = "2025-07-22T21:42:18.013Z" }, ] [[package]] name = "sqlalchemy" -version = "2.0.39" +version = "2.0.41" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/8e/e77fcaa67f8b9f504b4764570191e291524575ddbfe78a90fc656d671fdc/sqlalchemy-2.0.39.tar.gz", hash = "sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22", size = 9644602, upload-time = "2025-03-11T18:27:09.744Z" } +sdist = { url = "https://files.pythonhosted.org/packages/63/66/45b165c595ec89aa7dcc2c1cd222ab269bc753f1fc7a1e68f8481bd957bf/sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9", size = 9689424, upload-time = "2025-05-14T17:10:32.339Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/47/55778362642344324a900b6b2b1b26f7f02225b374eb93adc4a363a2d8ae/sqlalchemy-2.0.39-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87", size = 2102484, upload-time = "2025-03-11T19:21:54.018Z" }, - { url = "https://files.pythonhosted.org/packages/1b/e1/f5f26f67d095f408138f0fb2c37f827f3d458f2ae51881546045e7e55566/sqlalchemy-2.0.39-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716", size = 2092955, upload-time = "2025-03-11T19:21:55.658Z" }, - { url = "https://files.pythonhosted.org/packages/c5/c2/0db0022fc729a54fc7aef90a3457bf20144a681baef82f7357832b44c566/sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4", size = 3179367, upload-time = "2025-03-11T19:09:31.059Z" }, - { url = "https://files.pythonhosted.org/packages/33/b7/f33743d87d0b4e7a1f12e1631a4b9a29a8d0d7c0ff9b8c896d0bf897fb60/sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6b0a1c7ed54a5361aaebb910c1fa864bae34273662bb4ff788a527eafd6e14d", size = 3192705, upload-time = "2025-03-11T19:32:50.795Z" }, - { url = "https://files.pythonhosted.org/packages/c9/74/6814f31719109c973ddccc87bdfc2c2a9bc013bec64a375599dc5269a310/sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e", size = 3125927, upload-time = "2025-03-11T19:09:32.678Z" }, - { url = "https://files.pythonhosted.org/packages/e8/6b/18f476f4baaa9a0e2fbc6808d8f958a5268b637c8eccff497bf96908d528/sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c08a972cbac2a14810463aec3a47ff218bb00c1a607e6689b531a7c589c50723", size = 3154055, upload-time = "2025-03-11T19:32:53.344Z" }, - { url = "https://files.pythonhosted.org/packages/b4/60/76714cecb528da46bc53a0dd36d1ccef2f74ef25448b630a0a760ad07bdb/sqlalchemy-2.0.39-cp313-cp313-win32.whl", hash = "sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7", size = 2075315, upload-time = "2025-03-11T18:43:16.946Z" }, - { url = "https://files.pythonhosted.org/packages/5b/7c/76828886d913700548bac5851eefa5b2c0251ebc37921fe476b93ce81b50/sqlalchemy-2.0.39-cp313-cp313-win_amd64.whl", hash = "sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0", size = 2099175, upload-time = "2025-03-11T18:43:18.141Z" }, - { url = "https://files.pythonhosted.org/packages/7b/0f/d69904cb7d17e65c65713303a244ec91fd3c96677baf1d6331457fd47e16/sqlalchemy-2.0.39-py3-none-any.whl", hash = "sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f", size = 1898621, upload-time = "2025-03-11T19:20:33.027Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ad/2e1c6d4f235a97eeef52d0200d8ddda16f6c4dd70ae5ad88c46963440480/sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443", size = 2115491, upload-time = "2025-05-14T17:55:31.177Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8d/be490e5db8400dacc89056f78a52d44b04fbf75e8439569d5b879623a53b/sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc", size = 2102827, upload-time = "2025-05-14T17:55:34.921Z" }, + { url = "https://files.pythonhosted.org/packages/a0/72/c97ad430f0b0e78efaf2791342e13ffeafcbb3c06242f01a3bb8fe44f65d/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1", size = 3225224, upload-time = "2025-05-14T17:50:41.418Z" }, + { url = "https://files.pythonhosted.org/packages/5e/51/5ba9ea3246ea068630acf35a6ba0d181e99f1af1afd17e159eac7e8bc2b8/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a", size = 3230045, upload-time = "2025-05-14T17:51:54.722Z" }, + { url = "https://files.pythonhosted.org/packages/78/2f/8c14443b2acea700c62f9b4a8bad9e49fc1b65cfb260edead71fd38e9f19/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d", size = 3159357, upload-time = "2025-05-14T17:50:43.483Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b2/43eacbf6ccc5276d76cea18cb7c3d73e294d6fb21f9ff8b4eef9b42bbfd5/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23", size = 3197511, upload-time = "2025-05-14T17:51:57.308Z" }, + { url = "https://files.pythonhosted.org/packages/fa/2e/677c17c5d6a004c3c45334ab1dbe7b7deb834430b282b8a0f75ae220c8eb/sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f", size = 2082420, upload-time = "2025-05-14T17:55:52.69Z" }, + { url = "https://files.pythonhosted.org/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df", size = 2108329, upload-time = "2025-05-14T17:55:54.495Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fc/9ba22f01b5cdacc8f5ed0d22304718d2c758fce3fd49a5372b886a86f37c/sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576", size = 1911224, upload-time = "2025-05-14T17:39:42.154Z" }, ] [[package]] @@ -1946,22 +1907,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/1d/c43d3e1bda52a321f6cde3526b3634602958dc8ccf1f20fd6616767fd1a1/ulid_transform-1.4.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:9b1429ca7403696b290e4e97ffadbf8ed0b7470a97ad7e273372c3deae5bfb2f", size = 51566, upload-time = "2025-03-07T10:44:00.79Z" }, ] -[[package]] -name = "unicode-rbnf" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/1f/d952ba97832647e608700c36b22d1c4476016076c9ed1ce74ae814bea55a/unicode_rbnf-2.4.0.tar.gz", hash = "sha256:6d2f12a7581c69ea6218ee61fafcd2da46e1f9986bdcd0964c5151f7c2a938ac", size = 89069, upload-time = "2025-10-07T20:59:41.3Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/21/82f5d435808cba330668a8b69efb180e3ef9739d4998e8cd0381e8c9cb23/unicode_rbnf-2.4.0-py3-none-any.whl", hash = "sha256:0176b30ac9b7b84008d7dc0f23078055dc10d2671fdadfab5747943243e20e2d", size = 141691, upload-time = "2025-10-07T20:59:40.139Z" }, -] - [[package]] name = "urllib3" -version = "1.26.20" +version = "2.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380, upload-time = "2024-08-29T15:43:11.37Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225, upload-time = "2024-08-29T15:43:08.921Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] [[package]] @@ -1975,27 +1927,28 @@ wheels = [ [[package]] name = "uv" -version = "0.6.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/32/ffa984c2ecbcf48d0ae813adf1aad79b3ecb5ffc743362088755d64ae3be/uv-0.6.10.tar.gz", hash = "sha256:cbbb03deb30af457cd93ad299ee5c3258ade3d900b4dee1af936c8a6d87d5bcb", size = 3109190, upload-time = "2025-03-26T01:08:35.208Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/5a/5ef9324c333478608eaca8c97a374a869b861a9a614c1e6695045e06d90c/uv-0.6.10-py3-none-linux_armv6l.whl", hash = "sha256:06932d36f1afaf611522a6a7ec361dac48dc67a1147d24e9eadee9703b15faaf", size = 15825875, upload-time = "2025-03-26T01:07:49.96Z" }, - { url = "https://files.pythonhosted.org/packages/f7/2f/001f6bb4342ba50cf921bd4a338ea40e5228ea6a817bd3101fbabaf010dd/uv-0.6.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e5c2ba1922c47a245d7393465fcee942df5a8bd8b80489a7b8860ba9d60102f9", size = 15967139, upload-time = "2025-03-26T01:07:53.521Z" }, - { url = "https://files.pythonhosted.org/packages/36/6b/f66dcd28508bceed7cff48efb9dfe62a50a40a0685c41fb5e6ecd45f33cd/uv-0.6.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd8a4bcfd33a0dcae3fc0936bff8602f74e5719cf839e3df233059a0b8c8330d", size = 14796758, upload-time = "2025-03-26T01:07:56.269Z" }, - { url = "https://files.pythonhosted.org/packages/5a/a2/13eb03e8691b098f9ee63c4d3fa3a054c48bfa05a0a52aec3df33ab52376/uv-0.6.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:4dd20c47898c15ebd4b5f48101062ea248e32513bfc61fc04bc822abfe39ce8a", size = 15252527, upload-time = "2025-03-26T01:07:58.728Z" }, - { url = "https://files.pythonhosted.org/packages/58/90/053bde333fbf9030dff1354797bd74ce3624235bcf59d7558397749a88c1/uv-0.6.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:950c9cd7b75f67e25760d2f43ad4b0ee3f8c6724fe0a9cf9eff948b3044b6a6d", size = 15560957, upload-time = "2025-03-26T01:08:01.188Z" }, - { url = "https://files.pythonhosted.org/packages/34/80/feb9ecc8ab8f9e1968d6783dd47e7ebd1dfcd0231c8b7b0efd7204625cec/uv-0.6.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acca1dca7be342b2b8e26e509aa07c3144cb009788140eee045da2aad6a0c6fe", size = 16249302, upload-time = "2025-03-26T01:08:03.734Z" }, - { url = "https://files.pythonhosted.org/packages/0f/14/9a2e40e25fba7b550cb57cce62a07ddf28350cb53e9e8bd2e70c0fbacdbb/uv-0.6.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:13ac09945976dc0df0edde7e4ba3a46107036a114117c8ff84916e55216c2e32", size = 17196146, upload-time = "2025-03-26T01:08:06.129Z" }, - { url = "https://files.pythonhosted.org/packages/5e/05/5c9cd846243aca204f96c2da13da0fb38b6143eb3827dedea0e1dc1bcf1c/uv-0.6.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:145e75b99d6b7bdce8e454a851cfcd5605ff0491d568244c66fa75ca6b071bd6", size = 16944298, upload-time = "2025-03-26T01:08:08.827Z" }, - { url = "https://files.pythonhosted.org/packages/d2/14/63233a3143535a6df34ee6dc8246ef09ee79d99b902a6cc1ee179c1898f9/uv-0.6.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666d9fe312c810bba77633dbd463dc85f5a6a0d07905726a014dc53d07c774d9", size = 21226376, upload-time = "2025-03-26T01:08:11.488Z" }, - { url = "https://files.pythonhosted.org/packages/0a/d3/7e881e2a391203a7567cf03c72213701e63923591d2072c4e7fe694c919f/uv-0.6.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b98e8884093cbfb1a1cc3f855aa22f97ec8da1a87e0e761800e165d4f9224a45", size = 16621313, upload-time = "2025-03-26T01:08:14.435Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a9/124aa76690a04cf30344386358b772cdede17d84660ae1dce8643bf64939/uv-0.6.10-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:e8a8a75cf34c0814c1eabdbe651741d44fb125a6dcbe159b2da02871bbfdec7e", size = 15461518, upload-time = "2025-03-26T01:08:17.002Z" }, - { url = "https://files.pythonhosted.org/packages/ef/97/19813f2ec2faac77da5548c35d6ae039d044b973ecbb0732e3f07662fd36/uv-0.6.10-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:5260f52386e217615553f2f42740ce2f64ba439ff0fd502dc5b06250eb8ae613", size = 15524130, upload-time = "2025-03-26T01:08:19.392Z" }, - { url = "https://files.pythonhosted.org/packages/09/3f/5637bbf27ac145a09ea8eba8e0c926f7a3fe8fc4b3b1c91131c4558f4ec2/uv-0.6.10-py3-none-musllinux_1_1_i686.whl", hash = "sha256:603aebbaf6be938120c73fd36e9fd85f5e1b671d3d4638b3086f478e2bb423d9", size = 15901256, upload-time = "2025-03-26T01:08:22.141Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9b/2c688a897efad60d6e0587027968c1fdb0a63f70a8bef33d0b8154cc0fcd/uv-0.6.10-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d1f1bc7d94a4a7fdd75142be71b6bf2d7e01282f322721da185d711f065d7b80", size = 16746279, upload-time = "2025-03-26T01:08:24.916Z" }, - { url = "https://files.pythonhosted.org/packages/75/d4/df57d3f40c93c21fceed94156da41183daabd15422506e0fe73236c458a1/uv-0.6.10-py3-none-win32.whl", hash = "sha256:df6560256b93441c70ea2c062975bce2307a32de280f103cedb8db4a0f542348", size = 15953827, upload-time = "2025-03-26T01:08:27.395Z" }, - { url = "https://files.pythonhosted.org/packages/8a/21/a71c95c85624544c56695ae2469745bbda834e77dfc1e29d76711409eda5/uv-0.6.10-py3-none-win_amd64.whl", hash = "sha256:d795721fdd32e0471c952b7cb02a030657b6e67625fe836f4df14a3ae4aa4921", size = 17425178, upload-time = "2025-03-26T01:08:29.898Z" }, - { url = "https://files.pythonhosted.org/packages/ce/07/e6ffe467e1e365f7dd7863c4d505b1941af8cf69c494d0dbda08ba907043/uv-0.6.10-py3-none-win_arm64.whl", hash = "sha256:5188dc7041f4166bf64182d76c32c873f750259b6e4621a1400c26ebeea8c8dd", size = 16169219, upload-time = "2025-03-26T01:08:32.812Z" }, +version = "0.8.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/a1/4dea87c10875b441d906f82df42d725a4a04c2e8ae720d9fa01e1f75e3dc/uv-0.8.9.tar.gz", hash = "sha256:54d76faf5338d1e5643a32b048c600de0cdaa7084e5909106103df04f3306615", size = 3478291, upload-time = "2025-08-12T02:32:37.187Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/d8/a2a24d30660b5f05f86699f86b642b1193bea1017e77e5e5d3e1c64f7bcc/uv-0.8.9-py3-none-linux_armv6l.whl", hash = "sha256:4633c693c79c57a77c52608cbca8a6bb17801bfa223326fbc5c5142654c23cc3", size = 18477020, upload-time = "2025-08-12T02:31:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/4d/21/937e590fb08ce4c82503fddb08b54613c0d42dd06c660460f8f0552dd3a7/uv-0.8.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1cdc11cbc81824e51ebb1bac35745a79048557e869ef9da458e99f1c3a96c7f9", size = 18486975, upload-time = "2025-08-12T02:31:54.804Z" }, + { url = "https://files.pythonhosted.org/packages/60/a8/e6fc3e204731aa26b09934bbdecc8d6baa58a2d9e55b59b13130bacf8e52/uv-0.8.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7b20ee83e3bf294e0b1347d0b27c56ea1a4fa7eeff4361fbf1f39587d4273059", size = 17178749, upload-time = "2025-08-12T02:31:57.251Z" }, + { url = "https://files.pythonhosted.org/packages/b2/3e/3104a054bb6e866503a13114ee969d4b66227ebab19a38e3468f36c03a87/uv-0.8.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:3418315e624f60a1c4ed37987b35d5ff0d03961d380e7e7946a3378499d5d779", size = 17790897, upload-time = "2025-08-12T02:31:59.451Z" }, + { url = "https://files.pythonhosted.org/packages/50/e6/ab64cca644f40bf85fb9b3a9050aad25af7882a1d774a384fc473ef9c697/uv-0.8.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7efe01b3ed9816e07e6cd4e088472a558a1d2946177f31002b4c42cd55cb4604", size = 18124831, upload-time = "2025-08-12T02:32:02.151Z" }, + { url = "https://files.pythonhosted.org/packages/08/d1/68a001e3ad5d0601ea9ff348b54a78c8ba87fd2a6b6b5e27b379f6f3dff0/uv-0.8.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e571132495d7ab24d2f0270c559d6facd4224745d9db7dff8c20ec0c71ae105a", size = 18924774, upload-time = "2025-08-12T02:32:04.479Z" }, + { url = "https://files.pythonhosted.org/packages/ed/71/1b252e523eb875aa4ac8d06d5f8df175fa2d29e13da347d5d4823bce6c47/uv-0.8.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:67507c66837d8465daaad9f2ccd7da7af981d8c94eb8e32798f62a98c28de82d", size = 20256335, upload-time = "2025-08-12T02:32:07.12Z" }, + { url = "https://files.pythonhosted.org/packages/30/fc/062a25088b30a0fd27e4cc46baa272dd816acdec252b120d05a16d63170a/uv-0.8.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3162f495805a26fba5aacbee49c8650e1e74313c7a2e6df6aec5de9d1299087", size = 19920018, upload-time = "2025-08-12T02:32:10.041Z" }, + { url = "https://files.pythonhosted.org/packages/d8/55/90a0dc35938e68509ff8e8a49ff45b0fd13f3a44752e37d8967cd9d19316/uv-0.8.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60eb70afeb1c66180e12a15afd706bcc0968dbefccf7ef6e5d27a1aaa765419b", size = 19235553, upload-time = "2025-08-12T02:32:12.361Z" }, + { url = "https://files.pythonhosted.org/packages/ae/a4/2db5939a3a993a06bca0a42e2120b4385bf1a4ff54242780701759252052/uv-0.8.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011d2b2d4781555f7f7d29d2f0d6b2638fc60eeff479406ed570052664589e6a", size = 19259174, upload-time = "2025-08-12T02:32:14.697Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c9/c52249b5f40f8eb2157587ae4b997942335e4df312dfb83b16b5ebdecc61/uv-0.8.9-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:97621843e087a68c0b4969676367d757e1de43c00a9f554eb7da35641bdff8a2", size = 18048069, upload-time = "2025-08-12T02:32:16.955Z" }, + { url = "https://files.pythonhosted.org/packages/d0/ca/524137719fb09477e57c5983fa8864f824f5858b29fc679c0416634b79f0/uv-0.8.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b1be6a7b49d23b75d598691cc5c065a9e3cdf5e6e75d7b7f42f24d758ceef3c4", size = 18943440, upload-time = "2025-08-12T02:32:19.212Z" }, + { url = "https://files.pythonhosted.org/packages/f0/b8/877bf9a52207023a8bf9b762bed3853697ed71c5c9911a4e31231de49a23/uv-0.8.9-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:91598361309c3601382c552dc22256f70b2491ad03357b66caa4be6fdf1111dd", size = 18075581, upload-time = "2025-08-12T02:32:21.732Z" }, + { url = "https://files.pythonhosted.org/packages/96/de/272d4111ff71765bcbfd3ecb4d4fff4073f08cc38b3ecdb7272518c3fe93/uv-0.8.9-py3-none-musllinux_1_1_i686.whl", hash = "sha256:dc81df9dd7571756e34255592caab92821652face35c3f52ad05efaa4bcc39d3", size = 18420275, upload-time = "2025-08-12T02:32:24.488Z" }, + { url = "https://files.pythonhosted.org/packages/90/15/fecfc6665d1bfc5c7dbd32ff1d63413ac43d7f6d16d76fdc4d2513cbe807/uv-0.8.9-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:9ef728e0a5caa2bb129c009a68b30819552e7addf934916a466116e302748bed", size = 19354288, upload-time = "2025-08-12T02:32:27.714Z" }, + { url = "https://files.pythonhosted.org/packages/52/b5/9fef88ac0cc3ca71ff718fa7d7e90c1b3a8639b041c674825aae00d24bf5/uv-0.8.9-py3-none-win32.whl", hash = "sha256:a347c2f2630a45a3b7ceae28a78a528137edfec4847bb29da1561bd8d1f7d254", size = 18197270, upload-time = "2025-08-12T02:32:30.288Z" }, + { url = "https://files.pythonhosted.org/packages/04/0a/dacd483c9726d2b74e42ee1f186aabab508222114f3099a7610ad0f78004/uv-0.8.9-py3-none-win_amd64.whl", hash = "sha256:dc12048cdb53210d0c7218bb403ad30118b1fe8eeff3fbcc184c13c26fcc47d4", size = 20221458, upload-time = "2025-08-12T02:32:32.706Z" }, + { url = "https://files.pythonhosted.org/packages/ac/7e/f2b35278304673dcf9e8fe84b6d15531d91c59530dcf7919111f39a8d28f/uv-0.8.9-py3-none-win_arm64.whl", hash = "sha256:53332de28e9ee00effb695a15cdc70b2455d6b5f6b596d556076b5dd1fd3aa26", size = 18805689, upload-time = "2025-08-12T02:32:35.036Z" }, ] [[package]] @@ -2009,26 +1962,26 @@ wheels = [ [[package]] name = "voluptuous-openapi" -version = "0.0.6" +version = "0.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "voluptuous" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1f/6f/1075651d387c1570e4603080bdf0aa15aa254c21efb2688fdb18544cf4b9/voluptuous_openapi-0.0.6.tar.gz", hash = "sha256:4078c2acef23e04ceeab1ba58252590fcdc3ba6e3ed34521e8595374ab4de884", size = 13190, upload-time = "2025-01-07T07:19:07.266Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/20/ed87b130ae62076b731521b3c4bc502e6ba8cc92def09954e4e755934804/voluptuous_openapi-0.1.0.tar.gz", hash = "sha256:84bc44107c472ba8782f7a4cb342d19d155d5fe7f92367f092cd96cc850ff1b7", size = 14656, upload-time = "2025-05-11T21:10:14.876Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5c/331c21122901d4f5f4f6869683ab9859a08498074cee6075ff3eac3027a6/voluptuous_openapi-0.0.6-py3-none-any.whl", hash = "sha256:3561bbe5f46483f4cd9f631a0bd4a3ac3d7d74bab24f41bcd09b52501f712d5e", size = 9249, upload-time = "2025-01-07T07:19:05.948Z" }, + { url = "https://files.pythonhosted.org/packages/68/3b/9e689d9fc68f0032bf5b7cbf767fc8bd4771d75cddaf01267fcc05490061/voluptuous_openapi-0.1.0-py3-none-any.whl", hash = "sha256:c3aac740286d368c90a99e007d55ddca7fcddf790d218c60ee0eeec2fcd3db2b", size = 9967, upload-time = "2025-05-11T21:10:13.647Z" }, ] [[package]] name = "voluptuous-serialize" -version = "2.6.0" +version = "2.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "voluptuous" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/09/c26b38ab35d9f61e9bf5c3e805215db1316dd73c77569b47ab36a40d19b1/voluptuous-serialize-2.6.0.tar.gz", hash = "sha256:79acdc58239582a393144402d827fa8efd6df0f5350cdc606d9242f6f9bca7c4", size = 7562, upload-time = "2023-02-15T21:09:08.077Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/70/03a9b61324e1bb8b16682455b8b953bccd1001a28e43478c86f539e26285/voluptuous_serialize-2.7.0.tar.gz", hash = "sha256:d0da959f2fd93c8f1eb779c5d116231940493b51020c2c1026bab76eb56cd09e", size = 9202, upload-time = "2025-08-17T10:43:04.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/86/355e1c65934760e2fb037219f1f360562567cf6731d281440c1d57d36856/voluptuous_serialize-2.6.0-py3-none-any.whl", hash = "sha256:85a5c8d4d829cb49186c1b5396a8a517413cc5938e1bb0e374350190cd139616", size = 6819, upload-time = "2023-02-15T21:09:06.512Z" }, + { url = "https://files.pythonhosted.org/packages/f7/41/d536d9cf39821c35cc13aff403728e60e32b2fd711c240b6b9980af1c03f/voluptuous_serialize-2.7.0-py3-none-any.whl", hash = "sha256:ee3ebecace6136f38d0bf8c20ee97155db2486c6b2d0795563fafd04a519e76f", size = 7850, upload-time = "2025-08-17T10:43:03.498Z" }, ] [[package]] @@ -2179,54 +2132,72 @@ wheels = [ [[package]] name = "yarl" -version = "1.18.3" +version = "1.20.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062, upload-time = "2024-12-01T20:35:23.292Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/c7/c790513d5328a8390be8f47be5d52e141f78b66c6c48f48d241ca6bd5265/yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", size = 140789, upload-time = "2024-12-01T20:34:11.414Z" }, - { url = "https://files.pythonhosted.org/packages/30/aa/a2f84e93554a578463e2edaaf2300faa61c8701f0898725842c704ba5444/yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", size = 94144, upload-time = "2024-12-01T20:34:13.485Z" }, - { url = "https://files.pythonhosted.org/packages/c6/fc/d68d8f83714b221a85ce7866832cba36d7c04a68fa6a960b908c2c84f325/yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", size = 91974, upload-time = "2024-12-01T20:34:15.234Z" }, - { url = "https://files.pythonhosted.org/packages/56/4e/d2563d8323a7e9a414b5b25341b3942af5902a2263d36d20fb17c40411e2/yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", size = 333587, upload-time = "2024-12-01T20:34:17.358Z" }, - { url = "https://files.pythonhosted.org/packages/25/c9/cfec0bc0cac8d054be223e9f2c7909d3e8442a856af9dbce7e3442a8ec8d/yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", size = 344386, upload-time = "2024-12-01T20:34:19.842Z" }, - { url = "https://files.pythonhosted.org/packages/ab/5d/4c532190113b25f1364d25f4c319322e86232d69175b91f27e3ebc2caf9a/yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", size = 345421, upload-time = "2024-12-01T20:34:21.975Z" }, - { url = "https://files.pythonhosted.org/packages/23/d1/6cdd1632da013aa6ba18cee4d750d953104a5e7aac44e249d9410a972bf5/yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", size = 339384, upload-time = "2024-12-01T20:34:24.717Z" }, - { url = "https://files.pythonhosted.org/packages/9a/c4/6b3c39bec352e441bd30f432cda6ba51681ab19bb8abe023f0d19777aad1/yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", size = 326689, upload-time = "2024-12-01T20:34:26.886Z" }, - { url = "https://files.pythonhosted.org/packages/23/30/07fb088f2eefdc0aa4fc1af4e3ca4eb1a3aadd1ce7d866d74c0f124e6a85/yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", size = 345453, upload-time = "2024-12-01T20:34:29.605Z" }, - { url = "https://files.pythonhosted.org/packages/63/09/d54befb48f9cd8eec43797f624ec37783a0266855f4930a91e3d5c7717f8/yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", size = 341872, upload-time = "2024-12-01T20:34:31.454Z" }, - { url = "https://files.pythonhosted.org/packages/91/26/fd0ef9bf29dd906a84b59f0cd1281e65b0c3e08c6aa94b57f7d11f593518/yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", size = 347497, upload-time = "2024-12-01T20:34:34.004Z" }, - { url = "https://files.pythonhosted.org/packages/d9/b5/14ac7a256d0511b2ac168d50d4b7d744aea1c1aa20c79f620d1059aab8b2/yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", size = 359981, upload-time = "2024-12-01T20:34:36.624Z" }, - { url = "https://files.pythonhosted.org/packages/ca/b3/d493221ad5cbd18bc07e642894030437e405e1413c4236dd5db6e46bcec9/yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", size = 366229, upload-time = "2024-12-01T20:34:38.657Z" }, - { url = "https://files.pythonhosted.org/packages/04/56/6a3e2a5d9152c56c346df9b8fb8edd2c8888b1e03f96324d457e5cf06d34/yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", size = 360383, upload-time = "2024-12-01T20:34:40.501Z" }, - { url = "https://files.pythonhosted.org/packages/fd/b7/4b3c7c7913a278d445cc6284e59b2e62fa25e72758f888b7a7a39eb8423f/yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", size = 310152, upload-time = "2024-12-01T20:34:42.814Z" }, - { url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", size = 315723, upload-time = "2024-12-01T20:34:44.699Z" }, - { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109, upload-time = "2024-12-01T20:35:20.834Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, + { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, + { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, + { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, + { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, + { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, + { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, + { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, + { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, + { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, + { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, + { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, + { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, + { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, + { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, + { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, + { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, + { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, + { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, + { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, + { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, + { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, + { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, + { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, ] [[package]] name = "zeroconf" -version = "0.146.0" +version = "0.147.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ifaddr" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/ac/d4c67df0649c77f343e4976ef0a00e19a6e5c3342a6eaa6e64d7b853224f/zeroconf-0.146.0.tar.gz", hash = "sha256:a48010a1931acdba5b26e99326464788daeef96dcb7b9a44d1832352f76da49c", size = 161804, upload-time = "2025-03-05T01:47:18.095Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/eb/25e258fbd064e7b8f1497b9e345f29d6e44dd250a0fc5afd91aa04aafa57/zeroconf-0.146.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:faec552163f3007247ef9713fc817627d89844a782da8c1479b11ea3d3370684", size = 1840888, upload-time = "2025-03-05T02:20:56.799Z" }, - { url = "https://files.pythonhosted.org/packages/7b/1c/1fd373e225e7282c244003683740ca58bc39270cb79fa13b13435c6dc88a/zeroconf-0.146.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0fc7b22e33b9d5d81b5aee58af6447fc1cf9b11e04dc2a04e1a5d00b3ae4d23a", size = 1697122, upload-time = "2025-03-05T02:20:58.687Z" }, - { url = "https://files.pythonhosted.org/packages/bf/98/2a42f1f88f69b11db2524469e5dc6752dc819e4fe9b985e293be74b38dee/zeroconf-0.146.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6e24daeeb926f8c7d426c46082224786e26aa5b4ce9fb573133e52ff8bae81", size = 2143632, upload-time = "2025-03-05T02:21:00.927Z" }, - { url = "https://files.pythonhosted.org/packages/81/8c/6caf3a48575c2bcf7ba2739b2cda6f117a305c03e87b53d08f19c859fae3/zeroconf-0.146.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:9a798ea22c24a4148364f85b46ab33541072715bf8abccae2e3fd0c069f5808f", size = 2315076, upload-time = "2025-03-05T02:21:02.419Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b3/b86fa34f8d682b1bd3e144896b2c2cfb8a6c3308c1f773a7dcdb733d677b/zeroconf-0.146.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97a536e5b3d694e342bc908149342db2aae08a6f56466db63b6dffc26d2399ae", size = 2260655, upload-time = "2025-03-05T02:21:04.68Z" }, - { url = "https://files.pythonhosted.org/packages/06/2a/9b509a9d70c9f98b1b60f8d0002ac457df8f401325be6545ecb1f8071e8a/zeroconf-0.146.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f97a09c01424e2356c41b39f7c2fb7a743623c2d413a082e861030e28090aebb", size = 2097673, upload-time = "2025-03-05T02:21:06.287Z" }, - { url = "https://files.pythonhosted.org/packages/90/70/2fb1c0470fb4a230d9cd63e245b5d4bd349a19454d363499eb4cdee3b54a/zeroconf-0.146.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:55c2a0087847d5c8bc00cc1e85cb1d048e8b70b09b4e949a2b763f33389819bb", size = 2307311, upload-time = "2025-03-05T01:47:15.987Z" }, - { url = "https://files.pythonhosted.org/packages/64/c3/351b7c1d07c9bf43d75bbbf18f9d07f8081373e85865b5faa78b661ae882/zeroconf-0.146.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b87d01dc8d7d10b929cc63330cf2e0f726f105a57e8d86df5d946b93a0e6280f", size = 2297954, upload-time = "2025-03-05T02:21:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b17dda38b9c5b916b1491acb6f32044d198c89ee74074dec0a277f0d8f49/zeroconf-0.146.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f844214eed7b66c1db3ea4ab2dddf0d84b91c340d83b2721656f70efb8588ae4", size = 2152669, upload-time = "2025-03-05T02:21:09.702Z" }, - { url = "https://files.pythonhosted.org/packages/75/6c/ef97dcd5abdcfb6c4ea8a52d2cb08982541c43a9ec64dff1335ecc45a901/zeroconf-0.146.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cf9e85463a4fdeed8c5ea3b13e4a6c6de924d90b8b0982021e7331632f80192e", size = 2495779, upload-time = "2025-03-05T02:21:11.629Z" }, - { url = "https://files.pythonhosted.org/packages/90/f5/755bd701c69da699b6f0bd939972cd0978af6a7399174048a337de610f87/zeroconf-0.146.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fc1dd03301d370c21a8c5fbbe0a6a54a068a08384fa673d596c3f2424153aeca", size = 2459359, upload-time = "2025-03-05T02:21:13.346Z" }, - { url = "https://files.pythonhosted.org/packages/0c/24/12f936d8ec82e3ca14291e3c6f45f2a2b3d1139f5ae19670fd4624a66f86/zeroconf-0.146.0-cp313-cp313-win32.whl", hash = "sha256:b4e70e77a67b3f39e91b5c02df82ab49a54bfc4edb1aa5779e404a711938c5af", size = 1427510, upload-time = "2025-03-05T02:21:16.184Z" }, - { url = "https://files.pythonhosted.org/packages/49/bb/9ccf706c4f3dad7b72956d5123e2b228d0411a6f977f4db410ff6b8963c0/zeroconf-0.146.0-cp313-cp313-win_amd64.whl", hash = "sha256:5274ba298d2edd5d02bb3937181a1e82deef773075b04374eac149bd40fccd96", size = 1655847, upload-time = "2025-03-05T02:21:18.359Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/e2/78/f681afade2a4e7a9ade696cf3d3dcd9905e28720d74c16cafb83b5dd5c0a/zeroconf-0.147.0.tar.gz", hash = "sha256:f517375de6bf2041df826130da41dc7a3e8772176d3076a5da58854c7d2e8d7a", size = 163958, upload-time = "2025-05-03T16:24:54.207Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/83/c6ee14c962b79f616f8f987a52244e877647db3846007fc167f481a81b7d/zeroconf-0.147.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1deedbedea7402754b3a1a05a2a1c881443451ccd600b2a7f979e97dd9fcbe6d", size = 1841229, upload-time = "2025-05-03T16:59:17.783Z" }, + { url = "https://files.pythonhosted.org/packages/91/c0/42c08a8b2c5b6052d48a5517a5d05076b8ee2c0a458ea9bd5e0e2be38c01/zeroconf-0.147.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5c57d551e65a2a9b6333b685e3b074601f6e85762e4b4a490c663f1f2e215b24", size = 1697806, upload-time = "2025-05-03T16:59:20.083Z" }, + { url = "https://files.pythonhosted.org/packages/bf/79/d9b440786d62626f2ca4bd692b6c2bbd1e70e1124c56321bac6a2212a5eb/zeroconf-0.147.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:095bdb0cd369355ff919e3be930991b38557baaa8292d82f4a4a8567a3944f05", size = 2141482, upload-time = "2025-05-03T16:59:22.067Z" }, + { url = "https://files.pythonhosted.org/packages/48/12/ab7d31620892a7f4d446a3f0261ddb1198318348c039b4a5ec7d9d09579c/zeroconf-0.147.0-cp313-cp313-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:8ae0fe0bb947b3a128af586c76a16b5a7d027daa65e67637b042c745f9b136c4", size = 2315614, upload-time = "2025-05-03T16:59:24.091Z" }, + { url = "https://files.pythonhosted.org/packages/7b/48/2de072ee42e36328e1d80408b70eddf3df0a5b9640db188caa363b3e120f/zeroconf-0.147.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cbeea4d8d0c4f6eb5a82099d53f5729b628685039a44c1a84422080f8ec5b0d", size = 2259809, upload-time = "2025-05-03T16:59:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/02/ec/3344b1ed4e60b36dd73cb66c36299c83a356e853e728c68314061498e9cd/zeroconf-0.147.0-cp313-cp313-manylinux_2_31_armv7l.manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:728f82417800c5c5dd3298f65cf7a8fef1707123b457d3832dbdf17d38f68840", size = 2096364, upload-time = "2025-05-03T16:59:27.786Z" }, + { url = "https://files.pythonhosted.org/packages/cd/30/5f34363e2d3c25a78fc925edcc5d45d332296a756d698ccfc060bba8a7aa/zeroconf-0.147.0-cp313-cp313-manylinux_2_36_x86_64.whl", hash = "sha256:a2dc9ae96cd49b50d651a78204aafe9f41e907122dc98e719be5376b4dddec6f", size = 2307868, upload-time = "2025-05-03T16:24:52.178Z" }, + { url = "https://files.pythonhosted.org/packages/1b/a8/9b4242ae78bd271520e019faf47d8a2b36242b3b1a7fd47ee7510d380734/zeroconf-0.147.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9570ab3203cc4bd3ad023737ef4339558cdf1f33a5d45d76ed3fe77e5fa5f57", size = 2295063, upload-time = "2025-05-03T16:59:29.695Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e6/b63e4e09d71e94bfe0d30c6fc80b0e67e3845eb630bcfb056626db070776/zeroconf-0.147.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:fd783d9bac258e79d07e2bd164c1962b8f248579392b5078fd607e7bb6760b53", size = 2152284, upload-time = "2025-05-03T16:59:31.598Z" }, + { url = "https://files.pythonhosted.org/packages/72/12/42b990cb7ad997eb9f9fff15c61abff022adc44f5d1e96bd712ed6cd85ab/zeroconf-0.147.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b4acc76063cc379774db407dce0263616518bb5135057eb5eeafc447b3c05a81", size = 2498559, upload-time = "2025-05-03T16:59:33.444Z" }, + { url = "https://files.pythonhosted.org/packages/99/f9/080619bfcfc353deeb8cf7e813eaf73e8e28ff9a8ca7b97b9f0ecbf4d1d6/zeroconf-0.147.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:acc5334cb6cb98db3917bf9a3d6b6b7fdd205f8a74fd6f4b885abb4f61098857", size = 2456548, upload-time = "2025-05-03T16:59:35.721Z" }, + { url = "https://files.pythonhosted.org/packages/35/b6/a25b703f418200edd6932d56bbd32cbd087b828579cf223348fa778fb1ff/zeroconf-0.147.0-cp313-cp313-win32.whl", hash = "sha256:7c52c523aa756e67bf18d46db298a5964291f7d868b4a970163432e7d745b992", size = 1427188, upload-time = "2025-05-03T16:59:38.756Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e1/ba463435cdb0b38088eae56d508ec6128b9012f58cedab145b1b77e51316/zeroconf-0.147.0-cp313-cp313-win_amd64.whl", hash = "sha256:60f623af0e45fba69f5fe80d7b300c913afe7928fb43f4b9757f0f76f80f0d82", size = 1655531, upload-time = "2025-05-03T16:59:40.65Z" }, ] From e0d77bf2bafd764459d42aa27edf5c0df2e1c880 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:07:21 +0000 Subject: [PATCH 221/235] Enable ruff formatting --- .github/workflows/lint.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 9d6ad5277..627dc2b13 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -30,8 +30,7 @@ jobs: with: args: check --output-format=github - #TODO: Temporary disable until V3 - # - name: Ruff Format - # uses: astral-sh/ruff-action@v3 - # with: - # args: format --check --diff + - name: Ruff Format + uses: astral-sh/ruff-action@v3 + with: + args: format --check --diff From c65be4c6457b2902ddc2de8c10862682abea4e74 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:08:34 +0000 Subject: [PATCH 222/235] Ruff formatting --- custom_components/battery_notes/binary_sensor.py | 3 ++- custom_components/battery_notes/sensor.py | 9 +++++---- custom_components/battery_notes/store.py | 5 ++++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 50c513825..285073519 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -662,7 +662,8 @@ def __init__( @callback async def async_state_changed_listener( - self, event: Event[EventStateChangedData] | None = None # noqa: ARG002 + self, + event: Event[EventStateChangedData] | None = None, # noqa: ARG002 ) -> None: # pylint: disable=unused-argument """Handle child updates.""" diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index e73b42e7a..afcacac27 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -298,8 +298,7 @@ async def async_added_to_hass(self) -> None: """Handle added to Hass.""" await super().async_added_to_hass() - def _set_native_value(self, log_on_error=True): # noqa: ARG002 - + def _set_native_value(self, log_on_error=True): # noqa: ARG002 if last_replaced := self.coordinator.last_replaced: self._native_value = last_replaced @@ -385,7 +384,8 @@ def __init__( @callback async def async_state_changed_listener( - self, event: Event[EventStateChangedData] | None = None # noqa: ARG002 + self, + event: Event[EventStateChangedData] | None = None, # noqa: ARG002 ) -> None: # pylint: disable=unused-argument """Handle child updates.""" @@ -437,7 +437,8 @@ async def async_state_changed_listener( @callback async def async_state_reported_listener( - self, event: Event[EventStateReportedData] | None = None # noqa: ARG002 + self, + event: Event[EventStateReportedData] | None = None, # noqa: ARG002 ) -> None: """Handle child updates.""" diff --git a/custom_components/battery_notes/store.py b/custom_components/battery_notes/store.py index 53c2f4d20..831544bb4 100644 --- a/custom_components/battery_notes/store.py +++ b/custom_components/battery_notes/store.py @@ -52,7 +52,10 @@ class MigratableStore(Store): """Holds battery notes data.""" async def _async_migrate_func( - self, old_major_version: int, old_minor_version: int, data: dict # noqa: ARG002 + self, + old_major_version: int, + old_minor_version: int, + data: dict, # noqa: ARG002 ): # pylint: disable=arguments-renamed # pylint: disable=unused-argument From 215ca684131c3c4305b7c7f00a5b0fb7c2a7037b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:13:23 +0000 Subject: [PATCH 223/235] Lint --- custom_components/battery_notes/store.py | 6 +++--- pyproject.toml | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/custom_components/battery_notes/store.py b/custom_components/battery_notes/store.py index 831544bb4..3826cf1c1 100644 --- a/custom_components/battery_notes/store.py +++ b/custom_components/battery_notes/store.py @@ -53,9 +53,9 @@ class MigratableStore(Store): async def _async_migrate_func( self, - old_major_version: int, - old_minor_version: int, - data: dict, # noqa: ARG002 + old_major_version: int, # noqa: ARG002 + old_minor_version: int, # noqa: ARG002 + data: dict, ): # pylint: disable=arguments-renamed # pylint: disable=unused-argument diff --git a/pyproject.toml b/pyproject.toml index bd88c5e49..3622a2b66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ repository = "https://github.com/andrew-codechimp/HA-Battery-Notes" Changelog = "https://github.com/andrew-codechimp/HA-Battery-Notes/releases" [dependency-groups] -dev = [ +dev = [ "colorlog", "homeassistant==2025.9.0", "ruff", @@ -92,7 +92,6 @@ ignore = [ "ANN202", # Missing return type annotation for private function "ANN204", # Missing return type annotation for special method "ARG001", # Unused function argument - "ARG002", # Unused method argument "ARG004", # Unused static method argument "COM818", # Trailing comma on bare tuple prohibited "D204", # 1 blank line required after class docstring @@ -106,7 +105,6 @@ ignore = [ "I001", # Import block is un-sorted or un-formatted "INP001", # File is part of an implicit namespace package "PGH003", # Use specific rule codes when ignoring type issues - "PLR0912", # Too many branches "PLR0913", # Too many arguments in function definition "PLR0915", # Too many statements "PLR2004", # Magic value used in comparison From 768a7c14a70b2ad9839bd7d91ecea5b344c5cff5 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:25:12 +0000 Subject: [PATCH 224/235] Lint --- custom_components/battery_notes/__init__.py | 2 +- custom_components/battery_notes/config_flow.py | 2 +- custom_components/battery_notes/repairs.py | 2 +- pyproject.toml | 14 +++++--------- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index c7544a9f0..b5c82febe 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -185,7 +185,7 @@ async def async_setup_entry( ) @callback - async def _async_delayed_discovery(now: datetime) -> None: # pylint: disable=unused-argument + async def _async_delayed_discovery(now: datetime) -> None: # noqa: ARG001 """Update the library and do discovery.""" library_updater = LibraryUpdater(hass) await library_updater.copy_schema() diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index c4b4d67b1..3f53c36b4 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -157,7 +157,7 @@ class BatteryNotesFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): @staticmethod @callback - def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow: + def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow: # noqa: ARG004 # pylint: disable=unused-argument """Get the options flow for this handler.""" return OptionsFlowHandler() diff --git a/custom_components/battery_notes/repairs.py b/custom_components/battery_notes/repairs.py index ae97efe17..8f167fc12 100644 --- a/custom_components/battery_notes/repairs.py +++ b/custom_components/battery_notes/repairs.py @@ -57,7 +57,7 @@ async def async_step_confirm( async def async_create_fix_flow( - hass: HomeAssistant, # pylint: disable=unused-argument + hass: HomeAssistant, # noqa: ARG001 issue_id: str, data: dict[str, str | int | float | None] | None, ) -> RepairsFlow: diff --git a/pyproject.toml b/pyproject.toml index 3622a2b66..e7d1367d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,6 +82,11 @@ ignore = [ "W191", "RUF012", # Broken rule in some cases + # GitHub actions + "INP001", # File is part of an implicit namespace package + + # Project preference + "ERA001", # Found commented-out code "RUF001", # String contains ambiguous character "S101", # Use of assert detected "TC001", # Move application import into type checking @@ -91,19 +96,13 @@ ignore = [ "ANN201", # Missing return type annotation for public function "ANN202", # Missing return type annotation for private function "ANN204", # Missing return type annotation for special method - "ARG001", # Unused function argument - "ARG004", # Unused static method argument - "COM818", # Trailing comma on bare tuple prohibited - "D204", # 1 blank line required after class docstring "DTZ005", # The use of `datetime.datetime.now()` without `tz` argument is not allowed "EM101", # Exception must not use a string literal, assign to variable first "EM102", # Exception must not use an f-string literal, assign to variable first - "ERA001", # Found commented-out code "FBT001", # Boolean-typed positional argument in function definition "FBT002", # Boolean-typed positional argument in function definition "G004", # Logging statement uses f-string "I001", # Import block is un-sorted or un-formatted - "INP001", # File is part of an implicit namespace package "PGH003", # Use specific rule codes when ignoring type issues "PLR0913", # Too many arguments in function definition "PLR0915", # Too many statements @@ -118,7 +117,6 @@ ignore = [ "PYI041", # Use `float` instead of `int | float` "RET504", # Unnecessary assignment before `return` statement "RET505", # Unnecessary `else` after `return` statement - "RUF059", # Unpacked variable is never used "SIM102", # Use a single `if`-statement instead of nested `if`-statements "SIM103", # Return the condition directly "SLF001", # Private member accessed @@ -128,8 +126,6 @@ ignore = [ "TRY004", # Prefer `TypeError` exception for invalid type "TRY300", # Consider moving this statement to an `else` block "TRY400", # Use `logging.exception` instead of `logging.error` - "UP039", # Unnecessary parentheses after class name - "W292", # No newline at end of file ] From 2ce183aa2b092aa0ac0421fde34f88eed4fa43ce Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:33:26 +0000 Subject: [PATCH 225/235] Lint --- custom_components/battery_notes/__init__.py | 12 +++++++----- custom_components/battery_notes/binary_sensor.py | 2 +- pyproject.toml | 4 ---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index b5c82febe..3b093b0e0 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -255,18 +255,20 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> ) if not any( - entry.version < 3 and entry.source != SOURCE_IGNORE for entry in entries + entry.version < 3 # noqa: PLR2004 + and entry.source != SOURCE_IGNORE + for entry in entries ): return for entry in entries: - if entry.version == 3 and entry.unique_id == DOMAIN: + if entry.version == 3 and entry.unique_id == DOMAIN: # noqa: PLR2004 # We have a V3 entry, so we can use this as the base migrate_base_entry = entry break for entry in entries: - if entry.version >= 3: + if entry.version >= 3: # noqa: PLR2004 continue if entry.source == SOURCE_IGNORE: @@ -411,7 +413,7 @@ async def async_migrate_entry( config_entry.minor_version, ) - if config_entry.version > 3: + if config_entry.version > 3: # noqa: PLR2004 # This means the user has downgraded from a future version return False @@ -443,7 +445,7 @@ async def async_migrate_entry( 2, ) - if config_entry.version == 2 and config_entry.source == SOURCE_IGNORE: + if config_entry.version == 2 and config_entry.source == SOURCE_IGNORE: # noqa: PLR2004 hass.config_entries.async_update_entry( config_entry, version=3, title=config_entry.title ) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 285073519..353538810 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -459,7 +459,7 @@ def _async_template_startup( is_availability_template = False for attribute in attributes: # pylint: disable-next=protected-access - if attribute._attribute == "_attr_available": + if attribute._attribute == "_attr_available": # noqa: SLF001 has_availability_template = True is_availability_template = True attribute.async_setup() diff --git a/pyproject.toml b/pyproject.toml index e7d1367d3..07b05f699 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,9 +101,6 @@ ignore = [ "EM102", # Exception must not use an f-string literal, assign to variable first "FBT001", # Boolean-typed positional argument in function definition "FBT002", # Boolean-typed positional argument in function definition - "G004", # Logging statement uses f-string - "I001", # Import block is un-sorted or un-formatted - "PGH003", # Use specific rule codes when ignoring type issues "PLR0913", # Too many arguments in function definition "PLR0915", # Too many statements "PLR2004", # Magic value used in comparison @@ -119,7 +116,6 @@ ignore = [ "RET505", # Unnecessary `else` after `return` statement "SIM102", # Use a single `if`-statement instead of nested `if`-statements "SIM103", # Return the condition directly - "SLF001", # Private member accessed "TC003", # Move standard library import into a type-checking block "TC006", # Move third-party import into a type-checking block "TRY003", # Avoid specifying long messages outside the exception class From 36a400ecce67e9fecbb5d23c96becb76a98f3112 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:34:22 +0000 Subject: [PATCH 226/235] Lint --- custom_components/battery_notes/__init__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index 3b093b0e0..b5c82febe 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -255,20 +255,18 @@ async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> ) if not any( - entry.version < 3 # noqa: PLR2004 - and entry.source != SOURCE_IGNORE - for entry in entries + entry.version < 3 and entry.source != SOURCE_IGNORE for entry in entries ): return for entry in entries: - if entry.version == 3 and entry.unique_id == DOMAIN: # noqa: PLR2004 + if entry.version == 3 and entry.unique_id == DOMAIN: # We have a V3 entry, so we can use this as the base migrate_base_entry = entry break for entry in entries: - if entry.version >= 3: # noqa: PLR2004 + if entry.version >= 3: continue if entry.source == SOURCE_IGNORE: @@ -413,7 +411,7 @@ async def async_migrate_entry( config_entry.minor_version, ) - if config_entry.version > 3: # noqa: PLR2004 + if config_entry.version > 3: # This means the user has downgraded from a future version return False @@ -445,7 +443,7 @@ async def async_migrate_entry( 2, ) - if config_entry.version == 2 and config_entry.source == SOURCE_IGNORE: # noqa: PLR2004 + if config_entry.version == 2 and config_entry.source == SOURCE_IGNORE: hass.config_entries.async_update_entry( config_entry, version=3, title=config_entry.title ) From 5d875f1964ad94b2e47c245dcf8b1b10c5bd21f8 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:41:36 +0000 Subject: [PATCH 227/235] Lint --- custom_components/battery_notes/__init__.py | 2 +- custom_components/battery_notes/config_flow.py | 2 +- pyproject.toml | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index b5c82febe..cfffce94c 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -228,7 +228,7 @@ async def async_remove_entry( ) -async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> None: # noqa: PLR0912 +async def async_migrate_integration(hass: HomeAssistant, config: ConfigType) -> None: # noqa: PLR0912, PLR0915 """Migrate integration entry structure.""" migrate_base_entry: ConfigEntry | None = None diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 3f53c36b4..ab1b393fc 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -351,7 +351,7 @@ async def async_step_device( last_step=False, ) - async def async_step_battery( # noqa: PLR0912 + async def async_step_battery( # noqa: PLR0912, PLR0915 self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Second step in config flow to add the battery type.""" diff --git a/pyproject.toml b/pyproject.toml index 07b05f699..495046503 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,7 +102,6 @@ ignore = [ "FBT001", # Boolean-typed positional argument in function definition "FBT002", # Boolean-typed positional argument in function definition "PLR0913", # Too many arguments in function definition - "PLR0915", # Too many statements "PLR2004", # Magic value used in comparison "PLR5501", # Use `elif` instead of `else` then `if` "PLW2901", # `for` loop variable overwritten by assignment target From 39880fa922a310a7a50331bd5244bcc28544380a Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:46:14 +0000 Subject: [PATCH 228/235] Lint --- custom_components/battery_notes/__init__.py | 5 ++-- .../battery_notes/binary_sensor.py | 17 +++++------ .../battery_notes/config_flow.py | 29 +++++++++---------- custom_components/battery_notes/library.py | 11 ++++--- custom_components/battery_notes/sensor.py | 17 +++++------ pyproject.toml | 1 - 6 files changed, 37 insertions(+), 43 deletions(-) diff --git a/custom_components/battery_notes/__init__.py b/custom_components/battery_notes/__init__.py index cfffce94c..58b8343c9 100644 --- a/custom_components/battery_notes/__init__.py +++ b/custom_components/battery_notes/__init__.py @@ -501,9 +501,8 @@ async def _async_remove_subentry( if coordinator.source_entity_id: store.async_delete_entity(coordinator.source_entity_id) - else: - if coordinator.device_id: - store.async_delete_device(coordinator.device_id) + elif coordinator.device_id: + store.async_delete_device(coordinator.device_id) # Unhide the battery if coordinator.wrapped_battery: diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index 353538810..aab996beb 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -816,15 +816,14 @@ async def _async_state_changed_listener( self.coordinator.wrapped_battery_low.entity_id, hidden_by=er.RegistryEntryHider.INTEGRATION, ) - else: - if ( - self.coordinator.wrapped_battery_low - and self.coordinator.wrapped_battery_low.hidden_by - == er.RegistryEntryHider.INTEGRATION - ): - registry.async_update_entity( - self.coordinator.wrapped_battery_low.entity_id, hidden_by=None - ) + elif ( + self.coordinator.wrapped_battery_low + and self.coordinator.wrapped_battery_low.hidden_by + == er.RegistryEntryHider.INTEGRATION + ): + registry.async_update_entity( + self.coordinator.wrapped_battery_low.entity_id, hidden_by=None + ) self.async_on_remove( self.coordinator.async_add_listener(self._handle_coordinator_update) diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index ab1b393fc..eb75e3dde 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -874,22 +874,21 @@ async def async_step_reconfigure( if not device_entry: errors["base"] = "orphaned_battery_note" - else: - if device_entry and device_entry.manufacturer and device_entry.model: - _LOGGER.debug( - "Looking up device %s %s %s %s", - device_entry.manufacturer, - device_entry.model, - get_device_model_id(device_entry) or "", - device_entry.hw_version, - ) + elif device_entry and device_entry.manufacturer and device_entry.model: + _LOGGER.debug( + "Looking up device %s %s %s %s", + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry) or "", + device_entry.hw_version, + ) - self.model_info = ModelInfo( - device_entry.manufacturer, - device_entry.model, - get_device_model_id(device_entry), - device_entry.hw_version, - ) + self.model_info = ModelInfo( + device_entry.manufacturer, + device_entry.model, + get_device_model_id(device_entry), + device_entry.hw_version, + ) if self.data.get(CONF_BATTERY_LOW_TEMPLATE, None) is None: data_schema = vol.Schema( diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index f5e68ee84..a4bdd9388 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -247,12 +247,11 @@ def device_basic_match( library_device.model.casefold() ): return True - else: - if ( - library_device.model.casefold() - == str(device_to_find.model or "").casefold() - ): - return True + elif ( + library_device.model.casefold() + == str(device_to_find.model or "").casefold() + ): + return True return False def device_partial_match( diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index afcacac27..50f889699 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -617,15 +617,14 @@ async def _async_state_reported_listener( self.coordinator.wrapped_battery.entity_id, hidden_by=er.RegistryEntryHider.INTEGRATION, ) - else: - if ( - self.coordinator.wrapped_battery - and self.coordinator.wrapped_battery.hidden_by - == er.RegistryEntryHider.INTEGRATION - ): - registry.async_update_entity( - self.coordinator.wrapped_battery.entity_id, hidden_by=None - ) + elif ( + self.coordinator.wrapped_battery + and self.coordinator.wrapped_battery.hidden_by + == er.RegistryEntryHider.INTEGRATION + ): + registry.async_update_entity( + self.coordinator.wrapped_battery.entity_id, hidden_by=None + ) self.async_on_remove( self.coordinator.async_add_listener(self._handle_coordinator_update) diff --git a/pyproject.toml b/pyproject.toml index 495046503..1476f31ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,7 +103,6 @@ ignore = [ "FBT002", # Boolean-typed positional argument in function definition "PLR0913", # Too many arguments in function definition "PLR2004", # Magic value used in comparison - "PLR5501", # Use `elif` instead of `else` then `if` "PLW2901", # `for` loop variable overwritten by assignment target "PTH103", # `os.makedirs()` should be replaced by `Path.mkdir()` "PTH104", # `os.rename()` should be replaced by `Path.rename()` From a88f9fd6a4963a147028b1f28c60aa273e0b2d39 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:49:17 +0000 Subject: [PATCH 229/235] Lint --- custom_components/battery_notes/discovery.py | 5 +---- custom_components/battery_notes/library.py | 23 +++++++++----------- pyproject.toml | 2 -- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index 062505e14..38e6b746c 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -125,10 +125,7 @@ async def start_discovery(self) -> None: def should_process_device(self, device_entry: dr.DeviceEntry) -> bool: """Do some validations on the registry entry to see if it qualifies for discovery.""" - if device_entry.disabled: - return False - - return True + return not device_entry.disabled @callback def _init_entity_discovery( diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index a4bdd9388..417971b88 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -259,9 +259,9 @@ def device_partial_match( ) -> bool: """Check if device match on hw_version or model_id.""" if device_to_find.hw_version is None and device_to_find.model_id is None: - if library_device.hw_version is None and library_device.model_id is None: - return True - return False + return bool( + library_device.hw_version is None and library_device.model_id is None + ) if device_to_find.hw_version is None or device_to_find.model_id is None: if (library_device.hw_version or "").casefold() == str( @@ -277,13 +277,12 @@ def device_full_match( self, library_device: LibraryDevice, device_to_find: ModelInfo ) -> bool: """Check if device match on hw_version and model_id.""" - if (library_device.hw_version or "").casefold() == str( - device_to_find.hw_version - ).casefold() and (library_device.model_id or "").casefold() == str( - device_to_find.model_id - ).casefold(): - return True - return False + return bool( + (library_device.hw_version or "").casefold() + == str(device_to_find.hw_version).casefold() + and (library_device.model_id or "").casefold() + == str(device_to_find.model_id).casefold() + ) class DeviceBatteryDetails(NamedTuple): @@ -299,9 +298,7 @@ class DeviceBatteryDetails(NamedTuple): @property def is_manual(self): """Return whether the device should be discovered or battery type suggested.""" - if self.battery_type.casefold() == "manual".casefold(): - return True - return False + return self.battery_type.casefold() == "manual".casefold() @property def battery_type_and_quantity(self): diff --git a/pyproject.toml b/pyproject.toml index 1476f31ba..06f22d558 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,7 +103,6 @@ ignore = [ "FBT002", # Boolean-typed positional argument in function definition "PLR0913", # Too many arguments in function definition "PLR2004", # Magic value used in comparison - "PLW2901", # `for` loop variable overwritten by assignment target "PTH103", # `os.makedirs()` should be replaced by `Path.mkdir()` "PTH104", # `os.rename()` should be replaced by `Path.rename()` "PTH118", # `os.path.join()` should be replaced by `Path` with `/` operator @@ -113,7 +112,6 @@ ignore = [ "RET504", # Unnecessary assignment before `return` statement "RET505", # Unnecessary `else` after `return` statement "SIM102", # Use a single `if`-statement instead of nested `if`-statements - "SIM103", # Return the condition directly "TC003", # Move standard library import into a type-checking block "TC006", # Move third-party import into a type-checking block "TRY003", # Avoid specifying long messages outside the exception class From 2b6c3ec0a53e847d031d46e306433821eff2fbd2 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sun, 2 Nov 2025 16:54:23 +0000 Subject: [PATCH 230/235] Lint --- custom_components/battery_notes/binary_sensor.py | 2 +- custom_components/battery_notes/sensor.py | 6 +++--- pyproject.toml | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/custom_components/battery_notes/binary_sensor.py b/custom_components/battery_notes/binary_sensor.py index aab996beb..73ab91490 100644 --- a/custom_components/battery_notes/binary_sensor.py +++ b/custom_components/battery_notes/binary_sensor.py @@ -195,7 +195,7 @@ async def async_setup_entry( class _TemplateAttribute: """Attribute value linked to template result.""" - def __init__( + def __init__( # noqa: PLR0913 self, entity: Entity, attribute: str, diff --git a/custom_components/battery_notes/sensor.py b/custom_components/battery_notes/sensor.py index 50f889699..caad5a076 100644 --- a/custom_components/battery_notes/sensor.py +++ b/custom_components/battery_notes/sensor.py @@ -206,7 +206,7 @@ class BatteryNotesTypeSensor(BatteryNotesEntity, RestoreSensor): entity_description: BatteryNotesSensorEntityDescription _unrecorded_attributes = frozenset({ATTR_BATTERY_QUANTITY, ATTR_BATTERY_TYPE}) - def __init__( + def __init__( # noqa: PLR0913 self, hass, config_entry: BatteryNotesConfigEntry, # noqa: ARG002 @@ -270,7 +270,7 @@ class BatteryNotesLastReplacedSensor(BatteryNotesEntity, SensorEntity): _attr_should_poll = False entity_description: BatteryNotesSensorEntityDescription - def __init__( + def __init__( # noqa: PLR0913 self, hass, config_entry: BatteryNotesConfigEntry, # noqa: ARG002 @@ -343,7 +343,7 @@ class BatteryNotesBatteryPlusSensor(BatteryNotesEntity, RestoreSensor): entity_description: BatteryNotesSensorEntityDescription - def __init__( + def __init__( # noqa: PLR0913 self, hass: HomeAssistant, config_entry: BatteryNotesConfigEntry, diff --git a/pyproject.toml b/pyproject.toml index 06f22d558..8f33a5402 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,7 +101,6 @@ ignore = [ "EM102", # Exception must not use an f-string literal, assign to variable first "FBT001", # Boolean-typed positional argument in function definition "FBT002", # Boolean-typed positional argument in function definition - "PLR0913", # Too many arguments in function definition "PLR2004", # Magic value used in comparison "PTH103", # `os.makedirs()` should be replaced by `Path.mkdir()` "PTH104", # `os.rename()` should be replaced by `Path.rename()` From c67360cf3cbc3079b57fa7b66d94480edef3c2ae Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Thu, 6 Nov 2025 19:46:23 +0000 Subject: [PATCH 231/235] Fix threshold blueprint --- docs/blueprints/battery_notes_battery_threshold.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/blueprints/battery_notes_battery_threshold.yaml b/docs/blueprints/battery_notes_battery_threshold.yaml index 16c7cd93a..4aea66f8a 100644 --- a/docs/blueprints/battery_notes_battery_threshold.yaml +++ b/docs/blueprints/battery_notes_battery_threshold.yaml @@ -83,7 +83,7 @@ triggers: conditions: - condition: template value_template: |- - {{ trigger.event.data.device_id not in excluded_devices}} + {{ excluded_devices == none or excluded_devices | length == 0 or trigger.event.data.device_id not in excluded_devices }} - condition: template value_template: |- {{ not include_devices_enabled or trigger.event.data.device_id in include_devices }} From e991f8f76a7314eacbb3d9bafc6452fd0d25973b Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 7 Nov 2025 08:48:58 +0000 Subject: [PATCH 232/235] Update threshold blueprint --- docs/blueprints/battery_notes_battery_threshold.yaml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/blueprints/battery_notes_battery_threshold.yaml b/docs/blueprints/battery_notes_battery_threshold.yaml index 4aea66f8a..6c2627b7b 100644 --- a/docs/blueprints/battery_notes_battery_threshold.yaml +++ b/docs/blueprints/battery_notes_battery_threshold.yaml @@ -18,6 +18,12 @@ blueprint: default: True selector: boolean: + exclude_devices_enabled: + name: Enable Exclude Devices Filter + description: Do not trigger for specific devices when enabled. + default: true + selector: + boolean: excluded_devices: name: Devices to exclude (Optional) description: Devices that you do not want to trigger this automation. @@ -62,6 +68,7 @@ blueprint: variables: low_notification: !input low_notification high_notification: !input high_notification + exclude_devices_enabled: !input exclude_devices_enabled excluded_devices: !input excluded_devices include_devices_enabled: !input include_devices_enabled include_devices: !input include_devices @@ -83,10 +90,10 @@ triggers: conditions: - condition: template value_template: |- - {{ excluded_devices == none or excluded_devices | length == 0 or trigger.event.data.device_id not in excluded_devices }} + {{ not exclude_devices_enabled or (excluded_devices == none or excluded_devices | length == 0 or trigger.event.data.device_id not in excluded_devices) }} - condition: template value_template: |- - {{ not include_devices_enabled or trigger.event.data.device_id in include_devices }} + {{ not include_devices_enabled or (include_devices != none and include_devices | length > 0 and trigger.event.data.device_id in include_devices) }} - alias: User pick condition: !input additional_conditions From e1e72ead03dbd7e0ff91befb294919b9c7714146 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Fri, 7 Nov 2025 11:20:29 +0000 Subject: [PATCH 233/235] Update threshold blueprint --- docs/blueprints/battery_notes_battery_threshold.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/blueprints/battery_notes_battery_threshold.yaml b/docs/blueprints/battery_notes_battery_threshold.yaml index 6c2627b7b..12556a90d 100644 --- a/docs/blueprints/battery_notes_battery_threshold.yaml +++ b/docs/blueprints/battery_notes_battery_threshold.yaml @@ -26,7 +26,7 @@ blueprint: boolean: excluded_devices: name: Devices to exclude (Optional) - description: Devices that you do not want to trigger this automation. + description: When enabled above, these devices will not trigger this automation. default: selector: device: From a7dc9af0d8303c28b0f7dd3cf4c7a7ac9459c461 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Mon, 10 Nov 2025 10:01:39 +0000 Subject: [PATCH 234/235] Add ignore rule for TC006 in ruff linting configuration --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8f33a5402..9b7b90698 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,6 +90,7 @@ ignore = [ "RUF001", # String contains ambiguous character "S101", # Use of assert detected "TC001", # Move application import into type checking + "TC006", # Add quotes to type expression in typing.cast() # TODO: Temporary ignores, to review "ANN001", # Missing type annotation for function argument @@ -112,7 +113,6 @@ ignore = [ "RET505", # Unnecessary `else` after `return` statement "SIM102", # Use a single `if`-statement instead of nested `if`-statements "TC003", # Move standard library import into a type-checking block - "TC006", # Move third-party import into a type-checking block "TRY003", # Avoid specifying long messages outside the exception class "TRY004", # Prefer `TypeError` exception for invalid type "TRY300", # Consider moving this statement to an `else` block From e68f67b937c74c5ccf24b7bc3f86990117bb08b9 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Tue, 11 Nov 2025 09:06:03 +0000 Subject: [PATCH 235/235] Remove duplicate options section --- .../battery_notes/translations/ar.json | 25 ------------------- .../battery_notes/translations/ca.json | 25 ------------------- .../battery_notes/translations/cs.json | 25 ------------------- .../battery_notes/translations/da.json | 25 ------------------- .../battery_notes/translations/de.json | 25 ------------------- .../battery_notes/translations/el.json | 25 ------------------- .../battery_notes/translations/en.json | 25 ------------------- .../battery_notes/translations/es-ES.json | 25 ------------------- .../battery_notes/translations/fi.json | 25 ------------------- .../battery_notes/translations/fr.json | 25 ------------------- .../battery_notes/translations/hu.json | 25 ------------------- .../battery_notes/translations/it.json | 25 ------------------- .../battery_notes/translations/lt.json | 25 ------------------- .../battery_notes/translations/lv.json | 25 ------------------- .../battery_notes/translations/nl.json | 25 ------------------- .../battery_notes/translations/no.json | 25 ------------------- .../battery_notes/translations/pl.json | 25 ------------------- .../battery_notes/translations/pt-BR.json | 25 ------------------- .../battery_notes/translations/pt.json | 25 ------------------- .../battery_notes/translations/ru.json | 25 ------------------- .../battery_notes/translations/sk.json | 25 ------------------- .../battery_notes/translations/sr-Latn.json | 25 ------------------- .../battery_notes/translations/sv-SE.json | 25 ------------------- .../battery_notes/translations/tr.json | 25 ------------------- .../battery_notes/translations/uk.json | 25 ------------------- .../battery_notes/translations/ur-IN.json | 25 ------------------- .../battery_notes/translations/zh-Hans.json | 25 ------------------- .../battery_notes/translations/zh-Hant.json | 25 ------------------- 28 files changed, 700 deletions(-) diff --git a/custom_components/battery_notes/translations/ar.json b/custom_components/battery_notes/translations/ar.json index 30d003f24..bc8106dc7 100644 --- a/custom_components/battery_notes/translations/ar.json +++ b/custom_components/battery_notes/translations/ar.json @@ -152,31 +152,6 @@ "unknown": "حدث خطأ غير معروف." } }, - "battery_note_options": { - "step": { - "init": { - "description": "الصانع: {manufacturer}\nالطراز: {model}\nمعرف الطراز: {model_id}\nإصدار الجهاز: {hw_version}", - "data": { - "name": "اسم", - "battery_type": "نوع البطارية", - "battery_quantity": "كَمّيَّة البطارية", - "battery_low_threshold": "عتبة البطارية المنخفضة", - "battery_low_template": "قالب البطارية المنخفضة", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "تركه فارغًا سيأخذ الاسم من الجهاز المصدر.", - "battery_low_threshold": "الصفر سيستخدم العتبة الافتراضية العالمية.", - "battery_low_template": "القالب لتحديد إذا كانت البطارية منخفضة، يجب أن يُرجع \"صحيح\" إذا كانت منخفضة.\nمطلوب فقط للمستويات غير القياسية للبطارية.", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "الجهاز أو الكيان المرتبط لم يعد موجودًا لهذه الملاحظة الخاصة بالبطارية.", - "unknown": "حدث خطأ غير معروف." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/ca.json b/custom_components/battery_notes/translations/ca.json index 33a43bf6c..0deb8c569 100644 --- a/custom_components/battery_notes/translations/ca.json +++ b/custom_components/battery_notes/translations/ca.json @@ -152,31 +152,6 @@ "unknown": "S'ha produït un error desconegut" } }, - "battery_note_options": { - "step": { - "init": { - "description": "Fabricant: {manufacturer}\nModel: {model}\nIdentificador del model: {model_id}\nVersió de maquinari: {hw_version}", - "data": { - "name": "Nom", - "battery_type": "Tipus de bateria", - "battery_quantity": "Quantitat de bateries", - "battery_low_threshold": "Llindar baix de la bateria", - "battery_low_template": "Plantilla de bateria baixa", - "filter_outliers": "iltrar valors atípics" - }, - "data_description": { - "name": "Si ho deixes en blanc, agafarà el nom del dispositiu d'origen", - "battery_low_threshold": "0 utilitzarà el llindar predeterminat global", - "battery_low_template": "La plantilla per determinar que la bateria és baixa, hauria de tornar correcte si és baixa\nNomés és necessari per a nivells de bateria no estàndard", - "filter_outliers": "Filtra les grans caigudes del nivell de bateria, reduint els esdeveniments que es disparen falsament en els dispositius que informen erròniament dels nivells de manera ocasional." - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Unknown error occurred." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/cs.json b/custom_components/battery_notes/translations/cs.json index a089a5563..49bbd311f 100644 --- a/custom_components/battery_notes/translations/cs.json +++ b/custom_components/battery_notes/translations/cs.json @@ -152,31 +152,6 @@ "unknown": "Vyskytla se neznámá chyba." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Výrobce: {manufacturer}\nModel: {model}\nID modelu: {model_id}\nHardware verze: {hw_version}", - "data": { - "name": "Název", - "battery_type": "Typ baterie", - "battery_quantity": "Množství baterií", - "battery_low_threshold": "Práh nízkého stavu baterie", - "battery_low_template": "Šablona nízkého stavu baterie", - "filter_outliers": "Filtrovat odlehlé hodnoty" - }, - "data_description": { - "name": "Ponecháte-li prázdné, převezme název ze zdrojového zařízení", - "battery_low_threshold": "0 se použije jako globální výchozí práh", - "battery_low_template": "Šablona k určení zda je stav baterie nízký, měla by vrátit hodnotu pravda, pokud je nízký\nJe potřeba pouze pro nestandardní úroveně baterie", - "filter_outliers": "Filtrovat velké ztráty úrovně baterie, což snižuje falešné spouštění událostí na zařízení, která občas chybně hlásí úrovně" - } - } - }, - "error": { - "orphaned_battery_note": "Přidružené zařízení nebo entita pro tuto poznámku k baterii již neexistuje.", - "unknown": "Vyskytla se neznámá chyba." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/da.json b/custom_components/battery_notes/translations/da.json index 03edcfcac..7a875e314 100644 --- a/custom_components/battery_notes/translations/da.json +++ b/custom_components/battery_notes/translations/da.json @@ -152,31 +152,6 @@ "unknown": "Der opstod en ukendt fejl." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", - "data": { - "name": "Navn", - "battery_type": "Batteri type", - "battery_quantity": "Antal batterier", - "battery_low_threshold": "Lavt batteri niveau", - "battery_low_template": "Batteri lav skabelon", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Hvis du lader dette felt være tomt, hentes navnet fra kildeenheden", - "battery_low_threshold": "0 vil bruge den globale standardtærskel", - "battery_low_template": "Skabelon til at bestemme om et batteri er lavt, skal returnere sand, hvis lavt\nKun nødvendigt for ikke-standard batteriniveauer", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "Den tilknyttede enhed eller enhed eksisterer ikke længere for dette Battery Note.", - "unknown": "Der opstod en ukendt fejl." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/de.json b/custom_components/battery_notes/translations/de.json index e60b8aa59..181402bbe 100644 --- a/custom_components/battery_notes/translations/de.json +++ b/custom_components/battery_notes/translations/de.json @@ -152,31 +152,6 @@ "unknown": "Ein unbekannter Fehler ist aufgetreten." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Hersteller: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHardware Version: {hw_version}", - "data": { - "name": "Name", - "battery_type": "Batterieart", - "battery_quantity": "Batteriemenge", - "battery_low_threshold": "Schwelle für niedrigen Batteriestand", - "battery_low_template": "Vorlage für niedrigen Batteriestand", - "filter_outliers": "Ausreißer filtern" - }, - "data_description": { - "name": "Wenn du nichts eingibst, wird der Name vom Quellgerät übernommen", - "battery_low_threshold": "0 verwendet den globalen Standardschwellenwert", - "battery_low_template": "Vorlage um zu bestimmen, ob eine Batterie schwach ist; sollte \"wahr\" (true) rückmelden, wenn schwach.\nNur für nicht-Standard Batteriewerte benötigt.", - "filter_outliers": "Filtere größere Sprünge des Ladestandes der Batterie bei Geräten, die ihren Ladestand nur sporadisch mitteilen, um fehlerhafte Auslösungen zu verhindern" - } - } - }, - "error": { - "orphaned_battery_note": "Das zugeordnete Gerät für diesen Eintrag in \"Battery Notes\" ist nicht mehr verfügbar", - "unknown": "Ein unbekannter Fehler ist aufgetreten." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/el.json b/custom_components/battery_notes/translations/el.json index 965fb5007..7a0924f4c 100644 --- a/custom_components/battery_notes/translations/el.json +++ b/custom_components/battery_notes/translations/el.json @@ -152,31 +152,6 @@ "unknown": "Προέκυψε άγνωστο σφάλμα." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Κατασκευαστής: {manufacturer}\nΜοντέλο: {model}\nID Μοντέλου: {model_id}\nΕκδοση υλικού: {hw_version}", - "data": { - "name": "Ονομα", - "battery_type": "Τύπος μπαταρίας", - "battery_quantity": "Αριθμός μπαταριών", - "battery_low_threshold": "Ελάχιστο όριο μπαταρίας", - "battery_low_template": "Template χαμηλής στάθμης μπαταρίας", - "filter_outliers": "Φιλτράρισμα ακραίων τιμών" - }, - "data_description": { - "name": "Αφήνοντάς το κενό θα πάρει το όνομα από τη συσκευή προέλευσης", - "battery_low_threshold": "0 θα χρησιμοποιηθεί το καθολικό προεπιλεγμένο ελάχιστο όριο", - "battery_low_template": "Template για τον προσδιορισμό μιας μπαταρίας είναι χαμηλή, θα πρέπει να επιστρέψει true εάν είναι χαμηλή\nΧρειάζεται μόνο για μη τυπικές στάθμες μπαταρίας", - "filter_outliers": "Φιλτράρετε μεγάλες πτώσεις στάθμης μπαταρίας, περιορίζοντας την πυροδότηση ψευδών συμβάντων σε συσκευές που εσφαλμένα αναφέρουν επίπεδα περιστασιακά" - } - } - }, - "error": { - "orphaned_battery_note": "Η συσχετιζόμενη συσκευή ή οντότητα δεν υπάρχει πλέον για αυτήν την Σημείωση μπαταρίας.", - "unknown": "Προέκυψε άγνωστο σφάλμα." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/en.json b/custom_components/battery_notes/translations/en.json index 5a15991cc..2a92399f6 100644 --- a/custom_components/battery_notes/translations/en.json +++ b/custom_components/battery_notes/translations/en.json @@ -152,31 +152,6 @@ "unknown": "Unknown error occurred." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", - "data": { - "name": "Name", - "battery_type": "Battery type", - "battery_quantity": "Battery quantity", - "battery_low_threshold": "Battery low threshold", - "battery_low_template": "Battery low template", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Leaving blank will take the name from the source device", - "battery_low_threshold": "0 will use the global default threshold", - "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Unknown error occurred." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/es-ES.json b/custom_components/battery_notes/translations/es-ES.json index 46ebc4c0c..db058f735 100644 --- a/custom_components/battery_notes/translations/es-ES.json +++ b/custom_components/battery_notes/translations/es-ES.json @@ -152,31 +152,6 @@ "unknown": "Se ha producido un error desconocido." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Fabricante: {manufacturer}\nModelo: {model}\nID de Modelo: {model_id}\nVersión de Hardware: {hw_version}", - "data": { - "name": "Nombre", - "battery_type": "Tipo de batería", - "battery_quantity": "Cantidad de batería", - "battery_low_threshold": "Umbral bajo de batería", - "battery_low_template": "Plantilla de batería baja", - "filter_outliers": "Filtrar valores atípicos" - }, - "data_description": { - "name": "Dejar en blanco utilizará el nombre del dispositivo de serie", - "battery_low_threshold": "0 usará el umbral global por defecto", - "battery_low_template": "Plantilla para determinar que una batería es baja, debe devolver verdadero si es baja\nSolo necesario para niveles de batería no estándar", - "filter_outliers": "Filtra las grandes caídas del nivel de batería, reduciendo los eventos que se disparan falsamente en los dispositivos que informan erróneamente de los niveles de forma ocasional." - } - } - }, - "error": { - "orphaned_battery_note": "El dispositivo o entidad asociada ya no existe para esta Nota de batería", - "unknown": "Se ha producido un error desconocido." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/fi.json b/custom_components/battery_notes/translations/fi.json index 74aaee7be..c63f1c195 100644 --- a/custom_components/battery_notes/translations/fi.json +++ b/custom_components/battery_notes/translations/fi.json @@ -152,31 +152,6 @@ "unknown": "Tuntematon virhe." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", - "data": { - "name": "Nimi", - "battery_type": "Akun tyyppi", - "battery_quantity": "Akkujen määrä", - "battery_low_threshold": "Akun alhainen raja", - "battery_low_template": "Battery low template", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Tyhjäksi jättäminen ottaa nimen lähdelaitteesta", - "battery_low_threshold": "0 käyttää yleistä oletusarvoa", - "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Tuntematon virhe." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/fr.json b/custom_components/battery_notes/translations/fr.json index 55a385288..ea40067dc 100644 --- a/custom_components/battery_notes/translations/fr.json +++ b/custom_components/battery_notes/translations/fr.json @@ -152,31 +152,6 @@ "unknown": "Erreur inconnue." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Fabricant : {manufacturer}\nModèle : {model}\nID modèle : {model_id}\nVersion du matériel : {hw_version}", - "data": { - "name": "Nom", - "battery_type": "Type de batterie", - "battery_quantity": "Nombre de batteries", - "battery_low_threshold": "Seuil de batterie faible", - "battery_low_template": "Modèle de batterie faible", - "filter_outliers": "Filtrer les valeurs aberrantes" - }, - "data_description": { - "name": "Laisser vide gardera le seuil par defaut", - "battery_low_threshold": "0 gardera le seuil par defaut", - "battery_low_template": "Modèle pour déterminer si une batterie est faible, devrait retourner vrai si faible\nNécessaire uniquement pour les niveaux de batterie non standard", - "filter_outliers": "Filtrer les baisses importantes du niveau de batterie, pour réduire les événements faussement déclenchés par les appareils qui signalent occasionnellement des niveaux erronés" - } - } - }, - "error": { - "orphaned_battery_note": "Le périphérique ou l'entité associée n'existe plus pour cette Note de Batterie.", - "unknown": "Erreur inconnue." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/hu.json b/custom_components/battery_notes/translations/hu.json index 9a74369bd..dcb2d16bf 100644 --- a/custom_components/battery_notes/translations/hu.json +++ b/custom_components/battery_notes/translations/hu.json @@ -152,31 +152,6 @@ "unknown": "Ismeretlen hiba lépett fel." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Gyártó: {manufacturer}\nModell: {model}\nModell azonosító: {model_id}\nHardver verzió: {hw_version}", - "data": { - "name": "Név", - "battery_type": "Elemtípus", - "battery_quantity": "Elem darabszám", - "battery_low_threshold": "Alacsony elemszint küszöbérték", - "battery_low_template": "Alacsony elemszint sablon", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Üresen hagyva a forráseszköz nevét kapja", - "battery_low_threshold": "0 érték esetén a központi beállítást fogja használni", - "battery_low_template": "A sablon igaz értéket kell adjon, ha az elem nemsokára lemerül\nCsak nem szokványos töltöttségi szint esetén kell megadni", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "Az ehhez a Battery Note-hoz társított eszköz vagy entitás már nem létezik.", - "unknown": "Ismeretlen hiba lépett fel." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/it.json b/custom_components/battery_notes/translations/it.json index 0cf57e326..174c9cf7a 100644 --- a/custom_components/battery_notes/translations/it.json +++ b/custom_components/battery_notes/translations/it.json @@ -152,31 +152,6 @@ "unknown": "Errore sconosciuto." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Produttore: {manufacturer}\nModello: {model}\nID Modello: {model_id}\nVersione hardware: {hw_version}", - "data": { - "name": "Nome", - "battery_type": "Tipo di batteria", - "battery_quantity": "Quantità batteria", - "battery_low_threshold": "Livello batteria bassa", - "battery_low_template": "Modello batteria bassa", - "filter_outliers": "Filtra anomali" - }, - "data_description": { - "name": "Lasciando vuoto prenderà il nome dal dispositivo di origine", - "battery_low_threshold": "0 utilizzerà la soglia globale predefinita", - "battery_low_template": "Modello per determinare se una batteria è scarica, dovrebbe restituire vero se scarica. \nNecessario solo per livelli di batteria non standard", - "filter_outliers": "Filtra grossi cali batteria, riducendo falsi eventi su dispositivi che restituiscono occasionalmente livelli erronei" - } - } - }, - "error": { - "orphaned_battery_note": "L'entità o dispositivo associato non esiste più per questo Battery Note.", - "unknown": "Errore sconosciuto." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/lt.json b/custom_components/battery_notes/translations/lt.json index dba12e103..177dc4b18 100644 --- a/custom_components/battery_notes/translations/lt.json +++ b/custom_components/battery_notes/translations/lt.json @@ -152,31 +152,6 @@ "unknown": "Įvyko nežinoma klaida." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", - "data": { - "name": "Pavadinimas", - "battery_type": "Baterijos tipas", - "battery_quantity": "Baterijų kiekis", - "battery_low_threshold": "Battery low threshold", - "battery_low_template": "Battery low template", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Leaving blank will take the name from the source device", - "battery_low_threshold": "Įrašius 0 bus naudojama numatytoji vertė", - "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Įvyko nežinoma klaida." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/lv.json b/custom_components/battery_notes/translations/lv.json index 588e5d41b..d6bac8a4e 100644 --- a/custom_components/battery_notes/translations/lv.json +++ b/custom_components/battery_notes/translations/lv.json @@ -152,31 +152,6 @@ "unknown": "Notika nezināma kļūda." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Ražotājs: {manufacturer}\nModelis: {model}\nModeļa ID: {model_id}\nAparatūras versija: {hw_version}", - "data": { - "name": "Nosaukums", - "battery_type": "Baterijas tips", - "battery_quantity": "Bateriju daudzums", - "battery_low_threshold": "Zema baterijas līmeņa slieksnis", - "battery_low_template": "Zema baterijas līmeņa šablons", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Atstājot tukšu tiks ņemts nosaukums no pamata ierīces", - "battery_low_threshold": "Norādiet 0, lai izmantotu noklusēto slieksni", - "battery_low_template": "Šablons lai noteiktu zemu baterijas līmeni, kam jāatgriež patiesa vērtība, līmenis ir zems\nNepieciešams tikai nestandarta bateriju līmeņiem", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Notika nezināma kļūda." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/nl.json b/custom_components/battery_notes/translations/nl.json index 76a1f12ff..193e57346 100644 --- a/custom_components/battery_notes/translations/nl.json +++ b/custom_components/battery_notes/translations/nl.json @@ -152,31 +152,6 @@ "unknown": "Onbekende fout opgetreden." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Fabrikant: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware versie: {hw_version}", - "data": { - "name": "Naam", - "battery_type": "Batterij type", - "battery_quantity": "Aantal batterijen", - "battery_low_threshold": "Drempelwaarde batterij bijna leeg", - "battery_low_template": "Sjabloon batterij bijna leeg", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Indien dit leeg gelaten wordt dan wordt de naam van het bronapparaat overgenomen", - "battery_low_threshold": "0 zal de globale standaard drempelwaarde gebruiken", - "battery_low_template": "Sjabloon om te bepalen dat een batterij bijna leeg is, zal 'waar' teruggeven als bijna leeg\nAlleen nodig voor niet-standaard batterijniveaus", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "Het gekoppelde apparaat of entiteit bestaat niet meer voor deze Battery Note.", - "unknown": "Onbekende fout opgetreden." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/no.json b/custom_components/battery_notes/translations/no.json index 1ceb54023..90650c09a 100644 --- a/custom_components/battery_notes/translations/no.json +++ b/custom_components/battery_notes/translations/no.json @@ -152,31 +152,6 @@ "unknown": "En ukjent feil har oppstått." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Produsent: {manufacturer}\nModel: {model}\nModell-ID: {model_id}\nMaskinvareversjon: {hw_version}", - "data": { - "name": "Navn", - "battery_type": "Batteritype", - "battery_quantity": "Antall batterier", - "battery_low_threshold": "Lavt batterinivå-terskel", - "battery_low_template": "Mal for lavt batterinivå", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Leaving blank will take the name from the source device", - "battery_low_threshold": "0 will use the global default threshold", - "battery_low_template": "Template to determine a battery is low, should return true if low\nOnly needed for non-standard battery levels", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "En ukjent feil har oppstått." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/pl.json b/custom_components/battery_notes/translations/pl.json index 4686b76d1..b31c9e594 100644 --- a/custom_components/battery_notes/translations/pl.json +++ b/custom_components/battery_notes/translations/pl.json @@ -152,31 +152,6 @@ "unknown": "Wystąpił nieznany błąd." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Producent: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nWersja sprzętowa: {hw_version}", - "data": { - "name": "Nazwa", - "battery_type": "Typ baterii", - "battery_quantity": "Liczba baterii", - "battery_low_threshold": "Próg niskiego poziomu baterii", - "battery_low_template": "Szablon niskiego poziomu baterii", - "filter_outliers": "Filtr wartości odstających" - }, - "data_description": { - "name": "Pozostawienie pustego pola spowoduje pobranie nazwy z urządzenia źródłowego", - "battery_low_threshold": "0 użyje globalnego progu domyślnego", - "battery_low_template": "Szablon do określenia czy poziom naładowania baterii jest niski, powinien zwrócić wartość true, jeśli poziom jest niski.\nJest wymagany tylko dla niestandardowych raportów poziomu baterii", - "filter_outliers": "Filtruj duże spadki poziomu baterii, zmniejszając fałszywe wyzwalanie zdarzeń na urządzeniach, które sporadycznie zgłaszają poziomy baterii" - } - } - }, - "error": { - "orphaned_battery_note": "Powiązane urządzenie lub encja już nie istnieje dla tej Notatki Baterii.", - "unknown": "Wystąpił nieznany błąd." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/pt-BR.json b/custom_components/battery_notes/translations/pt-BR.json index 65408ced0..e73f7029e 100644 --- a/custom_components/battery_notes/translations/pt-BR.json +++ b/custom_components/battery_notes/translations/pt-BR.json @@ -152,31 +152,6 @@ "unknown": "Unknown error occurred." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Fabricante: {manufacturer}\nModelo: {model}\nModelo ID: {model_id}\nVersão de hardware: {hw_version}", - "data": { - "name": "Nome", - "battery_type": "Tipo de bateria", - "battery_quantity": "Quantidade de baterias", - "battery_low_threshold": "Limite de bateria fraca", - "battery_low_template": "Modelo de bateria fraca", - "filter_outliers": "Filtros atípicos" - }, - "data_description": { - "name": "Deixar em branco utilizará o nome do dispositivo de origem", - "battery_low_threshold": "0 irá usar o limite padrão global", - "battery_low_template": "Modelo para determinar se a bateria está fraca, deve retornar verdadeiro se estiver fraca\nNecessário apenas para níveis de bateria fora do padrão", - "filter_outliers": "Filtre grandes quedas no nível da bateria, reduzindo eventos de disparo falso em dispositivos que ocasionalmente relatam níveis incorretos." - } - } - }, - "error": { - "orphaned_battery_note": "O dispositivo ou entidade associados não existe mais para o Battery Notes.", - "unknown": "Ocorreu um erro desconhecido." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/pt.json b/custom_components/battery_notes/translations/pt.json index bc7167d03..9276280d2 100644 --- a/custom_components/battery_notes/translations/pt.json +++ b/custom_components/battery_notes/translations/pt.json @@ -152,31 +152,6 @@ "unknown": "Error desconhecido." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Fabricante: {manufacturer}\nModelo: {model}\nID do Modelo: {model_id}\nVersão de Hardware: {hw_version}", - "data": { - "name": "Nome", - "battery_type": "Tipo de bateria", - "battery_quantity": "Quantidade de baterias", - "battery_low_threshold": "Nivel de bateria baixa", - "battery_low_template": "Template de bateria baixa", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Deixar em branco fará com que tenha mesmo o nome que o dispositivo de origem", - "battery_low_threshold": "0 irá ser usado como valor por defeito para definir o descarregada", - "battery_low_template": "Template para determinar que a bateria está baixa, deve devolver true se estiver baixa\nÉ somente necessário para níveis de bateria non-standard", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "O dispositivo ou entidade associado não existe mais para esta Nota de Bateria.", - "unknown": "Error desconhecido." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/ru.json b/custom_components/battery_notes/translations/ru.json index 3ab2553ab..537bf2e94 100644 --- a/custom_components/battery_notes/translations/ru.json +++ b/custom_components/battery_notes/translations/ru.json @@ -152,31 +152,6 @@ "unknown": "Unknown error occurred." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Производитель: {manufacturer}\nМодель: {model}\nID модели: {model_id}\nРевизия: {hw_version}", - "data": { - "name": "Название", - "battery_type": "Тип батареи", - "battery_quantity": "Количество батарей", - "battery_low_threshold": "Порог низкого заряда батареи", - "battery_low_template": "Шаблон низкого заряда батареи", - "filter_outliers": "Фильтр скачков заряда" - }, - "data_description": { - "name": "Если оставить пустым, то название будет взято с исходного устройства", - "battery_low_threshold": "0 будет использовать общий порог по умолчанию", - "battery_low_template": "Шаблон низкого заряда батареи. В случае низкого заряда должен возвращать true.\nТребуется только для нестандартных уровней заряда батареи.", - "filter_outliers": "Отфильтровать скачки заряда, уменьшая ложные срабатывания событий для устройств, которые иногда сообщают заряд батареи с ошибками" - } - } - }, - "error": { - "orphaned_battery_note": "Привязанное к этой заметке устройство или объект больше не существует.", - "unknown": "Произошла неизвестная ошибка." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/sk.json b/custom_components/battery_notes/translations/sk.json index f5b0152bb..4af728bd3 100644 --- a/custom_components/battery_notes/translations/sk.json +++ b/custom_components/battery_notes/translations/sk.json @@ -152,31 +152,6 @@ "unknown": "Vyskytla sa neznáma chyba." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", - "data": { - "name": "Názov", - "battery_type": "Typ batérie", - "battery_quantity": "Množstvo batérie", - "battery_low_threshold": "Nízky prah batérie", - "battery_low_template": "Šablóna slabej batérie", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Ak ponecháte prázdne, názov sa prevezme zo zdrojového zariadenia", - "battery_low_threshold": "0 použije globálny predvolený prah", - "battery_low_template": "Šablóna na určenie nízkej úrovne batérie by mala vrátiť hodnotu true, ak je nízka\nPotrebné iba pri neštandardných úrovniach batérie", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Vyskytla sa neznáma chyba." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/sr-Latn.json b/custom_components/battery_notes/translations/sr-Latn.json index 7a06e9e8c..311f8f428 100644 --- a/custom_components/battery_notes/translations/sr-Latn.json +++ b/custom_components/battery_notes/translations/sr-Latn.json @@ -152,31 +152,6 @@ "unknown": "Nepoznata greška se dogodila!" } }, - "battery_note_options": { - "step": { - "init": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", - "data": { - "name": "Naziv", - "battery_type": "Tip baterije", - "battery_quantity": "Broj baterija", - "battery_low_threshold": "Nizak prag napunjenosti baterije", - "battery_low_template": "Šablon prazne baterije", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Ako ostavite prazno, naziv će preuzeti sa izvornog uređaja", - "battery_low_threshold": "0 će koristiti globalni podrazumevani prag", - "battery_low_template": "Šablon za određivanje da je baterija prazna, treba da vrati true ako je nizak nivo\nPotrebno samo za nestandardne nivoe baterije", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "Nepoznata greška se dogodila!" - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/sv-SE.json b/custom_components/battery_notes/translations/sv-SE.json index 441df59d8..aaf54f3d8 100644 --- a/custom_components/battery_notes/translations/sv-SE.json +++ b/custom_components/battery_notes/translations/sv-SE.json @@ -152,31 +152,6 @@ "unknown": "Okänt fel inträffade. " } }, - "battery_note_options": { - "step": { - "init": { - "description": "Tillverkare: {manufacturer}\nModell: {model}\nModell ID: {model_id}\nHårdvaruversion: {hw_version}", - "data": { - "name": "Namn", - "battery_type": "Batterityp", - "battery_quantity": "Antal batterier", - "battery_low_threshold": "Batteri lågt tröskelvärde", - "battery_low_template": "Batteri lågt template", - "filter_outliers": "Filtrera avvikande värden" - }, - "data_description": { - "name": "Genom att lämna blankt tas namnet från källenheten. ", - "battery_low_threshold": "0 kommer att använda den globala standardtröskelvärdet. ", - "battery_low_template": "Template för att bestämma om batteriet är lågt. Ska returnera true om lågt. Behövs endast för icke-standard batterinivåer. ", - "filter_outliers": "Filtrera bort stora batterinivåfall för att minska falska händelser på enheter som ibland rapporterar nivåer felaktigt" - } - } - }, - "error": { - "orphaned_battery_note": "Den associerade enheten eller entiteten finns inte längre för denna Batteri \nNotering .", - "unknown": "Okänt fel inträffade. " - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/tr.json b/custom_components/battery_notes/translations/tr.json index 74ff776fc..445225164 100644 --- a/custom_components/battery_notes/translations/tr.json +++ b/custom_components/battery_notes/translations/tr.json @@ -152,31 +152,6 @@ "unknown": "Bilinmeyen bir hata oluştu." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Üretici firma: {manufacturer}\nModel: {model}\nModel kodu: {model_id}\nDonanım sürümü: {hw_version}", - "data": { - "name": "İsim", - "battery_type": "Pil türü", - "battery_quantity": "Pil miktarı", - "battery_low_threshold": "Düşük pil eşiği", - "battery_low_template": "Düşük pil şablonu", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "Boş bırakıldığında kaynak cihazın ismi alınır", - "battery_low_threshold": "0 genel varsayılan eşiği kullanacaktır", - "battery_low_template": "Bir pilin zayıf olduğunu belirleyen şablon, zayıfsa true döndürmelidir\nYalnızca standart olmayan pil seviyeleri için gereklidir", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "İlişkili cihaz veya varlık bu Battery Notes için artık mevcut değildir.", - "unknown": "Bilinmeyen bir hata oluştu." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/uk.json b/custom_components/battery_notes/translations/uk.json index e29029992..064cf8905 100644 --- a/custom_components/battery_notes/translations/uk.json +++ b/custom_components/battery_notes/translations/uk.json @@ -152,31 +152,6 @@ "unknown": "Сталася невідома помилка." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Виробник: {manufacturer}\nМодель: {model}\nID моделі: {model_id}\nРевізія: {hw_version}", - "data": { - "name": "Назва", - "battery_type": "Тип батареї", - "battery_quantity": "Кількість батарей", - "battery_low_threshold": "Нижній поріг батареї", - "battery_low_template": "Шаблон низького заряду батареї", - "filter_outliers": "Відсіяти сторонні елементи" - }, - "data_description": { - "name": "Залишаючи незаповненим, буде взяте ім'я з основного пристрою", - "battery_low_threshold": "0 буде використовувати глобальний поріг за замовчуванням", - "battery_low_template": "Шаблон для визначення, коли заряд батареї низький - в такому випадку має повернути \"true\"\nПотрібен тільки для нестандартних рівнів батареї", - "filter_outliers": "Відфільтровуйте великі падіння рівня заряду акумулятора, зменшуючи кількість помилкових спрацьовувань на пристроях, які час від часу помилково повідомляють про рівень заряду" - } - } - }, - "error": { - "orphaned_battery_note": "Пов'язаний пристрій або об'єкт більше не існує для Battery Note", - "unknown": "Сталася невідома помилка." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/ur-IN.json b/custom_components/battery_notes/translations/ur-IN.json index ff494064e..de5cd4b6f 100644 --- a/custom_components/battery_notes/translations/ur-IN.json +++ b/custom_components/battery_notes/translations/ur-IN.json @@ -152,31 +152,6 @@ "unknown": "نامعلوم خرابی پیش آگئی." } }, - "battery_note_options": { - "step": { - "init": { - "description": "Manufacturer: {manufacturer}\nModel: {model}\nModel ID: {model_id}\nHardware version: {hw_version}", - "data": { - "name": "نام", - "battery_type": "بیٹری کی قسم", - "battery_quantity": "بیٹری کی مقدار", - "battery_low_threshold": "بیٹری کی کم حد", - "battery_low_template": " کم بیٹری ٹیمپلیٹ ", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "خالی چھوڑنے سے نام ماخذ آلہ سے لیا جائے گا۔", - "battery_low_threshold": "0 عالمی ڈیفالٹ حد استعمال کرے گا۔", - "battery_low_template": "بیٹری کم ہونے کا تعین کرنے کے لیے ٹیمپلیٹ، کم ہونے کی صورت میں درست ہونا چاہیے\nصرف غیر معیاری بیٹری کی سطح کے لیے ضروری ہے", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "The associated device or entity no longer exists for this Battery Note.", - "unknown": "نامعلوم خرابی پیش آگئی." - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/zh-Hans.json b/custom_components/battery_notes/translations/zh-Hans.json index 1784f488c..de1cdb1ea 100644 --- a/custom_components/battery_notes/translations/zh-Hans.json +++ b/custom_components/battery_notes/translations/zh-Hans.json @@ -152,31 +152,6 @@ "unknown": "发生未知错误。" } }, - "battery_note_options": { - "step": { - "init": { - "description": "制造商:{manufacturer}\n型号:{model}\n型号 ID:{model_id}\n硬件版本:{hw_version}", - "data": { - "name": "名称", - "battery_type": "电池类型", - "battery_quantity": "电池数量", - "battery_low_threshold": "低电量阈值", - "battery_low_template": "低电量模板", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "若留空,将使用来源装置的名称", - "battery_low_threshold": "若为零,将使用全域默认阈值", - "battery_low_template": "判断电池是否低电量的模板,若为低电量应回传 true\n仅在电池电量非标准时需要", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "此 Battery Note 的关联装置或实体已不存在。", - "unknown": "发生未知错误。" - } - }, "entity": { "binary_sensor": { "battery_low": { diff --git a/custom_components/battery_notes/translations/zh-Hant.json b/custom_components/battery_notes/translations/zh-Hant.json index a6eb1363e..3b926fa54 100644 --- a/custom_components/battery_notes/translations/zh-Hant.json +++ b/custom_components/battery_notes/translations/zh-Hant.json @@ -152,31 +152,6 @@ "unknown": "發生未知錯誤。" } }, - "battery_note_options": { - "step": { - "init": { - "description": "製造商:{manufacturer}\n型號:{model}\n型號 ID:{model_id}\n硬體版本:{hw_version}", - "data": { - "name": "名稱", - "battery_type": "電池類型", - "battery_quantity": "電池數量", - "battery_low_threshold": "低電量閾值", - "battery_low_template": "低電量模板", - "filter_outliers": "Filter outliers" - }, - "data_description": { - "name": "若留空,將使用來源裝置的名稱", - "battery_low_threshold": "若為零,將使用全域預設閾值", - "battery_low_template": "判斷電池是否低電量的模板,若為低電量應回傳 true\n僅在電池電量非標準時需要", - "filter_outliers": "Filter out large battery level drops, reducing falsely firing events on devices that erroneously report levels occasionally" - } - } - }, - "error": { - "orphaned_battery_note": "此 Battery Note 的關聯裝置或實體已不存在。", - "unknown": "發生未知錯誤。" - } - }, "entity": { "binary_sensor": { "battery_low": {