Skip to content

Commit 2afc549

Browse files
authored
Support nesting of natlang containers (#71)
* Support nesting of natlang containers `list of (list of int)` and similar constructs should be parsable now. However, I think it will rarely be a good idea to nest these forms – falling back to Python' syntax actually seems more readable. * Add more parsing tests for (bad) doctypes
1 parent 1928d24 commit 2afc549

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

src/docstub/doctype.lark

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ natlang_literal: "{" literal_item ("," literal_item)* "}"
6565
// These forms allow nesting with other expressions. But it's discouraged to do
6666
// so extensively to maintain readability.
6767
natlang_container: qualname "of" qualname _PLURAL_S?
68-
| qualname "of" "(" union ")"
68+
| qualname "of" "(" type ")"
6969
| _natlang_tuple
7070
| _natlang_mapping
7171

@@ -83,7 +83,7 @@ _natlang_tuple: qualname "of" "(" type "," ELLIPSES ")"
8383

8484

8585
// Natural language container variant for mappings.
86-
_natlang_mapping: qualname "of" "{" type ":" (type | union) "}"
86+
_natlang_mapping: qualname "of" "{" type ":" type "}"
8787

8888

8989
// A natural language alternative to describe arrays with a dtype and shape.

tests/test_docstrings.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,48 @@ def test_unexpected_value(self):
3434

3535

3636
class Test_DoctypeTransformer:
37+
@pytest.mark.parametrize(
38+
"doctype",
39+
[
40+
"((float))",
41+
"(float,)",
42+
"(, )",
43+
"...",
44+
"(..., ...)",
45+
"{}",
46+
"{:}",
47+
"{a:}",
48+
"{:b}",
49+
"{'a',}",
50+
"a or (b or c)",
51+
",, optional",
52+
],
53+
)
54+
def test_edge_case_errors(self, doctype):
55+
transformer = DoctypeTransformer()
56+
with pytest.raises(lark.exceptions.UnexpectedInput):
57+
transformer.doctype_to_annotation(doctype)
58+
59+
@pytest.mark.parametrize("doctype", DoctypeTransformer.blacklisted_qualnames)
60+
def test_reserved_keywords(self, doctype):
61+
assert DoctypeTransformer.blacklisted_qualnames
62+
63+
transformer = DoctypeTransformer()
64+
with pytest.raises(lark.exceptions.VisitError):
65+
transformer.doctype_to_annotation(doctype)
66+
67+
@pytest.mark.parametrize(
68+
("doctype", "expected"),
69+
[
70+
("int or float", "int | float"),
71+
("int or float or str", "int | float | str"),
72+
],
73+
)
74+
def test_natlang_union(self, doctype, expected):
75+
transformer = DoctypeTransformer()
76+
annotation, _ = transformer.doctype_to_annotation(doctype)
77+
assert annotation.value == expected
78+
3779
@pytest.mark.parametrize(
3880
("doctype", "expected"),
3981
[
@@ -67,14 +109,19 @@ def test_subscription(self, doctype, expected):
67109
("list of int", "list[int]"),
68110
("list of int(s)", "list[int]"),
69111
("list of (int or float)", "list[int | float]"),
112+
("list of (list of int)", "list[list[int]]"),
70113
# Natural tuple variant
71114
("tuple of (float, int, str)", "tuple[float, int, str]"),
72115
("tuple of (float, ...)", "tuple[float, ...]"),
73116
# Natural dict variant
74117
("dict of {str: int}", "dict[str, int]"),
75118
("dict of {str: int | float}", "dict[str, int | float]"),
76119
("dict of {str: int or float}", "dict[str, int | float]"),
77-
("dict[list of str]", "dict[list[str]]"),
120+
# Nesting is possible but probably rarely a good idea
121+
("list of (list of int(s))", "list[list[int]]"),
122+
("tuple of (tuple of (float, ...), ...)", "tuple[tuple[float, ...], ...]"),
123+
("dict of {str: dict of {str: float}}", "dict[str, dict[str, float]]"),
124+
("dict of {str: list of (list of int(s))}", "dict[str, list[list[int]]]"),
78125
],
79126
)
80127
def test_natlang_container(self, doctype, expected):
@@ -86,7 +133,7 @@ def test_natlang_container(self, doctype, expected):
86133
"doctype",
87134
[
88135
"list of int (s)",
89-
"list of (float)",
136+
"list of ((float))",
90137
"list of (float,)",
91138
"list of (, )",
92139
"list of ...",

0 commit comments

Comments
 (0)