Skip to content

Cannot parse code with "match / case" #79

@rabernat

Description

@rabernat

Thanks for maintaining this fantastic project! 🙏 We are using it to integrate our python API docs with a Docusaurus site.

Describe the bug
Python 3.10 introduced structural pattern matching with match / case syntax. I have found that mydoc markdown cannot parse code with this syntax. I am filing the bug report here rather than in pydoc-markdown because the stack trace indicates that the error comes from docspec_python

To Reproduce
Steps to reproduce the behavior:

Create the following python module

def function_with_match():
    """A function that can't be parsed with pydoc-markdown."""

    foo = "a"
    match foo:
        case "a":
            pass

Create a pydoc-markdown configuration to parse it. Mine looks like this

loaders:
  - type: python
    search_path: [../pydoc-markdown-bug]
processors:
  - type: filter
    skip_empty_modules: true
  - type: smart
  - type: crossref
renderer:
  type: docusaurus
  docs_base_path: docs
  relative_output_path: reference
  relative_sidebar_path: sidebar.json
  sidebar_top_level_label: 'Reference'

Then run pydoc-markdown. My stack trace looks like this

Traceback (most recent call last):
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/docspec_python/parser.py", line 88, in parse_to_ast
    return RefactoringTool([], options).refactor_string(code + '\n', filename)
  File "/Users/rabernat/mambaforge/lib/python3.10/lib2to3/refactor.py", line 364, in refactor_string
    self.log_error("Can't parse %s: %s: %s",
  File "/Users/rabernat/mambaforge/lib/python3.10/lib2to3/refactor.py", line 362, in refactor_string
    tree = self.driver.parse_string(data)
  File "/Users/rabernat/mambaforge/lib/python3.10/lib2to3/pgen2/driver.py", line 103, in parse_string
    return self.parse_tokens(tokens, debug)
  File "/Users/rabernat/mambaforge/lib/python3.10/lib2to3/pgen2/driver.py", line 71, in parse_tokens
    if p.addtoken(type, value, (prefix, start)):
  File "/Users/rabernat/mambaforge/lib/python3.10/lib2to3/pgen2/parse.py", line 162, in addtoken
    raise ParseError("bad input", type, value, context)
lib2to3.pgen2.parse.ParseError: bad input: type=1, value='foo', context=(' ', (5, 10))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/bin/pydoc-markdown", line 8, in <module>
    sys.exit(cli())
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/pydoc_markdown/main.py", line 344, in cli
    session.render(pydocmd)
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/pydoc_markdown/main.py", line 136, in render
    modules = config.load_modules()
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/pydoc_markdown/__init__.py", line 154, in load_modules
    modules.extend(loader.load())
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/docspec_python/__init__.py", line 87, in load_python_modules
    yield parse_python_module(filename, module_name=module_name, options=options, encoding=encoding)
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/docspec_python/__init__.py", line 128, in parse_python_module
    return parse_python_module(fpobj, fp, module_name, options, encoding)
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/docspec_python/__init__.py", line 132, in parse_python_module
    ast = parser.parse_to_ast(fp.read(), filename)
  File "/Users/rabernat/Library/Caches/pypoetry/virtualenvs/icechunk-client-6qaybCGJ-py3.10/lib/python3.10/site-packages/docspec_python/parser.py", line 90, in parse_to_ast
    raise ParseError(exc.msg, exc.type, exc.value, tuple(exc.context) + (filename,))
lib2to3.pgen2.parse.ParseError: bad input: type=1, value='foo', context=(' ', (5, 10), '/Users/rabernat/gh/earth-mover/pydoc-markdown-bug/match_bug.py')

Expected behavior
Given that docspec-python supports Python >=3.7, I would expect it to be able to parse all valid python 3.10 syntax.

Versions
pydoc-markdown, version 4.6.3
docspec-python, version 2.0.2

Metadata

Metadata

Assignees

Labels

type: bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions