Bug Report: `nbdev` Parser `IndexError` on `@patch_to` with Keyword Arguments
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- jupyter-notebook, python
- Domain
- devtools, documentation
Research direction
Start in nbdev/doclinks.py at patch_name and reproduce the failure through nbdev_export using the notebook setup described in the issue. Verify that @patch_to(cls=MyClass) no longer raises IndexError and that the export completes successfully, while preserving positional-argument behavior.
Written by the indexing model from the issue text.
Description
Bug Report: nbdev Parser IndexError on @patch_to with Keyword Arguments
Description
The nbdev AST parser fails with an IndexError when it encounters the @patch_to decorator used with a keyword argument (e.g., cls=ClassName) instead of a positional argument. This occurs during processes like nbdev_export that involve indexing symbols.
Root Cause
In nbdev/doclinks.py, the patch_name function attempts to extract the class name being patched. It explicitly assumes the class is the first positional argument in the decorator's AST representation.
File: nbdev/doclinks.py
Code Snippet:
elif nm=='patch_to': a = d.args[0] # <--- CRASHES HERE
If d.args is empty (which happens when a keyword argument is used), d.args[0] raises an IndexError.
Reproduction Proof
As demonstrated in the reproduction script above:
- Input:
@patch_to(MyClass)->d.argscontains 1 element. Result: Success. - Input:
@patch_to(cls=MyClass)->d.argsis empty;d.keywordscontains the data. Result: IndexError.
Impact
Users cannot use standard Python keyword argument syntax for the @patch_to decorator without breaking the nbdev export/documentation pipeline.
Recommended Fix
The parser should check both d.args and d.keywords. A robust fix would be:
elif nm=='patch_to':
a = d.args[0] if d.args else [k.value for k in d.keywords if k.arg=='cls'][0]
Reproduce with
import os
import nbformat as nbf
import traceback
from nbdev.doclinks import nbdev_export
# 1. Setup a clean minimal nbdev project structure
!rm -rf /content/reproduction_project
!mkdir -p /content/reproduction_project/reproduction_project
%cd /content/reproduction_project
# 2. Manually create pyproject.toml
with open('pyproject.toml', 'w') as f:
f.write("""[project]\nname = \"reproduction_project\"\nauthors = [{name=\"Test\"}]\n\n[tool.nbdev]\nlib_name = \"reproduction_project\"\nuser = \"testuser\"\nlib_path = \"reproduction_project\"\nnbs_path = \".\"\nrecursive = false\ntst_flags = \"notest\"\n""")
# 3. Create a notebook with the bug-triggering code and required default_exp
nb = nbf.v4.new_notebook()
# Adding default_exp to satisfy nbdev requirements
code = """#| default_exp core\n#| export\nfrom fastcore.utils import patch_to\n\nclass MyClass: pass\n\n@patch_to(cls=MyClass)\ndef my_method(self): \n return \"Hello World\"\n"""
nb['cells'] = [nbf.v4.new_code_cell(code)]
with open('00_core.ipynb', 'w') as f:
nbf.write(nb, f)
print("\n--- Attempting nbdev_export (Expected to trigger IndexError) ---")
try:
nbdev_export()
except Exception as e:
print(f"\nCaught Error: {type(e).__name__}: {e}")
traceback.print_exc()
I get
--- Attempting nbdev_export (Expected to trigger IndexError) ---
Caught Error: IndexError: list index out of range
Traceback (most recent call last):
File "/tmp/ipykernel_2846/2623198774.py", line 26, in <cell line: 0>
nbdev_export()
File "/usr/local/lib/python3.12/dist-packages/fastcore/script.py", line 161, in _f
if not mod: return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/nbdev/doclinks.py", line 156, in nbdev_export
_build_modidx()
File "/usr/local/lib/python3.12/dist-packages/nbdev/doclinks.py", line 112, in _build_modidx
try: res['syms'].update(_get_modidx((dest.parent/file).resolve(), code_root, nbs_path=nbs_path))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/nbdev/doclinks.py", line 91, in _get_modidx
if isinstance(tree, _def_types): _stor(patch_name(tree))
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/dist-packages/nbdev/doclinks.py", line 51, in patch_name
elif nm=='patch_to': a = d.args[0]
~~~~~~^^^
IndexError: list index out of range
- Dominant language
- Jupyter Notebook
- Stars
- 5.3k
- Forks
- 514
- Avg merge
- 2d 30m
- Merged PRs (30d)
- 8
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from AnswerDotAI/nbdev
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
AnswerDotAI/nbdev#1587 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
AnswerDotAI/nbdev#1584 ·
-
Difficulty 3/5 1-2 days Newbie friendliness 35/100
AnswerDotAI/nbdev#1583 · 1 comment · 1 reaction ·
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 52/100
AnswerDotAI/nbdev#1581 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 45/100
AnswerDotAI/nbdev#1569 · 1 comment ·
All issues in AnswerDotAI/nbdev
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
use-agent-os/agent-os#3314 ·
-
documentation low-priority templates
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
jesseray718/openroot#87 ·
-
factory-active factory-automatic task-bug-reproduction-cannot-reproduce task-identify-harness-labels-done task-identify-issue-type-done
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
danielmiessler/LifeOS#2218 ·
-
in-progress proposal
Difficulty 1/5 Under an hour Newbie friendliness 88/100
uibcdf/molsyssuite#36 ·