Skip to content

Commit a378ec4

Browse files
committed
lint fixes
1 parent 5f8e101 commit a378ec4

File tree

12 files changed

+133
-334
lines changed

12 files changed

+133
-334
lines changed

.github/workflows/combined.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020

2121
- name: Install dependencies
2222
run: |
23-
python3 -m pip install poetry~=1.8
23+
python3 -m pip install poetry~=2.2.1
2424
poetry install
2525
- uses: "actions/checkout@v5"
2626
- name: HACS validation

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
1717
- uses: actions/setup-python@v6
1818
with:
19-
python-version: 3.12
19+
python-version: 3.13
2020
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
2121
- uses: actions/cache@v4
2222
with:

.github/workflows/pull.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ jobs:
2525
- uses: "actions/checkout@v5"
2626
- uses: "actions/setup-python@v6"
2727
with:
28-
python-version: "3.12"
29-
- run: python3 -m pip install poetry~=1.8
28+
python-version: "3.13"
29+
- run: python3 -m pip install poetry~=2.2.1
3030
- run: poetry install
3131
- run: poetry run ./scripts/lint --no-fix
3232

@@ -39,9 +39,9 @@ jobs:
3939
- name: Setup Python
4040
uses: "actions/setup-python@v6"
4141
with:
42-
python-version: "3.12"
42+
python-version: "3.13"
4343
- name: Install requirements
44-
run: python3 -m pip install poetry~=1.8 && poetry install
44+
run: python3 -m pip install poetry~=2.2.1 && poetry install
4545
- name: Run tests
4646
run: |
4747
poetry run pytest --cov=./custom_components --cov-report=xml --cov-report=html

.ruff.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ lint.select = [
6464
"S317", # suspicious-xml-sax-usage
6565
"S318", # suspicious-xml-mini-dom-usage
6666
"S319", # suspicious-xml-pull-dom-usage
67-
"S320", # suspicious-xmle-tree-usage
6867
"S601", # paramiko-call
6968
"S602", # subprocess-popen-with-shell-equals-true
7069
"S604", # call-with-shell-equals-true
@@ -111,8 +110,6 @@ lint.ignore = [
111110
"SIM115", # Use context handler for opening files
112111
"TRY003", # Avoid specifying long messages outside the exception class
113112
"TRY400", # Use `logging.exception` instead of `logging.error`
114-
# Ignored due to performance: https://github.com/charliermarsh/ruff/issues/2923
115-
"UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)`
116113

117114
# May conflict with the formatter, https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
118115
"W191",

CONTRIBUTING.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Report a bug by [opening a new issue](../../issues/new/choose); it's that easy!
4141
- What actually happens
4242
- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
4343

44-
People *love* thorough bug reports. I'm not even kidding.
44+
People _love_ thorough bug reports. I'm not even kidding.
4545

4646
## Use a Consistent Coding Style
4747

@@ -53,14 +53,16 @@ Visual Studio Code is the recommended code editor for this project.
5353
This project includes a [devcontainer](./.devcontainer) configuration for an easy to use and consistent development environment. With this container you will have a stand alone Home Assistant instance running and already configured with the included [`configuration.yaml`](./config/configuration.yaml) file.
5454

5555
### Dependency management
56+
5657
Dependencies are managed via [Poetry](https://python-poetry.org). This will be managed for you automatically if using the dev container. If you wish to run outside of a dev container, you will need to install your dependencies manually:
5758

5859
```sh
59-
pip install poetry~=1.8
60+
pip install poetry~=2.2.1
6061
poetry install
6162
```
6263

6364
### Running tests
65+
6466
Use `./scripts/test` to invoke the test runner.
6567

6668
You must be within the virtual environment where project dependencies are installed:
@@ -78,11 +80,13 @@ poetry shell
7880
```
7981

8082
### Updating snapshots
83+
8184
If you've made a change to code that impacts a snapshot, your test will fail and the snapshot needs to be updated. To update snapshots run /bin/bash ./scripts/update_snapshots
8285

8386
Or in vscode you can run one of the two update snapshot tasks by opening the command pallete with cmd + p (or ctrl + p), and type `task Update` to see the tasks related to updating snapshots.
8487

8588
### Linting
89+
8690
In the devcontainer, linting and formatting runs on save and linting errors are showed as PROBLEMS in vscode.
8791

8892
To invoke a full lint/format, in vscode open the command pallete with cmd + p (or ctrl + p), and type `task Lint`.

custom_components/elasticsearch/es_publish_pipeline.py

Lines changed: 29 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,7 @@
7474
from custom_components.elasticsearch.es_gateway import ElasticsearchGateway
7575

7676
ALLOWED_ATTRIBUTE_KEY_TYPES = str
77-
ALLOWED_ATTRIBUTE_VALUE_TYPES = (
78-
tuple | dict | set | list | int | float | bool | str | None
79-
)
77+
ALLOWED_ATTRIBUTE_VALUE_TYPES = tuple | dict | set | list | int | float | bool | str | None
8078
SKIP_ATTRIBUTES = [
8179
"friendly_name",
8280
"entity_picture",
@@ -205,9 +203,7 @@ async def async_init(self, config_entry: ConfigEntry) -> None:
205203
if len(self._settings.change_detection_type) != 0:
206204
await self._listener.async_init()
207205
else:
208-
self._logger.warning(
209-
"No change detection type set. Disabling change listener."
210-
)
206+
self._logger.warning("No change detection type set. Disabling change listener.")
211207

212208
# We only need to initialize the poller if the user has configured a polling frequency
213209
if self._settings.polling_frequency > 0:
@@ -259,10 +255,7 @@ async def _populate_static_fields(self) -> None:
259255
if result.hostname:
260256
self._static_fields["host.hostname"] = result.hostname
261257

262-
if (
263-
self._hass.config.latitude is not None
264-
and self._hass.config.longitude is not None
265-
):
258+
if self._hass.config.latitude is not None and self._hass.config.longitude is not None:
266259
self._static_fields["host.location"] = [
267260
self._hass.config.longitude,
268261
self._hass.config.latitude,
@@ -275,14 +268,9 @@ async def _populate_static_fields(self) -> None:
275268
def reload_config_entry(self, msg) -> None:
276269
"""Reload the config entry."""
277270

278-
if (
279-
self._config_entry
280-
and self._config_entry.state == ConfigEntryState.LOADED
281-
):
271+
if self._config_entry and self._config_entry.state == ConfigEntryState.LOADED:
282272
self._logger.info("%s Reloading integration.", msg)
283-
self._hass.config_entries.async_schedule_reload(
284-
self._config_entry.entry_id
285-
)
273+
self._hass.config_entries.async_schedule_reload(self._config_entry.entry_id)
286274
else:
287275
self._logger.warning("%s Config entry not found or not loaded.", msg)
288276

@@ -317,9 +305,7 @@ def __init__(
317305
self._excluded_labels: list[str] = settings.excluded_labels
318306
self._included_entities: list[str] = settings.included_entities
319307
self._excluded_entities: list[str] = settings.excluded_entities
320-
self._change_detection_type: list[StateChangeType] = (
321-
settings.change_detection_type
322-
)
308+
self._change_detection_type: list[StateChangeType] = settings.change_detection_type
323309

324310
self._entity_registry = entity_registry.async_get(hass)
325311
self._label_registry = label_registry.async_get(hass)
@@ -349,94 +335,66 @@ def passes_filter(self, state: State, reason: StateChangeType) -> bool:
349335
if not self._passes_change_detection_type_filter(reason):
350336
return False
351337

352-
entity: RegistryEntry | None = self._entity_registry.async_get(
353-
state.entity_id
354-
)
338+
entity: RegistryEntry | None = self._entity_registry.async_get(state.entity_id)
355339

356340
if not entity:
357341
return self._reject(base_msg, "Entity not found in registry.")
358342

359343
device: DeviceEntry | None = (
360-
self._device_registry.async_get(entity.device_id)
361-
if entity.device_id
362-
else None
344+
self._device_registry.async_get(entity.device_id) if entity.device_id else None
363345
)
364346

365-
if self._exclude_targets and not self._passes_exclude_targets(
366-
entity=entity, device=device
367-
):
347+
if self._exclude_targets and not self._passes_exclude_targets(entity=entity, device=device):
368348
return False
369349

370-
if self._include_targets and not self._passes_include_targets(
371-
entity=entity, device=device
372-
):
350+
if self._include_targets and not self._passes_include_targets(entity=entity, device=device):
373351
return False
374352

375353
return self._accept(base_msg, "Entity passed all filters.")
376354

377-
def _passes_exclude_targets(
378-
self, entity: RegistryEntry, device: DeviceEntry | None
379-
) -> bool:
355+
def _passes_exclude_targets(self, entity: RegistryEntry, device: DeviceEntry | None) -> bool:
380356
base_msg = f"Processing exclusion filters for entity [{entity.entity_id}]: "
381357

382358
if entity.entity_id in self._excluded_entities:
383359
return self._reject(base_msg, "In the excluded entities list.")
384360

385361
if entity.area_id in self._excluded_areas:
386-
return self._reject(
387-
base_msg, f"In an excluded area [{entity.area_id}]."
388-
)
362+
return self._reject(base_msg, f"In an excluded area [{entity.area_id}].")
389363

390364
for label in entity.labels:
391365
if label in self._excluded_labels:
392-
return self._reject(
393-
base_msg, f"Excluded entity label present: [{label}]."
394-
)
366+
return self._reject(base_msg, f"Excluded entity label present: [{label}].")
395367

396368
if device is not None:
397369
if device.id in self._excluded_devices:
398-
return self._reject(
399-
base_msg, f"Attached to an excluded device [{device.id}]."
400-
)
370+
return self._reject(base_msg, f"Attached to an excluded device [{device.id}].")
401371

402372
for label in device.labels:
403373
if label in self._excluded_labels:
404-
return self._reject(
405-
base_msg, f"Excluded device label present: [{label}]."
406-
)
374+
return self._reject(base_msg, f"Excluded device label present: [{label}].")
407375

408376
return self._accept(base_msg, "Entity was not excluded by filters.")
409377

410-
def _passes_include_targets(
411-
self, entity: RegistryEntry, device: DeviceEntry | None
412-
) -> bool:
378+
def _passes_include_targets(self, entity: RegistryEntry, device: DeviceEntry | None) -> bool:
413379
base_msg = f"Processing inclusion filters for entity [{entity.entity_id}]: "
414380

415381
if entity.entity_id in self._included_entities:
416382
return self._accept(base_msg, "In the included entities list.")
417383

418384
if entity.area_id in self._included_areas:
419-
return self._accept(
420-
base_msg, f"In an included area [{entity.area_id}]."
421-
)
385+
return self._accept(base_msg, f"In an included area [{entity.area_id}].")
422386

423387
for label in entity.labels:
424388
if label in self._included_labels:
425-
return self._accept(
426-
base_msg, f"Included entity label present: [{label}]."
427-
)
389+
return self._accept(base_msg, f"Included entity label present: [{label}].")
428390

429391
if device is not None:
430392
if device.id in self._included_devices:
431-
return self._accept(
432-
base_msg, f"Attached to an included device [{device.id}]."
433-
)
393+
return self._accept(base_msg, f"Attached to an included device [{device.id}].")
434394

435395
for label in device.labels:
436396
if label in self._included_labels:
437-
return self._accept(
438-
base_msg, f"Included device label present: [{label}]."
439-
)
397+
return self._accept(base_msg, f"Included device label present: [{label}].")
440398

441399
return False
442400

@@ -574,18 +532,14 @@ async def async_init(self, static_fields: dict[str, Any]) -> None:
574532
"""Initialize the formatter."""
575533
self._static_fields = static_fields
576534

577-
def format(
578-
self, time: datetime, state: State, reason: StateChangeType
579-
) -> dict[str, Any]:
535+
def format(self, time: datetime, state: State, reason: StateChangeType) -> dict[str, Any]:
580536
"""Format the state change into a document."""
581537

582538
document = {
583539
"@timestamp": time.isoformat(),
584540
"event.action": reason.to_publish_reason(),
585541
"event.kind": "event",
586-
"event.type": "info"
587-
if reason == StateChangeType.NO_CHANGE
588-
else "change",
542+
"event.type": "info" if reason == StateChangeType.NO_CHANGE else "change",
589543
"hass.entity": {**self._state_to_extended_details(state)},
590544
"hass.entity.attributes": self._state_to_attributes(state),
591545
"hass.entity.value": state.state,
@@ -600,9 +554,7 @@ def format(
600554
def _state_to_extended_details(self, state: State) -> dict:
601555
"""Gather entity details from the state object and return a mapped dictionary ready to be put in an elasticsearch document."""
602556

603-
document = self._extended_entity_details.async_get(
604-
state.entity_id
605-
).to_dict()
557+
document = self._extended_entity_details.async_get(state.entity_id).to_dict()
606558

607559
# The logic for friendly name is in the state for some reason
608560
document["friendly_name"] = state.name
@@ -685,10 +637,7 @@ def filter_attribute(self, entity_id, key, value) -> bool:
685637

686638
def reject(msg: str) -> bool:
687639
if self._debug_attribute_filtering:
688-
message = (
689-
f"Filtering attributes for entity [{entity_id}]: Attribute [{key}] "
690-
+ msg
691-
)
640+
message = f"Filtering attributes for entity [{entity_id}]: Attribute [{key}] " + msg
692641
self._logger.debug(message)
693642

694643
return False
@@ -700,14 +649,10 @@ def reject(msg: str) -> bool:
700649
return reject(f"has a disallowed key type [{type(key)}].")
701650

702651
if not isinstance(value, ALLOWED_ATTRIBUTE_VALUE_TYPES):
703-
return reject(
704-
f"with value [{value}] has disallowed value type [{type(value)}]."
705-
)
652+
return reject(f"with value [{value}] has disallowed value type [{type(value)}].")
706653

707654
if key.strip() == "":
708-
return reject(
709-
"is empty after stripping leading and trailing whitespace."
710-
)
655+
return reject("is empty after stripping leading and trailing whitespace.")
711656

712657
return True
713658

@@ -717,9 +662,7 @@ def normalize_attribute_name(attribute_name: str) -> str:
717662
"""Create an ECS-compliant version of the provided attribute name."""
718663
# Normalize to closest ASCII equivalent where possible
719664
normalized_string = (
720-
unicodedata.normalize("NFKD", attribute_name)
721-
.encode("ascii", "ignore")
722-
.decode()
665+
unicodedata.normalize("NFKD", attribute_name).encode("ascii", "ignore").decode()
723666
)
724667

725668
# Replace all non-word characters with an underscore
@@ -868,14 +811,10 @@ async def publish(self) -> None:
868811

869812
try:
870813
if not await self._gateway.check_connection():
871-
self._logger.debug(
872-
"Skipping publishing as connection is not available."
873-
)
814+
self._logger.debug("Skipping publishing as connection is not available.")
874815
return
875816

876-
actions = self._add_action_and_meta_data(
877-
iterable=self._manager.sip_queue()
878-
)
817+
actions = self._add_action_and_meta_data(iterable=self._manager.sip_queue())
879818

880819
await self._gateway.bulk(actions=actions)
881820

mypy.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
[mypy]
3-
python_version = 3.12
3+
python_version = 3.13
44
platform = linux
55
plugins = pydantic.mypy
66
show_error_codes = true

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ norecursedirs = [
7878
expected-line-ending-format = "LF"
7979

8080
[tool.pylint.MAIN]
81-
py-version = "3.12"
81+
py-version = "3.13"
8282
ignore = [
8383
"tests",
8484
]

0 commit comments

Comments
 (0)