Skip to content

Extract base classes for unknown-reference repair boilerplate#1255

Draft
frenckatron wants to merge 1 commit into
frenck:mainfrom
frenckatron:frenckatron/extract-unknown-reference-base
Draft

Extract base classes for unknown-reference repair boilerplate#1255
frenckatron wants to merge 1 commit into
frenck:mainfrom
frenckatron:frenckatron/extract-unknown-reference-base

Conversation

@frenckatron
Copy link
Copy Markdown
Collaborator

@frenckatron frenckatron commented May 20, 2026

What

Pulls the duplicated async_inspect boilerplate out of 10 repair modules into two abstract base classes on repairs.py, and re-enables pylint's duplicate-code check that was disabled because of it.

Why

Six ectoplasms/automation/repairs/unknown_*_references.py files and four unknown_source.py files (switch_as_x, integration, utility_meter, trend) were structurally identical — they differed only in the registry queried, the attribute looked up on the entity, and one placeholder key. The shared code blocked duplicate-code from being usefully enabled.

How

Two abstract bases in custom_components/spook/repairs.py:

  • AbstractSpookEntityComponentUnknownReferencesRepair walks an EntityComponent (DATA_INSTANCES). Subclasses provide three hooks:

    • _async_setup_inspection — cache known IDs once per inspection cycle.
    • _should_inspect_entity — defaults True; overridden in unknown_entity_references to skip disabled automations.
    • _async_compute_unknown_references — per-entity lookup, returns the set of unknown IDs.

    The base owns the unavailable-entity skip, the issue payload (with configurable entity_label, reference_label, edit_url_pattern) and the debug log.

  • AbstractSpookEntityPlatformUnknownSourceRepair walks an EntityPlatform (DATA_ENTITY_PLATFORM), optionally filtered to a single source_platform_domain. Subclasses only implement _get_source_entity_id to expose the private source attribute.

Each leaf module is now ~45 lines that read as the 5 attributes that actually differentiate them.

Side effects:

  • duplicate-code is back on the active pylint checks. min-similarity-lines = 12 and ignore-imports/ignore-signatures are set so trivial header overlap (imports, inspect_events = {...}) doesn't trigger.
  • Four files outside this mission's scope still mirror each other intentionally (the person/services/{add,remove}_device_tracker.py pair and the proximity/repairs/unknown_{ignored_zones,tracked_entities}.py pair). They carry a one-line # pylint: disable=duplicate-code with the reason; deduping them is a separate concern.
  • Stats: 10 leaf modules −436 lines, base infra +154 lines, leaf modules −244 net.

Testing

  • uv run ruff check custom_components/ → clean.
  • uv run ruff format --check custom_components/ → clean.
  • uv run pre-commit run pylint --all-files → only the pre-existing async_timeout import-error in blueprint/services/importer.py (unrelated, depends on Python <3.13.2; CI installs it transitively). 0 duplicate-code warnings after the refactor; main has the rule disabled altogether.
  • All 11 touched modules import cleanly under uv run python -c "import …".

Quality Report

Changes: 16 files changed, 357 insertions(+), 436 deletions(-)

Code scan: clean

Tests: failed (command not found)

Branch hygiene: 1 issue(s)

  • Branch is not pushed to remote

Generated by Kōan post-mission quality pipeline

Ten repair modules ground out near-identical async_inspect bodies — six
under ectoplasms/automation/repairs/unknown_*_references.py and four
unknown_source.py files across switch_as_x, integration, utility_meter
and trend. Each variant differed only in the registry queried, the
attribute looked up on the entity, and a placeholder key.

This pulls the boilerplate into two abstract bases on repairs.py:

- AbstractSpookEntityComponentUnknownReferencesRepair walks an
  EntityComponent (DATA_INSTANCES) and exposes three hooks:
  _async_setup_inspection (cache known IDs once per cycle),
  _should_inspect_entity (defaults True, overridden for "skip disabled
  automations"), and _async_compute_unknown_references (per-entity
  lookup). The issue payload and debug logging are built once at the
  base.

- AbstractSpookEntityPlatformUnknownSourceRepair walks an
  EntityPlatform (DATA_ENTITY_PLATFORM), optionally filtered to a
  single source_platform_domain, and asks subclasses only for the
  per-entity _get_source_entity_id.

Net: ~440 lines deleted, ~155 of base infra added. The 10 leaf modules
now read as the ~5 attributes that actually differentiate them.

A side effect is that pylint's duplicate-code can be re-enabled
without flooding the report. The four remaining pre-existing
duplicates outside this mission's scope (person services pair,
proximity repairs pair) carry a local pylint: disable=duplicate-code
explaining the intent; min-similarity-lines is also bumped to 12 so
trivial header overlap (imports, inspect_events sets) doesn't trigger.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ac9c1dd9-77ac-4327-8fb3-8be26270508e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant