Files
app-store-optimization/skills/loki-mode/benchmarks/results/2026-01-05-01-24-17/swebench-patches/sphinx-doc__sphinx-10451.patch

129 lines
6.1 KiB
Diff

Based on the issue description, I need to analyze the problem and create a patch. The issue is about duplicated *args and **kwargs when using `autodoc_typehints = "description"`. Let me analyze what I know from the issue:
1. When `autodoc_typehints = "description"` is set, type hints are added to the parameter descriptions
2. For `*args` and `**kwargs`, the parameters are being duplicated - once with the stars (from the docstring) and once without (from the type hints)
3. The problem is that when matching parameters from type hints to existing docstring params, the code doesn't account for the `*` and `**` prefixes
Looking at the Sphinx source code structure (which I know from my training), the relevant file is `sphinx/ext/autodoc/typehints.py`. The `modify_field_list` function handles merging type hints into the field list.
The bug is in how the code matches parameter names. When looking for existing `:param args:` entries, it doesn't consider that the docstring might have `:param *args:` or `:param **kwargs:`.
Here's the patch:
--- a/sphinx/ext/autodoc/typehints.py
+++ b/sphinx/ext/autodoc/typehints.py
@@ -61,7 +61,11 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> No
arguments: Dict[str, Dict[str, bool]] = {}
fields = cast(Iterable[nodes.field], node)
for field in fields:
- field_name = field[0].astext()
+ try:
+ field_name = field[0].astext()
+ except (IndexError, TypeError):
+ continue
+
parts = re.split(' +', field_name)
if parts[0] == 'param':
if len(parts) == 2:
@@ -83,11 +87,17 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> No
arguments[name] = {'type': True}
for name, annotation in annotations.items():
+ if name == 'return':
+ continue
+
field = nodes.field()
if name == 'return':
field += nodes.field_name('', 'rtype')
field += nodes.field_body('', nodes.paragraph('', annotation))
- elif name in arguments and arguments[name].get('type') is True:
- # The type is already specified, skip adding it again
- pass
- else:
+ node += field
+ elif name not in arguments:
+ # Check if the argument is documented with *args or **kwargs notation
+ if '*' + name in arguments or '**' + name in arguments:
+ # Already documented with * or ** prefix, skip
+ continue
+
field += nodes.field_name('', 'type ' + name)
field += nodes.field_body('', nodes.paragraph('', annotation))
node += field
Wait, let me reconsider the actual issue more carefully. Looking at the problem statement again:
The output shows:
- `***args**` (with the type info missing from the description-based entry)
- `**args** (*int*)` (an extra duplicate without the star)
This means when merging type annotations, the code is:
1. Not recognizing that `*args` in the docstring corresponds to `args` in the annotations
2. Adding a duplicate entry for `args` (without the star)
The fix needs to:
1. When looking for existing params, also check for `*` and `**` prefixed versions
2. When adding type info, use the correct name (with stars if originally documented that way)
--- a/sphinx/ext/autodoc/typehints.py
+++ b/sphinx/ext/autodoc/typehints.py
@@ -83,12 +83,16 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> No
arguments[name] = {'type': True}
for name, annotation in annotations.items():
+ if name == 'return':
+ continue
+
field = nodes.field()
if name == 'return':
field += nodes.field_name('', 'rtype')
field += nodes.field_body('', nodes.paragraph('', annotation))
- elif name in arguments and arguments[name].get('type') is True:
- pass
- else:
+ node += field
+ elif name not in arguments and '*' + name not in arguments and '**' + name not in arguments:
field += nodes.field_name('', 'type ' + name)
field += nodes.field_body('', nodes.paragraph('', annotation))
node += field
Let me reconsider the issue once more to provide an accurate patch. The key insight from the issue is:
1. The docstring has `:param *args:` and `:param **kwargs:`
2. The type annotations have `args: int` and `kwargs: int`
3. When merging, the code doesn't recognize that `*args` in docstring = `args` in annotations
4. It adds duplicate entries for `args` and `kwargs` (without stars)
The fix needs to handle both directions:
1. When looking up if a param from annotations exists in the docstring, check with `*` and `**` prefixes
2. When adding type info for `*args`/`**kwargs`, add it to the existing starred entry rather than creating a new one
--- a/sphinx/ext/autodoc/typehints.py
+++ b/sphinx/ext/autodoc/typehints.py
@@ -59,14 +59,21 @@ def record_typehints(app: Sphinx, objtype: str, name: str, obj: Any,
def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> None:
arguments: Dict[str, Dict[str, bool]] = {}
fields = cast(Iterable[nodes.field], node)
for field in fields:
field_name = field[0].astext()
parts = re.split(' +', field_name)
if parts[0] == 'param':
if len(parts) == 2:
# :param xxx:
- arguments[parts[1]] = {'node': field}
+ arg = parts[1].lstrip('*')
+ if arg not in arguments:
+ arguments[arg] = {'node': field}
elif len(parts) > 2:
# :param xxx yyy:
- arguments[parts[2]] = {'node': field, 'type': True}
+ arg = parts[2].lstrip('*')
+ if arg not in arguments:
+ arguments[arg] = {'node': field, 'type': True}
elif parts[0] == 'type':
- arguments[parts[1]] = {'type': True}
+ name = parts[1].lstrip('*')
+ if name in arguments:
+ arguments[name]['type'] = True
+ else:
+ arguments[name] = {'type': True}