Skip to content

Commit

Permalink
✨ feat: basic example parser
Browse files Browse the repository at this point in the history
  • Loading branch information
SigureMo committed Dec 31, 2023
1 parent 2324996 commit 3bb5fc1
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/dokyu/parser/docstring/args.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pyright: basic
# pyright: reportUndefinedVariable=false


from typing import Any

Expand Down
38 changes: 38 additions & 0 deletions src/dokyu/parser/docstring/examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# pyright: basic


from typing import Any

from parsita import Parser, ParserContext, lit, opt, reg, rep, success

from dokyu.parser.docstring.utils import double_indent, identifiers, indent
from dokyu.schema.docstring import Example


def to_example_code(example_code_lines: list[Any]) -> Parser[str, str]:
return success("\n".join(example_code_lines))


def to_examples(examples_raw: list[Any]) -> Parser[str, list[Example]]:
examples = []
for example_info in examples_raw:
lang_, label_, code = example_info
lang = lang_.strip()
label = label_.strip() if label_ else None
examples.append(Example(description=None, lang=lang, label=label, code=code))
return success(examples)


class ExamplesParser(ParserContext, whitespace=None):
next_line = lit("\n") & indent
blank_line = lit("\n")
examples_head = lit("Examples:")
example_code_block_head = indent >> reg(r".. code-block::\s*") >> identifiers << lit("\n")
# example_code_block_description = rep(double_indent >> reg(r".*") << lit("\n"))
example_code_block_label = opt(double_indent >> reg(r":name:\s*") >> reg(r".+") << lit("\n"))
example_code_block_body = (
rep((double_indent >> reg(r".+") << lit("\n")) | (lit("") << blank_line)) >= to_example_code
)
example_code_block = example_code_block_head & example_code_block_label << blank_line & example_code_block_body
examples_body = lit("\n") >> rep(example_code_block << rep(blank_line))
examples = examples_head >> examples_body >= to_examples
3 changes: 1 addition & 2 deletions src/dokyu/parser/docstring/returns.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# pyright: basic
# pyright: reportUndefinedVariable=false

from typing import Any

from parsita import Parser, ParserContext, lit, opt, reg, rep, success

from dokyu.parser.docstring.utils import double_indent, identifiers, indent, optional_whitespace
from dokyu.parser.docstring.utils import double_indent, indent, optional_whitespace
from dokyu.schema.docstring import Return


Expand Down
24 changes: 23 additions & 1 deletion src/dokyu/schema/docstring.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, Union

from pydantic import BaseModel

Expand All @@ -13,3 +13,25 @@ class Argument(BaseModel):
class Return(BaseModel):
type: Optional[str]
description: str


class Example(BaseModel):
lang: str
description: Optional[str]
label: Optional[str]
code: str


class Warning(BaseModel):
content: str


class Note(BaseModel):
content: str


class Docstring(BaseModel):
description: list[Union[str, Warning, Note]]
args: list[Argument]
returns: Optional[Return]
examples: list[Example]
45 changes: 45 additions & 0 deletions tests/test_parser/test_docstring/test_examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# pyright: basic

import pytest
from parsita import Success

from dokyu.parser.docstring.examples import ExamplesParser
from dokyu.schema.docstring import Example


@pytest.mark.parametrize(
("examples_string", "expected"),
[
(
"""\
Examples:
.. code-block:: python
>>> import paddle
>>> a = paddle.to_tensor(1)
>>> b = paddle.to_tensor(2)
>>> paddle.add(a, b)
Tensor(shape=[], dtype=int64, place=CPUPlace, stop_gradient=True)
""",
[
Example(
description=None,
lang="python",
label=None,
code="""\
>>> import paddle
>>> a = paddle.to_tensor(1)
>>> b = paddle.to_tensor(2)
>>> paddle.add(a, b)
Tensor(shape=[], dtype=int64, place=CPUPlace, stop_gradient=True)""",
)
],
),
],
)
def test_parse_returns(examples_string: str, expected: list[Example]):
res = ExamplesParser.examples.parse(examples_string)
assert isinstance(res, Success)
assert res.unwrap() == expected

0 comments on commit 3bb5fc1

Please sign in to comment.