Skip to content

fix: render dict **-unpacking as **value instead of None: value#467

Merged
pawamoy merged 1 commit into
mkdocstrings:mainfrom
gaoflow:fix-dict-unpacking-render
Jun 22, 2026
Merged

fix: render dict **-unpacking as **value instead of None: value#467
pawamoy merged 1 commit into
mkdocstrings:mainfrom
gaoflow:fix-dict-unpacking-render

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 20, 2026

Copy link
Copy Markdown
Contributor
  • I did not use AI
  • I used AI and thoroughly reviewed every code/docs change

Description

ExprDict.iterate renders the None key that the AST uses to mark a **-unpacked value as a literal None: value, producing invalid (and semantically wrong) Python:

def f(a={**base, "x": 1}): ...   # default renders as  {None: base, 'x': 1}
def g(b={**d1, **d2}): ...       # default renders as  {None: d1, None: d2}

_build_dict faithfully preserves the AST's None-key unpacking marker, but iterate then renders it with the literal text "None". This affects any rendered signature/default/annotation containing a dict with **-unpacking.

The fix renders entries whose key is the unpacking marker as **value (no key: part):

def f(a={**base, "x": 1}): ...   # now renders as  {**base, 'x': 1}
def g(b={**d1, **d2}): ...       # now renders as  {**d1, **d2}

A genuine None literal key is an ast.Constant, not the AST's unpacking marker, so it is left untouched ({None: 1, "y": 2} still renders as {None: 1, 'y': 2}).

Verification

  • Added test_render_dict_with_unpacking covering **-spread, multiple spreads, and the literal-None-key case.
  • Round-trip oracle: every rendered form now re-parses AST-equal to its source.
  • Full griffelib suite passes with no new failures (the unrelated test_finder.py::test_pth_file_handling* and test_api/test_git failures are pre-existing on this environment, identical with the change stashed).

This pull request was prepared with the assistance of AI, under my direction and review.

`ExprDict.iterate` rendered the `None` key that the AST uses to mark a
`**`-unpacked value as a literal `None: value`, producing invalid Python
(e.g. `{None: base, 'x': 1}` for `{**base, 'x': 1}`). Render those entries
as `**value`. A genuine `None` literal key is an `ast.Constant` rather
than the AST's unpacking marker, so it is preserved.

@pawamoy pawamoy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks a lot @gaoflow! It all looks good 🙂

@pawamoy pawamoy merged commit 74ddbbf into mkdocstrings:main Jun 22, 2026
34 checks passed
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.

2 participants