fix: handle a single-entry mapping in PositionalArgumentsFormatter - #844
Open
januththedev wants to merge 1 commit into
Open
januththedev wants to merge 1 commit into
januththedev wants to merge 1 commit into
Conversation
This branch has not been deployed
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.
PositionalArgumentsFormatterraisesKeyError: 0on a single-entry mappingDescription
PositionalArgumentsFormatter.__call__starts with:This is a port of
logging.LogRecord.__init__, whereargsis always a tuple produced bymsg, *args = ..., and a lone mapping argument therefore still needs unwrapping.structlog's
positional_argsis not always a tuple.ProcessorFormatter(pass_foreign_args=True)copiesLogRecord.argsstraight into the event dict, and the stdlib has already unwrapped a single mapping argument by then. Soargscan be adict.When it is,
len(args) == 1short-circuits true andargs[0]performs a dict lookup by integer key →KeyError: 0.Reproduction
With the documented
ProcessorFormattersetup (pass_foreign_args=True,use_get_message=False,PositionalArgumentsFormatterinprocessors):Directly:
Two keys work and one key does not — a plain arity asymmetry. Because
KeyErroris not a formatting error,loggingcannot swallow it the way it swallowsTypeError; the entry is silently dropped and only a--- Logging error ---trace on stderr remains. structlog's own suite already asserts this dict shape is produced:tests/test_stdlib.py::test_pass_foreign_args_true_sets_positional_args_keysetspositional_args = {"foo": "bar"}.The change
Skip the unwrap branch when
positional_argsalready is a mapping, so it flows into theevent % argsline unchanged:Every previously-working input takes exactly the same path, and a mapping is already the correct argument form for keyword placeholders. The docstring is updated to record that a mapping is used as-is.
Tests
TestPositionalArgumentsFormatter::test_formats_single_entry_mappingfails before the change withKeyError: 0atsrc/structlog/stdlib.py:802, and passes after.pytest tests/test_stdlib.py -q→ 142 passed (141 before).4 failed, 898 passed, 20 skipped. Those 4 are pre-existing and unrelated —tests/test_packaging.py::TestLegacyMetadataHackfails withPackageNotFoundErrorbecause the package is not pip-installed in my environment. The count went 897 → 898 by exactly this one new test.ruff checkandruff format --checkclean on both files.I checked the 9 open PRs and 25 open issues: PR #832 wraps
event_dict["event"] %= argsincontextlib.suppress(TypeError, ValueError), but theKeyErrorhappens earlier, on theargs[0]subscript, so it does not cover this.