Skip to content

BU update#44

Merged
eXPerience83 merged 26 commits intobackup_v1.8.3from
main
Dec 6, 2025
Merged

BU update#44
eXPerience83 merged 26 commits intobackup_v1.8.3from
main

Conversation

@eXPerience83
Copy link
Owner

@eXPerience83 eXPerience83 commented Dec 6, 2025

PR Type

Enhancement, Tests, Bug fix


Description

  • Improve error messages in config flow and coordinator with context-specific details

  • Defer per-day entity cleanup until after initial data validation succeeds

  • Add comprehensive test coverage for config/options flows and coordinator retry logic

  • Implement AST-based translation key extraction to ensure all flow keys are defined

  • Update GitHub Actions to v6 and add package installation in test workflow

  • Fix manifest JSON formatting and add metadata consistency validation


Diagram Walkthrough

flowchart LR
  A["Config Flow & Coordinator"] -->|"Improved error messages"| B["Better debugging"]
  C["Setup Entry"] -->|"Defer cleanup"| D["Validate data first"]
  E["Test Suite"] -->|"AST parsing + new tests"| F["Translation validation"]
  G["Workflows"] -->|"Update actions v5→v6"| H["CI improvements"]
  I["Metadata"] -->|"Format & validate"| J["Consistency checks"]
Loading

File Walkthrough

Relevant files
Enhancement
3 files
config_flow.py
Clarify unexpected error message with flow context             
+1/-1     
sensor.py
Defer cleanup, add timeout/network error fallback messages
+9/-5     
pyproject.toml
Add project name and version metadata fields                         
+2/-0     
Tests
6 files
test_config_flow.py
Refactor stubs, add AST-based key extraction, expand validation tests
+242/-22
test_init.py
Add unload/reload tracking and happy path setup/unload test
+36/-1   
test_metadata.py
New metadata consistency tests for version and package alignment
+40/-0   
test_options_flow.py
New options flow validation tests covering language and forecast days
+130/-0 
test_sensor.py
Add SequenceSession helper with exhaustion guard and retry scenario
tests
+214/-5 
test_translations.py
New AST-based translation key extraction and coverage validation
+401/-0 
Configuration changes
6 files
format.yml
Update checkout and setup-python actions to v6                     
+2/-2     
hassfest.yml
Add branch filter and update checkout action to v6             
+2/-1     
lint.yml
Add branch filter and update checkout/setup-python to v6 
+3/-2     
tests.yml
Update actions to v6, add package install, set PYTHONPATH
+9/-2     
validate.yml
Add branch filter for push trigger                                             
+1/-0     
renovate.json
Add Renovate configuration for dependency updates               
+6/-0     
Documentation
1 files
CHANGELOG.md
Document 1.8.4 fixes and improvements                                       
+9/-0     
Bug fix
1 files
manifest.json
Fix JSON formatting and bump version to 1.8.4                       
+9/-9     

eXPerience83 and others added 26 commits November 24, 2025 22:40
…n-6.x

Update actions/setup-python action to v6
…ntegration

Improve config validation logging and test robustness
@eXPerience83 eXPerience83 merged commit 3e1875e into backup_v1.8.3 Dec 6, 2025
30 of 31 checks passed
@qodo-code-review
Copy link
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit logs: New error-handling paths and retries were added but no audit logging of critical actions
(e.g., connection/auth failures) with user/timestamp context is evident in the added
lines.

Referred Code
except aiohttp.ClientError as err:
    _LOGGER.error(
        "Connection error: %s",
        redact_api_key(err, user_input.get(CONF_API_KEY)),
    )
    errors["base"] = "cannot_connect"
except Exception as err:  # defensive
    _LOGGER.exception(
        "Unexpected error in Pollen Levels config flow while validating input: %s",
        redact_api_key(err, user_input.get(CONF_API_KEY)),
    )
    errors["base"] = "cannot_connect"

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
External input handling: While added changes improve error messages and retries, the diff does not show explicit
validation or sanitization for externally sourced data in these new paths, which may rely
on existing code outside the diff.

Referred Code
            "Pollen API timeout — retrying in %.2fs (attempt %d/%d)",
            delay,
            attempt + 1,
            max_retries,
        )
        await asyncio.sleep(delay)
        continue
    msg = redact_api_key(err, self.api_key)
    if not msg:
        msg = "Google Pollen API call timed out"
    raise UpdateFailed(f"Timeout: {msg}") from err

except aiohttp.ClientError as err:
    # Transient client-side issues (DNS reset, connector errors, etc.)
    if attempt < max_retries:
        delay = 0.8 * (2**attempt) + random.uniform(0.0, 0.3)
        _LOGGER.warning(
            "Network error to Pollen API — retrying in %.2fs (attempt %d/%d)",
            delay,
            attempt + 1,
            max_retries,


 ... (clipped 8 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Conditionally set PYTHONPATH for tests

Conditionally set PYTHONPATH in the test workflow to ensure tests for Python
3.14 run against the installed package rather than the local source code.

.github/workflows/tests.yml [45-49]

 - name: Run tests
   run: |
     pytest -q
   env:
-    PYTHONPATH: .
+    PYTHONPATH: ${{ matrix.python-version < '3.14' && '.' || '' }}
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a flaw in the CI workflow where tests for Python 3.14 would not validate the installed package as intended, and it provides a correct and concise fix.

Medium
Fix incorrect test setup logic

Correct the test_setup_entry_success_and_unload test by removing the
pre-population of hass.data to ensure it properly validates that
async_setup_entry populates this data itself.

tests/test_init.py [135-153]

 def test_setup_entry_success_and_unload() -> None:
     """Happy path should forward setup, register listener, and unload cleanly."""
 
     hass = _FakeHass()
     entry = _FakeEntry()
-    hass.data[integration.DOMAIN] = {entry.entry_id: "coordinator"}
 
     assert asyncio.run(integration.async_setup_entry(hass, entry)) is True
 
     assert hass.config_entries.forward_calls == [(entry, ["sensor"])]
     assert entry._update_listener is integration._update_listener  # noqa: SLF001
     assert entry._on_unload is entry._update_listener  # noqa: SLF001
+    assert entry.entry_id in hass.data[integration.DOMAIN]
 
     asyncio.run(entry._update_listener(hass, entry))  # noqa: SLF001
     assert hass.config_entries.reload_calls == [entry.entry_id]
 
     assert asyncio.run(integration.async_unload_entry(hass, entry)) is True
     assert hass.config_entries.unload_calls == [(entry, ["sensor"])]
     assert hass.data[integration.DOMAIN] == {}
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the test pre-populates data that the function under test should be creating, and the proposed change correctly fixes the test logic to properly verify the function's behavior.

Medium
General
Capture call arguments in test helper

Enhance the SequenceSession test helper to capture the arguments passed to its
get method, allowing for more thorough testing of API call parameters.

tests/test_sensor.py [258-279]

 class SequenceSession:
     """Session that returns a sequence of responses or raises exceptions."""
 
     def __init__(self, sequence: list[ResponseSpec | Exception]):
         self.sequence = sequence
         self.calls = 0
+        self.call_args: list[tuple[tuple, dict]] = []
 
-    def get(self, *_args, **_kwargs):
+    def get(self, *args, **kwargs):
+        self.call_args.append((args, kwargs))
         if self.calls >= len(self.sequence):
             raise AssertionError(
                 "SequenceSession exhausted; no more responses "
                 f"(calls={self.calls}, sequence_len={len(self.sequence)})."
             )
         item = self.sequence[self.calls]
         self.calls += 1
 
         if isinstance(item, Exception):
             raise item
 
         return FakeResponse(
             item.payload, status=item.status, headers=item.headers or {}
         )
  • Apply / Chat
Suggestion importance[1-10]: 4

__

Why: The suggestion proposes a useful enhancement to the new test helper SequenceSession, but it's not strictly necessary as the existing tests don't require argument inspection.

Low
  • More

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant