Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 32 additions & 20 deletions strictdoc/backend/sdoc_source_code/reader_python.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# mypy: disable-error-code="no-redef,no-untyped-call,no-untyped-def,type-arg,var-annotated"
import sys
import traceback
from typing import List, Optional, Union
from typing import List, Optional, Sequence, Union

import tree_sitter_python
from tree_sitter import Language, Node, Parser
Expand Down Expand Up @@ -119,25 +119,9 @@ def read(self, input_buffer: bytes, file_path=None):

assert function_name is not None, "Function name"

parent_class_name: Optional[str] = None
if (function_parent_node := node_.parent) is not None and (
class_node_or_node := function_parent_node.parent
) is not None:
if (
class_node_or_node.type == "class_definition"
and len(class_node_or_node.children) > 1
):
second_node_or_none = class_node_or_node.children[1]
if (
second_node_or_none.type == "identifier"
and second_node_or_none.text is not None
):
parent_class_name = second_node_or_none.text.decode(
"utf8"
)

if parent_class_name is not None:
function_name = parent_class_name + "." + function_name
parent_names = self.get_node_ns(node_)
if parent_names:
function_name = f"{'.'.join(parent_names)}.{function_name}"

block_comment = None
if (
Expand Down Expand Up @@ -271,3 +255,31 @@ def read_from_file(self, file_path):
# TODO: when --debug is provided
# traceback.print_exc() # noqa: ERA001
sys.exit(1)

@staticmethod
def get_node_ns(node: Node) -> Sequence[str]:
"""Walk up the tree and find parent classes"""
parent_scopes = []
cursor: Optional[Node] = node
while cursor:
if (block_node := cursor.parent) is not None and (
class_node_or_node := block_node.parent
) is not None:
cursor = class_node_or_node
if (
class_node_or_node.type == "class_definition"
and len(class_node_or_node.children) > 1
):
second_node_or_none = class_node_or_node.children[1]
if (
second_node_or_none.type == "identifier"
and second_node_or_none.text is not None
):
parent_class_name = second_node_or_none.text.decode(
"utf8"
)
parent_scopes.append(parent_class_name)
else:
cursor = None
parent_scopes.reverse()
return parent_scopes
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
class Foo:
class Bar:
class Baz:
def hello_world(self):
print("hello world") # noqa: T201

def hello_world(self):
"""
@relation(REQ-1, scope=function)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ STATEMENT: Requirement Statement
RELATIONS:
- TYPE: File
VALUE: file.py
FUNCTION: Foo.hello_world
FUNCTION: Foo.Bar.Baz.hello_world
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ CHECK: Published: Hello world doc
RUN: %check_exists --file "%S/Output/html/_source_files/file.py.html"

RUN: %cat %S/Output/html/%THIS_TEST_FOLDER/input.html | filecheck %s --dump-input=fail --check-prefix CHECK-HTML
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-1#2#11">
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-1#6#11">
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-1#8#8">
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-1#2#11">
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-1#7#16">
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-1#11#16">
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-1#13#13">
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-1#7#16">
CHECK-HTML: <a{{.*}}href="../_source_files/file.py.html#REQ-2#4#5">

RUN: %cat %S/Output/html/_source_files/file.py.html | filecheck %s --dump-input=fail --check-prefix CHECK-SOURCE-FILE
CHECK-SOURCE-FILE: def</span> <span class="nf">hello_world</span>
CHECK-SOURCE-FILE: href="../_source_files/file.py.html#REQ-1#2#11"
CHECK-SOURCE-FILE: href="../_source_files/file.py.html#REQ-2#2#11"
CHECK-SOURCE-FILE: <div data-line=3 class="source__line-content">
CHECK-SOURCE-FILE: href="../_source_files/file.py.html#REQ-1#2#11"
CHECK-SOURCE-FILE: def</span> <span class="nf">hello_world</span>
CHECK-SOURCE-FILE: href="../_source_files/file.py.html#REQ-2#4#5"
CHECK-SOURCE-FILE: href="../_source_files/file.py.html#REQ-1#7#16"
CHECK-SOURCE-FILE: href="../_source_files/file.py.html#REQ-1#11#16"
CHECK-SOURCE-FILE: href="../_source_files/file.py.html#REQ-1#13#13"

RUN: %cat %S/Output/html/source_coverage.html | filecheck %s --dump-input=fail --check-prefix CHECK-SOURCE-COVERAGE
CHECK-SOURCE-COVERAGE: 71.4%
CHECK-SOURCE-COVERAGE: 63.2%
Loading