Skip to content

fix: adding a user whose PIN is taken or too long names them in a message Home Assistant accepts - #1810

Merged
raman325 merged 1 commit into
mainfrom
fix/hassfest-quoted-placeholders
Nov 4, 2026
Merged

raman325 merged 1 commit into
mainfrom
fix/hassfest-quoted-placeholders

Conversation

@raman325

@raman325 raman325 commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Proposed change

Hassfest now rejects a translation string with a placeholder inside single quotes. Two add_user refusals wrote "'{name}': ...", so Hassfest failed on every pull request, and the Auto Merge check failed with it. That's why every open Dependabot PR is red.

The two messages now use the same wording as the editor's errors for the same rules (pin_not_unique_in_block, pin_too_long_in_block):

Key Before After
user_pin_not_unique '{name}': Another user already has this PIN. {name} has a PIN another user already has.
user_pin_too_long '{name}': PIN may be at most 255 characters. {name} has a PIN longer than 255 characters.

The change covers strings.json, translations/en.json and the tests that match the rendered messages.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (which adds functionality)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

🤖 Generated with Claude Code

…sage Home Assistant accepts

Hassfest now rejects translation strings with a placeholder inside single
quotes, so the two add_user refusals that wrote "'{name}': ..." failed
validation on every pull request. They now use the same wording as the
editor's errors for the same rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: a38362a6ba68
Copilot AI balanced review requested due to automatic review settings November 4, 2026 04:45
@github-actions github-actions Bot added python Pull requests that update Python code bug Something isn't working labels Nov 4, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

There are no active review issues for the error-message wording updates addressing Hassfest’s placeholder restrictions.

No open issues 🎉

What changed in this PR

This PR updates Lock Code Manager’s add_user error messages to address Hassfest’s rejection of single-quoted placeholders, which was blocking checks on dependency-update PRs.

Changes:

  • Rewords duplicate-PIN and overlong-PIN errors while preserving the user’s name.
  • Keeps source strings and English translations aligned.
  • Updates service-test expectations to match the revised messages.
File Description
tests/​test_services.py Updates expected duplicate-PIN and overlong-PIN error messages.
custom_components/​lock_code_manager/​translations/​en.json Applies the revised wording to English translations.
custom_components/​lock_code_manager/​strings.json Removes single quotes around name placeholders in both source messages.

Review effort: Balanced

@codecov

codecov Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
3628 1 3627 12
View the top 1 failed test(s) by shortest run time
tests.properties.test_shared_lock_machine.TestSharedLockMachine::runTest
Stack Traces | 8.49s run time
data = data(...)

    @settings
>   @given(st.data())
               ^^^^^^^

.../hostedtoolcache/Python/3.14.10......................../x64/lib/python3.14................../site-packages/hypothesis/stateful.py:154: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../hostedtoolcache/Python/3.14.10......................../x64/lib/python3.14.../site-packages/hypothesis/core.py:1001: in test
    return self.test(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
.../hostedtoolcache/Python/3.14.10......................../x64/lib/python3.14................../site-packages/hypothesis/stateful.py:266: in run_state_machine
    machine.check_invariants(settings, output, cd._stateful_run_times)
.../hostedtoolcache/Python/3.14.10......................../x64/lib/python3.14................../site-packages/hypothesis/stateful.py:531: in check_invariants
    result = invar.function(self)
             ^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = SharedLockMachine({})

    @invariant()
    def loaded_slots_are_in_sync(self) -> None:
        hass = self.hass
        expected = {
            (
                in_sync_entity_id(hass, position.entry, index + 1, lock),
                code_entity_id(hass, position.entry, index + 1, lock),
            ): PINS[index + 1]
            for index, position in enumerate(self.positions)
            if position.loaded and position.entry is not None
            for lock in position.holds
            if self._ready(lock)
        }
    
        def _in_sync() -> bool:
            return all(
                (in_sync := hass.states.get(in_sync_id)) is not None
                and in_sync.state == STATE_ON
                and (code := hass.states.get(code_id)) is not None
                and code.state == pin
                for (in_sync_id, code_id), pin in expected.items()
            )
    
        async def _async_ticks_until_in_sync() -> bool:
            for _ in range(MAX_TICKS_TO_SYNC):
                if _in_sync():
                    return True
                await async_advance_clock(
                    hass, self.freezer, TICK_INTERVAL.total_seconds(), settle=False
                )
                await self._async_settle()
            return _in_sync()
    
>       assert self._run(_async_ticks_until_in_sync(), "loaded_slots_are_in_sync"), (
            f"slots not in sync with the lock's codes after {MAX_TICKS_TO_SYNC} "
            f"sync ticks: {expected}"
        )
E       AssertionError: slots not in sync with the lock's codes after 8 sync ticks: {('binary_sensor.shared_1_user1_test_1_in_sync', 'sensor.shared_1_user1_test_1_pin'): '1357'}
E       assert False
E        +  where False = _run(<coroutine object SharedLockMachine.loaded_slots_are_in_sync.<locals>._async_ticks_until_in_sync at 0x74da337b0590>, 'loaded_slots_are_in_sync')
E        +    where _run = SharedLockMachine({})._run
E        +    and   <coroutine object SharedLockMachine.loaded_slots_are_in_sync.<locals>._async_ticks_until_in_sync at 0x74da337b0590> = <function SharedLockMachine.loaded_slots_are_in_sync.<locals>._async_ticks_until_in_sync at 0x74da337d0ca0>()

tests/properties/test_shared_lock_machine.py:939: AssertionError

During handling of the above exception, another exception occurred:

self = <hypothesis.stateful.SharedLockMachine.TestCase testMethod=runTest>

    def runTest(self):
>       run_state_machine_as_test(cls, settings=self.settings)

.../hostedtoolcache/Python/3.14.10......................../x64/lib/python3.14................../site-packages/hypothesis/stateful.py:558: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../hostedtoolcache/Python/3.14.10......................../x64/lib/python3.14................../site-packages/hypothesis/stateful.py:308: in run_state_machine_as_test
    state_machine_test()
.../hostedtoolcache/Python/3.14.10......................../x64/lib/python3.14................../site-packages/hypothesis/stateful.py:154: in run_state_machine
    @given(st.data())
               ^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <hypothesis.internal.conjecture.datatree.TreeRecordingObserver object at 0x74da33d6dda0>
status = Status.INTERESTING
interesting_origin = InterestingOrigin(exc_type=<class 'AssertionError'>, filename='.../tests/properties/test_shared_lock_machine.py', lineno=939, context=(), group_elems=())

    def conclude_test(
        self, status: Status, interesting_origin: InterestingOrigin | None
    ) -> None:
        """Says that ``status`` occurred at node ``node``. This updates the
        node if necessary and checks for consistency."""
        if status == Status.OVERRUN:
            return
        i = self._index_in_current_node
        node = self._current_node
    
        if i < len(node.values) or isinstance(node.transition, Branch):
>           raise FlakyStrategyDefinition.with_detail(
                "The second run stopped drawing earlier than the first run, "
                "which continued to draw more data.\n"
            )
E           hypothesis.errors.FlakyStrategyDefinition: Inconsistent data generation! Data generation behaved differently between test cases. Is your data generation depending on external state?
E           
E           The second run stopped drawing earlier than the first run, which continued to draw more data.

.../hostedtoolcache/Python/3.14.10......................../x64/lib/python3.14.../internal/conjecture/datatree.py:1163: FlakyStrategyDefinition

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@raman325
raman325 merged commit 430ca33 into main Nov 4, 2026
20 of 22 checks passed
@raman325
raman325 deleted the fix/hassfest-quoted-placeholders branch November 4, 2026 05:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working python Pull requests that update Python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants