Skip to content

Commit 46b8341

Browse files
committed
Add docstring handling to PythonParser and extend FunctionDefinition model
1 parent b7e4546 commit 46b8341

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

codetide/core/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class FunctionDefinition(BaseCodeElement):
100100
signature: Optional[FunctionSignature]=None
101101
modifiers: List[str] = Field(default_factory=list) # e.g., "async", "generator", etc.
102102
decorators: List[str] = Field(default_factory=list)
103+
docstring: Optional[str]=None
103104
references: List[CodeReference] = Field(default_factory=list)
104105

105106
class MethodDefinition(FunctionDefinition):

codetide/parsers/python_parser.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ def filepath(self, filepath: Union[str, Path]):
4040
filepath = Path(filepath)
4141
self._filepath = filepath
4242

43+
@staticmethod
44+
def is_docstring(content :str)->bool:
45+
if not content:
46+
return False
47+
48+
stripped = content.strip()
49+
if stripped.startswith('"""') and stripped.endswith('"""'):
50+
return True
51+
elif stripped.startswith("'''") and stripped.endswith("'''"):
52+
return True
53+
return False
54+
4355
@staticmethod
4456
def import_statement_template(importSatement :ImportStatement)->str:
4557
statement = f"import {importSatement.source or importSatement.name}"
@@ -312,19 +324,29 @@ def _process_decorated_definition(cls, node: Node, code: bytes, codeFile: CodeFi
312324
decorators.append(cls._get_content(code, child))
313325
elif child.type == "function_definition":
314326
cls._process_function_definition(child, code, codeFile, is_class_method=is_class_method, decorators=decorators, raw=raw)
327+
328+
@classmethod
329+
def _get_docstring_from_block(cls, node: Node, code: bytes)->Optional[str]:
330+
for child in node.children:
331+
if child.type == "expression_statement":
332+
candidate = cls._get_content(code, child, preserve_indentation=True)
333+
if cls.is_docstring(candidate):
334+
return candidate
335+
return None
336+
315337

316338
@classmethod
317339
def _process_function_definition(cls, node: Node, code: bytes, codeFile: CodeFileModel, is_class_method :bool=False, decorators :Optional[List[str]]=None, raw :Optional[str]=None):
318340
# print(node.type, cls._get_content(code, node))
319341
definition = None
342+
docstring = None
320343
signature = FunctionSignature()
321344
modifiers = []
322345

323346

324347
if decorators is None:
325348
decorators = []
326349

327-
### TODO add logic to extract modifiers i.e. async
328350
for child in node.children:
329351
if child.type == "identifier":
330352
definition = cls._get_content(code, child)
@@ -335,6 +357,8 @@ def _process_function_definition(cls, node: Node, code: bytes, codeFile: CodeFil
335357
signature.parameters = cls._process_parameters(child, code)
336358
elif child.type == "type":
337359
signature.return_type = cls._get_content(code, child)
360+
elif child.type == "block":
361+
docstring = cls._get_docstring_from_block(child, code)
338362

339363
if is_class_method:
340364
if raw is None:
@@ -345,6 +369,7 @@ def _process_function_definition(cls, node: Node, code: bytes, codeFile: CodeFil
345369
signature=signature,
346370
decorators=decorators,
347371
modifiers=modifiers,
372+
docstring=docstring,
348373
raw=raw
349374
)
350375
)
@@ -361,6 +386,7 @@ def _process_function_definition(cls, node: Node, code: bytes, codeFile: CodeFil
361386
signature=signature,
362387
decorators=decorators,
363388
modifiers=modifiers,
389+
docstring=docstring,
364390
raw=raw
365391
)
366392
)

0 commit comments

Comments
 (0)