Skip to content

Commit

Permalink
Adjusted tests to the griffe library and updated snapshot tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Masara committed Apr 4, 2024
1 parent 1ae288e commit 386a9f9
Show file tree
Hide file tree
Showing 12 changed files with 750 additions and 153 deletions.
3 changes: 2 additions & 1 deletion src/safeds_stubgen/docstring_parsing/_docstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from safeds_stubgen.api_analyzer import AbstractType
from typing import Any

from safeds_stubgen.api_analyzer import AbstractType


@dataclass(frozen=True)
class ClassDocstring:
Expand Down
46 changes: 29 additions & 17 deletions src/safeds_stubgen/docstring_parsing/_docstring_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
from typing import TYPE_CHECKING, Literal

from griffe import load
from griffe.dataclasses import Docstring
from griffe.docstrings.dataclasses import DocstringAttribute, DocstringParameter
from griffe.docstrings.utils import parse_annotation
from griffe.enumerations import DocstringSectionKind, Parser
from griffe.expressions import Expr, ExprName, ExprSubscript, ExprTuple

# noinspection PyProtectedMember
import safeds_stubgen.api_analyzer._types as sds_types

from ._abstract_docstring_parser import AbstractDocstringParser
from ._docstring import (
AttributeDocstring,
Expand All @@ -21,7 +25,7 @@
if TYPE_CHECKING:
from pathlib import Path

from griffe.dataclasses import Docstring, Object
from griffe.dataclasses import Object
from mypy import nodes

from safeds_stubgen.api_analyzer import AbstractType
Expand Down Expand Up @@ -113,6 +117,9 @@ def get_parameter_documentation(
if not isinstance(last_parameter, DocstringParameter): # pragma: no cover
raise TypeError(f"Expected parameter docstring, got {type(last_parameter)}.")

if griffe_docstring is None:
griffe_docstring = Docstring("")

return ParameterDocstring(
type=self._griffe_annotation_to_api_type(last_parameter.annotation, griffe_docstring),
default_value=last_parameter.default or "",
Expand All @@ -131,9 +138,7 @@ def get_attribute_documentation(
griffe_docstring = self.__get_cached_docstring(parent_qname)
if griffe_docstring is None:
matching_attributes = []
elif self.parser == Parser.sphinx:
# ReST does not differentiate between parameterd and attributes
matching_attributes = self._get_matching_docstrings(griffe_docstring, attribute_name, "param")
griffe_docstring = Docstring("")
else:
matching_attributes = self._get_matching_docstrings(griffe_docstring, attribute_name, "attr")

Expand Down Expand Up @@ -203,10 +208,8 @@ def _get_matching_docstrings(
def _griffe_annotation_to_api_type(
self,
annotation: Expr | str | None,
docstring: Docstring
docstring: Docstring,
) -> AbstractType | None:
import safeds_stubgen.api_analyzer._types as sds_types

if annotation is None:
return None
elif isinstance(annotation, ExprName):
Expand All @@ -231,11 +234,17 @@ def _griffe_annotation_to_api_type(
elif isinstance(annotation, ExprSubscript):
slices = annotation.slice
if isinstance(slices, ExprTuple):
types = [
self._griffe_annotation_to_api_type(slice_, docstring) for slice_ in slices.elements
]
types = []
for slice_ in slices.elements:
new_type = self._griffe_annotation_to_api_type(slice_, docstring)
if new_type is None:
continue
types.append(new_type)
else:
types = [self._griffe_annotation_to_api_type(slices, docstring)]
types = []
type_ = self._griffe_annotation_to_api_type(slices, docstring)
if type_ is not None:
types.append(type_)

if annotation.canonical_path == "list":
return sds_types.ListType(types=types)
Expand All @@ -249,12 +258,13 @@ def _griffe_annotation_to_api_type(
elements = []
has_optional = False
for element in annotation.elements:
if element.canonical_path == "optional":
if not isinstance(element, str) and element.canonical_path == "optional":
has_optional = True
else:
elements.append(
self._griffe_annotation_to_api_type(element, docstring)
)
new_element = self._griffe_annotation_to_api_type(element, docstring)
if new_element is None:
continue
elements.append(new_element)
if len(elements) == 1:
if has_optional:
elements.append(sds_types.NamedType(name="None", qname="builtins.None"))
Expand Down Expand Up @@ -299,8 +309,10 @@ def _get_griffe_node(self, qname: str) -> Object | None:
elif part == "__init__" and griffe_node.is_class:
return None
else:
raise ValueError(f"Something went wrong while searching for the docstring for {qname}. Please make sure"
" that all directories with python files have an __init__.py file.")
raise ValueError(
f"Something went wrong while searching for the docstring for {qname}. Please make sure"
" that all directories with python files have an __init__.py file.",
)

return griffe_node

Expand Down
6 changes: 5 additions & 1 deletion tests/data/docstring_parser_package/googledoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ def __init__(self, p) -> None:
pass


def function_with_parameters(no_type_no_default, type_no_default, with_default, *args, **kwargs) -> None:
def function_with_parameters(no_type_no_default, optional_type, type_no_default, with_default, *args, **kwargs) -> None:
"""function_with_parameters.
Dolor sit amet.
Args:
no_type_no_default: no type and no default.
optional_type (int, optional): optional type.
type_no_default (int): type but no default.
with_default (int): foo. Defaults to 2.
*args (int): foo: *args
Expand All @@ -71,6 +72,7 @@ def function_with_attributes_and_parameters(q) -> None:
Args:
q (int): foo. Defaults to 2.
"""
p: int = 2


class ClassWithAttributes:
Expand All @@ -81,9 +83,11 @@ class ClassWithAttributes:
Attributes:
p (int): foo. Defaults to 1.
q (int): foo. Defaults to 1.
optional_unknown_default (int, optional): foo.
"""
p: int
q = 1
optional_unknown_default = None


def function_with_return_value_and_type() -> bool:
Expand Down
8 changes: 5 additions & 3 deletions tests/data/docstring_parser_package/numpydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
A module for testing the various docstring types.
"""
from typing import Any, Optional
from typing import Optional
from enum import Enum


Expand Down Expand Up @@ -45,9 +45,11 @@ class ClassWithParameters:
----------
p : int, default=1
foo
grouped_parameter_1, grouped_parameter_2 : int, default=4
foo: grouped_parameter_1 and grouped_parameter_2
"""

def __init__(self, p) -> None:
def __init__(self, p, grouped_parameter_1, grouped_parameter_2) -> None:
pass


Expand Down Expand Up @@ -160,7 +162,7 @@ class ClassWithAttributes:
grouped_attribute_1, grouped_attribute_2 : int, default=4
foo: grouped_attribute_1 and grouped_attribute_2
"""
no_type_no_default: Any
no_type_no_default = ""
type_no_default: int
optional_unknown_default: Optional[int]
with_default_syntax_1 = 1
Expand Down
82 changes: 79 additions & 3 deletions tests/data/docstring_parser_package/restdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def __init__(self, p) -> None:
pass


def function_with_parameters(no_type_no_default, type_no_default, with_default, *args, **kwargs) -> None:
def function_with_parameters(no_type_no_default, optional_unknown_default, type_no_default, with_default, *args, **kwargs) -> None:
"""
function_with_parameters.
Expand All @@ -57,6 +57,8 @@ def function_with_parameters(no_type_no_default, type_no_default, with_default,
:param no_type_no_default: no type and no default
:param type_no_default: type but no default
:type type_no_default: int
:param optional_unknown_default: optional type
:type optional_unknown_default: int, optional
:param with_default: foo that defaults to 2
:type with_default: int
:param *args: foo: *args
Expand Down Expand Up @@ -131,8 +133,6 @@ class EnumDocstring(Enum):

class ClassWithVariousParameterTypes:
"""
Parameters
----------
:param no_type:
:param optional_type:
:type optional_type: int, optional
Expand Down Expand Up @@ -180,3 +180,79 @@ def __init__(
tuple_type_1, tuple_type_2, tuple_type_3, tuple_type_4, tuple_type_5
) -> None:
pass


class ClassWithVariousAttributeTypes:
"""
:var has_default: Description...
:type has_default: int, defaults to 1.
:var optional_int:
:type optional_int: int, optional
:var no_type:
:ivar ivar_type:
:type ivar_type: int
:cvar cvar_type:
:type cvar_type: int
:var optional_type:
:type optional_type: int, optional
:var none_type:
:type none_type: None
:var int_type:
:type int_type: int
:var bool_type:
:type bool_type: bool
:var str_type:
:type str_type: str
:var float_type:
:type float_type: float
:var multiple_types:
:type multiple_types: int, bool
:var list_type_1:
:type list_type_1: list
:var list_type_2:
:type list_type_2: list[str]
:var list_type_3:
:type list_type_3: list[int, bool]
:var list_type_4:
:type list_type_4: list[list[int]]
:var set_type_1:
:type set_type_1: set
:var set_type_2:
:type set_type_2: set[str]
:var set_type_3:
:type set_type_3: set[int, bool]
:var set_type_4:
:type set_type_4: set[list[int]]
:var tuple_type_1:
:type tuple_type_1: tuple
:var tuple_type_2:
:type tuple_type_2: tuple[str]
:var tuple_type_3:
:type tuple_type_3: tuple[int, bool]
:var tuple_type_4:
:type tuple_type_4: tuple[list[int]]
"""
has_default = 1
optional_int = None
no_type = ""
ivar_type = ""
cvar_type = ""
optional_type = ""
none_type = ""
int_type = ""
bool_type = ""
str_type = ""
float_type = ""
multiple_types = ""
list_type_1 = ""
list_type_2 = ""
list_type_3 = ""
list_type_4 = ""
set_type_1 = ""
set_type_2 = ""
set_type_3 = ""
set_type_4 = ""
tuple_type_1 = ""
tuple_type_2 = ""
tuple_type_3 = ""
tuple_type_4 = ""
Original file line number Diff line number Diff line change
Expand Up @@ -1054,11 +1054,8 @@
list([
dict({
'docstring': dict({
'description': 'Attribute of the calculator. (ReST)',
'type': dict({
'name': 'str',
'qname': 'builtins.str',
}),
'description': '',
'type': None,
}),
'id': 'tests/data/various_modules_package/docstring_module/RestDocstringClass/attr_1',
'is_public': True,
Expand Down
Loading

0 comments on commit 386a9f9

Please sign in to comment.