Skip to content

Commit 2c695eb

Browse files
committed
Use numpydoc
1 parent aec86fe commit 2c695eb

File tree

1 file changed

+102
-2
lines changed

1 file changed

+102
-2
lines changed

singlestoredb/functions/ext/asgi.py

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,7 +1266,7 @@ def _locate_app_functions(self, cur: Any) -> Tuple[Set[str], Set[str]]:
12661266

12671267
def _extract_sample_usage(self, docstring: str) -> Optional[str]:
12681268
"""
1269-
Extract sample usage from docstring that starts with 'SAMPLE:'.
1269+
Extract sample usage from NumPy-style docstring Examples section or legacy SAMPLE: prefix.
12701270
12711271
Parameters
12721272
----------
@@ -1281,6 +1281,104 @@ def _extract_sample_usage(self, docstring: str) -> Optional[str]:
12811281
if not docstring:
12821282
return None
12831283

1284+
# Try to use numpydoc parser first
1285+
try:
1286+
import numpydoc.docscrape as nds
1287+
parsed = nds.FunctionDoc(None, doc=docstring)
1288+
1289+
# Extract Examples section
1290+
if hasattr(parsed, 'Examples') and parsed.Examples:
1291+
examples_lines = []
1292+
for example in parsed.Examples:
1293+
if hasattr(example, '__iter__') and not isinstance(example, str):
1294+
examples_lines.extend(str(line) for line in example)
1295+
else:
1296+
examples_lines.append(str(example))
1297+
1298+
if examples_lines:
1299+
return '\n'.join(examples_lines).strip()
1300+
except ImportError:
1301+
# numpydoc not available, fall back to manual parsing
1302+
pass
1303+
except Exception:
1304+
# If numpydoc parsing fails, fall back to manual parsing
1305+
pass
1306+
1307+
# Manual parsing for Examples section (NumPy-style)
1308+
examples_content = self._manual_parse_examples_section(docstring)
1309+
if examples_content:
1310+
return examples_content
1311+
1312+
# Fallback to legacy SAMPLE: prefix parsing
1313+
return self._legacy_sample_parsing(docstring)
1314+
1315+
def _manual_parse_examples_section(self, docstring: str) -> Optional[str]:
1316+
"""
1317+
Manually parse Examples section from NumPy-style docstring.
1318+
1319+
Parameters
1320+
----------
1321+
docstring : str
1322+
The function's docstring
1323+
1324+
Returns
1325+
-------
1326+
Optional[str]
1327+
The examples content if found, None otherwise
1328+
"""
1329+
lines = docstring.strip().split('\n')
1330+
examples_lines = []
1331+
in_examples_section = False
1332+
examples_started = False
1333+
1334+
for i, line in enumerate(lines):
1335+
stripped_line = line.strip()
1336+
1337+
# Look for Examples section header
1338+
if stripped_line.lower() == 'examples':
1339+
# Check if next line is underline (dashes)
1340+
if i + 1 < len(lines) and lines[i + 1].strip().startswith('-'):
1341+
in_examples_section = True
1342+
continue
1343+
elif in_examples_section:
1344+
# Check if we've hit another section (word followed by line of dashes)
1345+
if (stripped_line and
1346+
not stripped_line.startswith('-') and
1347+
i + 1 < len(lines) and
1348+
lines[i + 1].strip().startswith('-')):
1349+
break
1350+
1351+
# Skip the underline
1352+
if stripped_line.startswith('-') and not examples_started:
1353+
examples_started = True
1354+
continue
1355+
1356+
if examples_started:
1357+
# Collect all content in Examples section
1358+
examples_lines.append(line.rstrip())
1359+
1360+
if examples_lines:
1361+
# Remove trailing empty lines
1362+
while examples_lines and not examples_lines[-1].strip():
1363+
examples_lines.pop()
1364+
return '\n'.join(examples_lines) if examples_lines else None
1365+
1366+
return None
1367+
1368+
def _legacy_sample_parsing(self, docstring: str) -> Optional[str]:
1369+
"""
1370+
Legacy parsing for SAMPLE: prefix format.
1371+
1372+
Parameters
1373+
----------
1374+
docstring : str
1375+
The function's docstring
1376+
1377+
Returns
1378+
-------
1379+
Optional[str]
1380+
The sample usage string if found, None otherwise
1381+
"""
12841382
lines = docstring.strip().split('\n')
12851383
sample_lines = []
12861384
in_sample_block = False
@@ -1293,14 +1391,16 @@ def _extract_sample_usage(self, docstring: str) -> Optional[str]:
12931391
if stripped_line.startswith(prefix):
12941392
in_sample_block = True
12951393
# Extract the part after SAMPLE:
1296-
sample_content = stripped_line[len(prefix)].strip() # Remove 'SAMPLE:' prefix
1394+
sample_content = stripped_line[len(prefix):].strip() # Remove 'SAMPLE:' prefix
12971395
if sample_content:
12981396
sample_lines.append(sample_content)
12991397
elif in_sample_block:
13001398
# Continue collecting lines until we hit an empty line or end
13011399
if not stripped_line:
13021400
break
13031401
sample_lines.append(stripped_line)
1402+
1403+
return '\n'.join(sample_lines) if sample_lines else None
13041404

13051405
def _get_function_implementation(self, func: Callable[..., Any], func_name: str) -> Dict[str, Any]:
13061406
"""

0 commit comments

Comments
 (0)