Repository navigation
Stop re-wrapping an inherited set_password once per MRO class - #770
Open
januththedev wants to merge 1 commit into
Open
januththedev wants to merge 1 commit into
januththedev wants to merge 1 commit into
Conversation
januththedev
force-pushed
the
fix/set-password-rewrap
branch
from
October 3, 2026 10:28
7c4f8f2 to
3f381f5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
KeyringBackendMetare-wraps an inheritedset_passwordonce per class in the MRODescription
The metaclass runs this for every class it creates. When a subclass does not define its own
set_password,cls.set_passwordresolves through the MRO to a base's already-wrapped function, so the wrapper is applied again — nesting once per class in the MRO. Each layer re-runs_validate_username, so oneset_password()call validates N times.Why that's wrong
The wrapper exists to validate the username exactly once per call. Two consequences:
#668empty-usernameDeprecationWarningfires N times, and because each nested layer has a distinctstackleveltarget,stacklevel=3resolves to keyring's ownbackend.py:60for the inner layers instead of the caller — a misattributed location, which breaks module-scoped warning filters.Reproduction
Counting real
_validate_usernameinvocations across every registered backend, before the fix:After,
DBusKeyringKWallet4is 1, one warning is emitted, and it is attributed to the caller's line.ChainerBackendcorrectly stays at 2 — it validates itself and then delegates to a chained backend, which are two distinct objects needing one validation each.The marker is set after
functools.wraps(which copies__dict__), so it can never be inherited from an unmarked original.Tests
tests/test_backend_meta.py, two tests:test_validates_username_once— the defect, failingassert 2 == 1before the fix.test_overridden_set_password_is_still_wrapped— guards against an over-broad fix: a subclass that supplies its ownset_passwordmust still be wrapped.The 3 pre-existing failures are identical before and after and are environmental, not keyring bugs:
test_Windows.py::test_read_utf8_passwordis a pywin32-ctypes incompatibility in the test helper, andtest_multiprocess.pyfails withModuleNotFoundError: No module named 'tests.test_multiprocess'(Windows spawn +--import-mode importlib; upstream issue #737 / PR #761 address this). The 76 skips are the OS-keychain backends (macOS,kwallet,libsecret,SecretService), which need D-Bus, secretstorage, or the macOS Security framework. Ruff reports 10 findings inbackend.pythat are pre-existing at HEAD (identical set, line-shifted by 5); the new test file is clean.Relationship to open work
Issue #717 ("KeyringBackend
set_password()keyword argument renamed by wrapper") and PR #769 touch this exact function, but reading #769's diff, it only renamessystemtoservice— it does not address re-wrapping, so this is a distinct unfixed defect. A maintainer will likely want to land the two together. The news fragment isnewsfragments/+set-password-wrap.bugfix.rst, using the skeleton's+form since there is no issue ID for this specific fix.