Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

bug: attributes using dict comprehension are incorrectly displayed #311

Copy link
Copy link
@niooss-ledger

Description

@niooss-ledger
Issue body actions

Description of the bug

When displaying (with some options detailed later) a module attribute initialized with dictionary comprehension, the documentation shows incorrect Python code and random characters.

For example,

TEST_0_INDEX_BY_KEY = {obj.key: obj for obj in []}

Is displayed in the documentation generated by mkdocs as:

TEST_0_INDEX_BY_KEY = {(key): _Hlfor obj in []}

The options I used to trigger this behaviour were separate_signature: true and signature_crossrefs: true.

To Reproduce

I reproduced using 3 files:

  • test_dict.py
TEST_0_INDEX_BY_KEY = {obj.key: obj for obj in []}
"""Showing `(key): <random characters>` instead of `obj.key: obj`."""

TEST_1_ACCESS_MEMBER = {obj: obj.member for obj in []}
"""Showing `obj: (member)` instead of `obj: obj.member`."""

TEST_2_LONG_NAME = {
    some_object_with_a_long_name: some_object_with_a_long_name
    for some_object_with_a_long_name in []
}
"""Showing `some_object_with_a_long_name: <more random characters>` instead of `some_object_with_a_long_name: some_object_with_a_long_name`."""
  • mkdocs.yml
site_name: Test Python dict comprehension

plugins:
  - mkdocstrings:
      handlers:
        python:
          options:
            separate_signature: true
            signature_crossrefs: true
  • docs/index.md
::: test_dict

The 3 files can be created with this command (which uses a base64-encoded tar.gz archive):

echo H4sIAAAAAAACA+3WUWvbMBAAYD/7Vxx5ah/myYljg+kGbWfG2JKNJQ8rYyiurcReI8tICl0Y++87OzFLN3Cg0IzCfS+OrYvucO5QrDCW52VmvXrrPBGGwjBor+jvK4uiyPHHLPKDMAiZ7zB/6I98B5hzAhtjUw3gaKVsX9yx9WdqnszmnPF30zfJF351w98nN/AKfqrb796d2MaAH2CpdHstK/j67Zc7GAxmhbovqxUszjDoPIYLnVa5kpAVqU4zK7R5vcBwY0Wag1rC4nC/hYc7uG6b2eeX19fJbMYnyeQq+bxP3YZ5Ushbofuyt6Fnu7jzfxIe7nKYc8g/fJy+5dPLSdLkcwEZJQXHcJFZfl/agqd8raoVr1Ip4t7V9utNjX1Bu+Ldh9X357yQSgs49l4fX/fujTjyLleZ8bZy/XQ9dmz+Ryzo5n8cDUc4//44YjT/p2BKK/bdMsejAD5tbaEqaE4EyJSstShEZUpVuW693qyw92Ls+Bew6xursZPbJ40Cm3WNPdrdA9Ttbn/uAVRtcTNz+AinT9TY31iIKVdVajcaq7F6Ix4GdWs808oYLZZmH+WQR2t+xZdllYsfnsz/0/wzP+zmfzgehe35H4xp/k8hjnGIuv+ANEmEEEIIIYQQQgghhBBCCCGEEPJs/QaXqtegACgAAA== | base64 -d | tar -xz

Then, install mkdocs and mkdocstrings-python and launch the server:

pip install mkdocs mkdocstrings-python
mkdocs serve

http://127.0.0.1:8000/ shows:

Image

The 3 Python snippets are:

TEST_0_INDEX_BY_KEY = {(key): _Z5for obj in []}

TEST_1_ACCESS_MEMBER = {obj: (member)for obj in []}

TEST_2_LONG_NAME = {some_object_with_a_long_name: _6Jpv7OmLiQU4bm2xsgNeOyqDsdmfor some_object_with_a_long_name in []}

It is also possible to run mkdocs build and read site/index.html:

Extract of site/index.html
<h2 id="test_dict.TEST_0_INDEX_BY_KEY" class="doc doc-heading">
            <span class="doc doc-object-name doc-attribute-name">TEST_0_INDEX_BY_KEY</span>


  <span class="doc doc-labels">
      <small class="doc doc-label doc-label-module-attribute"><code>module-attribute</code></small>
  </span>

</h2>
<pre class="highlight"><code class="language-python doc-signature">TEST_0_INDEX_BY_KEY = {(<span title="obj.key">key</span>): _xEfor <span title="obj">obj</span> in []}</code></pre>

    <div class="doc doc-contents ">

        <p>Showing <code>(key): &lt;random characters&gt;</code> instead of <code>obj.key: obj</code>.</p>

    </div>

</div>

<div class="doc doc-object doc-attribute">



<h2 id="test_dict.TEST_1_ACCESS_MEMBER" class="doc doc-heading">
            <span class="doc doc-object-name doc-attribute-name">TEST_1_ACCESS_MEMBER</span>


  <span class="doc doc-labels">
      <small class="doc doc-label doc-label-module-attribute"><code>module-attribute</code></small>
  </span>

</h2>
<pre class="highlight"><code class="language-python doc-signature">TEST_1_ACCESS_MEMBER = {<span title="obj">obj</span>: (<span title="obj.member">member</span>)for <span title="obj">obj</span> in []}</code></pre>

    <div class="doc doc-contents ">

        <p>Showing <code>obj: (member)</code> instead of <code>obj: obj.member</code>.</p>

    </div>

</div>

<div class="doc doc-object doc-attribute">



<h2 id="test_dict.TEST_2_LONG_NAME" class="doc doc-heading">
            <span class="doc doc-object-name doc-attribute-name">TEST_2_LONG_NAME</span>


  <span class="doc doc-labels">
      <small class="doc doc-label doc-label-module-attribute"><code>module-attribute</code></small>
  </span>

</h2>
<pre class="highlight"><code class="language-python doc-signature">TEST_2_LONG_NAME = {<span title="some_object_with_a_long_name">some_object_with_a_long_name</span>: _7kTCpbiedqLcznZoOnrjKhe3D9Gfor <span title="some_object_with_a_long_name">some_object_with_a_long_name</span> in []}</code></pre>

    <div class="doc doc-contents ">

        <p>Showing <code>some_object_with_a_long_name: &lt;more random characters&gt;</code> instead of <code>some_object_with_a_long_name: some_object_with_a_long_name</code>.</p>

    </div>

</div>
Without `separate_signature: true`, this generates code which is mostly right (a space is missing before `for`, and some extra parentheses are added):
TEST_0_INDEX_BY_KEY = {(obj.key): objfor obj in []}

TEST_1_ACCESS_MEMBER = {obj: (obj.member)for obj in []}

TEST_2_LONG_NAME = {some_object_with_a_long_name: some_object_with_a_long_namefor some_object_with_a_long_name in []}

With separate_signature: true and without signature_crossrefs: true, obj. disappears from the first two reproducers:

TEST_0_INDEX_BY_KEY = {(key): objfor obj in []}

TEST_1_ACCESS_MEMBER = {obj: (member)for obj in []}

TEST_2_LONG_NAME = {some_object_with_a_long_name: some_object_with_a_long_namefor some_object_with_a_long_name in []}

Expected behavior

I expect the Python code displayed by mkdocs to be consistent.

Environment information

I tested in a Python 3.13 container with the current git main version:

podman run --rm --net=host -it docker.io/library/python:3.13 bash

pip install 'git+https://github.com/mkdocs/mkdocs'
pip install 'git+https://github.com/mkdocstrings/python'

This installed:

$ pip freeze
click==8.3.0
colorama==0.4.6
ghp-import==2.1.0
griffe==1.14.0
Jinja2==3.1.6
Markdown==3.9
MarkupSafe==3.0.3
mergedeep==1.3.4
mkdocs @ git+https://github.com/mkdocs/mkdocs@f68e5fc18d3cd3811dbddfdeda1a57721f9e2e4e
mkdocs-autorefs==1.4.3
mkdocs-get-deps==0.2.0
mkdocstrings==0.30.1
mkdocstrings-python @ git+https://github.com/mkdocstrings/python@f25b2ecf73f30ac0ea836bec1aa60e87a360e23a
packaging==25.0
pathspec==0.12.1
platformdirs==4.4.0
pymdown-extensions==10.16.1
python-dateutil==2.9.0.post0
PyYAML==6.0.3
pyyaml_env_tag==1.1
six==1.17.0
watchdog==6.0.0
python -m mkdocstrings_handlers.python._internal.debug  # | xclip -selection clipboard
  • System: Linux-6.8.0-85-generic-x86_64-with-glibc2.39
  • Python: cpython 3.13.0 (/usr/local/bin/python)
  • Environment variables:
  • Installed packages:
    • mkdocstrings-python v1.18.3.dev1+gf25b2ec

I also tested with uv and several Python versions:

uv run --python python3.13 --with mkdocs --with mkdocstrings-python mkdocs serve

uv run --python python3.14 --with mkdocs --with mkdocstrings-python mkdocs serve

Additional context

I encountered this issue in a project where several classes are defined (ClsA, ClsB, ClsC), a global variable listes the classes (ALL_CLASSES = (ClsA, ClsB, ClsC)) and another global variable enables getting a class through their name:

CLASS_BY_NAME = {cls.name: cls for cls in ALL_CLASSES}

The documentation generated by mkdocs was buggy and this is what led to the first minimal reproducer I shared (TEST_0_INDEX_BY_KEY = {obj.key: obj for obj in []}).

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.