rbtr-lang-python 2026.7.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rbtr_lang_python/__init__.py +1 -0
- rbtr_lang_python/plugin.py +120 -0
- rbtr_lang_python/py.typed +0 -0
- rbtr_lang_python/python.scm +59 -0
- rbtr_lang_python/tests/__init__.py +0 -0
- rbtr_lang_python/tests/__snapshots__/test_samples/test_edges_match_snapshot.json +3 -0
- rbtr_lang_python/tests/__snapshots__/test_samples/test_extraction_matches_snapshot.json +470 -0
- rbtr_lang_python/tests/cases_docstrings.py +174 -0
- rbtr_lang_python/tests/cases_extraction.py +572 -0
- rbtr_lang_python/tests/samples/python/config.py +3 -0
- rbtr_lang_python/tests/samples/python/python.py +84 -0
- rbtr_lang_python/tests/test_docstrings.py +54 -0
- rbtr_lang_python/tests/test_extraction.py +110 -0
- rbtr_lang_python/tests/test_samples.py +83 -0
- rbtr_lang_python-2026.7.0.dev0.dist-info/METADATA +8 -0
- rbtr_lang_python-2026.7.0.dev0.dist-info/RECORD +18 -0
- rbtr_lang_python-2026.7.0.dev0.dist-info/WHEEL +4 -0
- rbtr_lang_python-2026.7.0.dev0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""Python docstring-extraction test cases.
|
|
2
|
+
|
|
3
|
+
Each `@case` returns `(lang, source, symbol_name, snippet)` consumed by
|
|
4
|
+
`test_docstrings.py`; tags drive the documented/undocumented assertion.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pytest_cases import case
|
|
10
|
+
|
|
11
|
+
type DocstringCase = tuple[str, str, str, str]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@case(tags=["documented", "canonical", "interior_doc"])
|
|
15
|
+
def case_py_function_docstring() -> DocstringCase:
|
|
16
|
+
"""PEP 257 single-line function docstring."""
|
|
17
|
+
src = '''\
|
|
18
|
+
def greet(name):
|
|
19
|
+
"""Return a friendly greeting for *name*."""
|
|
20
|
+
return f"hi {name}"
|
|
21
|
+
'''
|
|
22
|
+
return "python", src, "greet", "Return a friendly greeting"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@case(tags=["documented", "canonical", "interior_doc"])
|
|
26
|
+
def case_py_class_docstring() -> DocstringCase:
|
|
27
|
+
"""Class-level docstring as first statement of the body."""
|
|
28
|
+
src = '''\
|
|
29
|
+
class Greeter:
|
|
30
|
+
"""Produce friendly greetings."""
|
|
31
|
+
|
|
32
|
+
def hi(self):
|
|
33
|
+
return "hi"
|
|
34
|
+
'''
|
|
35
|
+
return "python", src, "Greeter", "Produce friendly greetings"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@case(tags=["documented", "canonical", "interior_doc"])
|
|
39
|
+
def case_py_method_docstring() -> DocstringCase:
|
|
40
|
+
"""Method docstring inside a class."""
|
|
41
|
+
src = '''\
|
|
42
|
+
class Svc:
|
|
43
|
+
def run(self):
|
|
44
|
+
"""Execute the main loop."""
|
|
45
|
+
return 0
|
|
46
|
+
'''
|
|
47
|
+
return "python", src, "run", "Execute the main loop"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@case(tags=["documented", "canonical", "interior_doc"])
|
|
51
|
+
def case_py_multiline_docstring() -> DocstringCase:
|
|
52
|
+
"""Multi-line docstring with summary + body."""
|
|
53
|
+
src = '''\
|
|
54
|
+
def compute(x, y):
|
|
55
|
+
"""Add two numbers.
|
|
56
|
+
|
|
57
|
+
The summary is one line; the body elaborates. Both parts
|
|
58
|
+
must remain in chunk content.
|
|
59
|
+
"""
|
|
60
|
+
return x + y
|
|
61
|
+
'''
|
|
62
|
+
return "python", src, "compute", "The summary is one line"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@case(tags=["documented", "edge_case", "interior_doc"])
|
|
66
|
+
def case_py_raw_string_docstring() -> DocstringCase:
|
|
67
|
+
"""`r\"\"\"...\"\"\"` raw string is a valid docstring."""
|
|
68
|
+
src = '''\
|
|
69
|
+
def regex():
|
|
70
|
+
r"""Match DIGIT sequences."""
|
|
71
|
+
return 1
|
|
72
|
+
'''
|
|
73
|
+
return "python", src, "regex", "Match DIGIT sequences"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@case(tags=["documented", "edge_case", "interior_doc"])
|
|
77
|
+
def case_py_single_quoted_docstring() -> DocstringCase:
|
|
78
|
+
"""Single-quoted triple-string is equally valid."""
|
|
79
|
+
src = """\
|
|
80
|
+
def foo():
|
|
81
|
+
'''Single-quoted docstring content.'''
|
|
82
|
+
return 1
|
|
83
|
+
"""
|
|
84
|
+
return "python", src, "foo", "Single-quoted docstring content"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@case(tags=["documented", "edge_case", "interior_doc"])
|
|
88
|
+
def case_py_decorated_function_docstring() -> DocstringCase:
|
|
89
|
+
"""Decorators precede `def`; docstring is still interior."""
|
|
90
|
+
src = '''\
|
|
91
|
+
@cache
|
|
92
|
+
@wraps(other)
|
|
93
|
+
def memoized(x):
|
|
94
|
+
"""Memoise calls to *other*."""
|
|
95
|
+
return other(x)
|
|
96
|
+
'''
|
|
97
|
+
return "python", src, "memoized", "Memoise calls"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@case(tags=["documented", "unconventional", "interior_doc"])
|
|
101
|
+
def case_py_docstring_with_code_block() -> DocstringCase:
|
|
102
|
+
"""Docstring embedding example code - common in libraries."""
|
|
103
|
+
src = '''\
|
|
104
|
+
def parse(s):
|
|
105
|
+
"""Parse *s* into tokens.
|
|
106
|
+
|
|
107
|
+
Example::
|
|
108
|
+
|
|
109
|
+
>>> parse("1+2")
|
|
110
|
+
[1, "+", 2]
|
|
111
|
+
"""
|
|
112
|
+
return []
|
|
113
|
+
'''
|
|
114
|
+
return "python", src, "parse", ">>> parse"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@case(tags=["documented", "unconventional", "interior_doc"])
|
|
118
|
+
def case_py_class_and_method_both_documented() -> DocstringCase:
|
|
119
|
+
"""Method chunk carries its own docstring, not the class's."""
|
|
120
|
+
src = '''\
|
|
121
|
+
class Svc:
|
|
122
|
+
"""Service facade."""
|
|
123
|
+
|
|
124
|
+
def start(self):
|
|
125
|
+
"""Boot the service."""
|
|
126
|
+
return 1
|
|
127
|
+
'''
|
|
128
|
+
return "python", src, "start", "Boot the service"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@case(tags=["undocumented", "no_docs"])
|
|
132
|
+
def case_py_function_without_docstring() -> DocstringCase:
|
|
133
|
+
"""Plain function: chunk content has no triple-quoted prose.
|
|
134
|
+
|
|
135
|
+
The probe is a unique marker string that would only be
|
|
136
|
+
present if some other source polluted this chunk.
|
|
137
|
+
"""
|
|
138
|
+
src = """\
|
|
139
|
+
def add(a, b):
|
|
140
|
+
return a + b
|
|
141
|
+
"""
|
|
142
|
+
return "python", src, "add", "PHANTOM_DOC_TEXT_SHOULD_NEVER_APPEAR"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@case(tags=["undocumented", "no_docs"])
|
|
146
|
+
def case_py_class_without_docstring() -> DocstringCase:
|
|
147
|
+
"""Plain class with no documentation."""
|
|
148
|
+
src = """\
|
|
149
|
+
class Bare:
|
|
150
|
+
pass
|
|
151
|
+
"""
|
|
152
|
+
return "python", src, "Bare", "PHANTOM_DOC_TEXT_SHOULD_NEVER_APPEAR"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@case(tags=["undocumented", "invalid"])
|
|
156
|
+
def case_py_trailing_string_not_a_docstring() -> DocstringCase:
|
|
157
|
+
"""A triple-string placed *after* other statements is a
|
|
158
|
+
discarded expression, not a docstring. The text is in the
|
|
159
|
+
chunk content (it is part of the function body) but is not
|
|
160
|
+
treated as documentation.
|
|
161
|
+
|
|
162
|
+
We probe for presence of the marker using the
|
|
163
|
+
`test_no_phantom_documentation` logic inverted: the marker
|
|
164
|
+
*is* in the chunk, so probing for a different string that
|
|
165
|
+
would only appear if the extractor invented content gives
|
|
166
|
+
the right signal.
|
|
167
|
+
"""
|
|
168
|
+
src = '''\
|
|
169
|
+
def late():
|
|
170
|
+
x = 1
|
|
171
|
+
"""PSEUDO_DOC"""
|
|
172
|
+
return x
|
|
173
|
+
'''
|
|
174
|
+
return "python", src, "late", "PHANTOM_DOC_TEXT_SHOULD_NEVER_APPEAR"
|