From bdb43bdd5e190251c85be67b74c38e8f57785c24 Mon Sep 17 00:00:00 2001 From: Arsam Islami Date: Fri, 22 Mar 2024 13:07:23 +0100 Subject: [PATCH] feat: Safe-DS stubs also contain docstring information. (#78) ### Summary of Changes Added docstring information support for all docstring types, excluding attribute information for Epydoc docstrings. The following is included: - [X] Module docstring - [X] Class parameter docstrings - [X] Class attribute docstrings - [x] docstrings for ```@property``` methods - [X] Function parameter docstrings - [X] Function result docstrings --------- Co-authored-by: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Co-authored-by: Lars Reimann --- .gitignore | 1 + .../stubs_generator/_generate_stubs.py | 134 +++++- tests/conftest.py | 4 +- tests/data/docstring_parser_package/epydoc.py | 61 ++- .../full_docstring.py | 15 +- .../docstring_parser_package/googledoc.py | 77 +++- .../data/docstring_parser_package/numpydoc.py | 111 ++++- .../docstring_parser_package/plaintext.py | 10 +- .../data/docstring_parser_package/restdoc.py | 64 ++- .../__snapshots__/test__get_api.ambr | 430 +++++++++--------- .../api_analyzer/test__get_api.py | 12 +- .../docstring_parsing/test_epydoc_parser.py | 2 +- .../test_get_full_docstring.py | 8 +- .../test_googledoc_parser.py | 12 +- .../docstring_parsing/test_numpydoc_parser.py | 20 +- .../test_plaintext_docstring_parser.py | 8 +- .../docstring_parsing/test_restdoc_parser.py | 8 +- ...test_stub_creation[another_module].sdsstub | 6 + ...st_stub_creation[docstring_module].sdsstub | 100 ++++ ...on.test_stub_creation[enum_module].sdsstub | 8 + ..._stub_creation[infer_types_module].sdsstub | 3 + ..._docstring_creation[epydoc-EPYDOC].sdsstub | 153 +++++++ ...creation[full_docstring-PLAINTEXT].sdsstub | 45 ++ ...cstring_creation[googledoc-GOOGLE].sdsstub | 164 +++++++ ...string_creation[numpydoc-NUMPYDOC].sdsstub | 233 ++++++++++ ...ring_creation[plaintext-PLAINTEXT].sdsstub | 38 ++ ...b_docstring_creation[restdoc-REST].sdsstub | 133 ++++++ .../stubs_generator/test_generate_stubs.py | 39 +- 28 files changed, 1576 insertions(+), 323 deletions(-) create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[epydoc-EPYDOC].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[full_docstring-PLAINTEXT].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[googledoc-GOOGLE].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[numpydoc-NUMPYDOC].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[plaintext-PLAINTEXT].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[restdoc-REST].sdsstub diff --git a/.gitignore b/.gitignore index 2f5b3ba8..19a9cc75 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ __pycache__/ # Python environment venv/ +.venv/ # Pytest outputs .mypy_cache/ diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index bacfae27..42bc478d 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -21,6 +21,8 @@ if TYPE_CHECKING: from collections.abc import Generator + from safeds_stubgen.docstring_parsing import AttributeDocstring, ClassDocstring, FunctionDocstring + class NamingConvention(IntEnum): PYTHON = 1 @@ -65,7 +67,11 @@ def _generate_stubs_data( # the file would look like this: "package path.to.myPackage\n" or this: # '@PythonModule("path.to.my_package")\npackage path.to.myPackage\n'. With the split we check if the module # has enough information, if not, we won't create it. - splitted_text = module_text.split("\n") + _module_text = module_text + if _module_text.startswith("/**"): + # Remove docstring + _module_text = "*/\n".join(_module_text.split("*/\n\n")[1:]) + splitted_text = _module_text.split("\n") if len(splitted_text) <= 2 or (len(splitted_text) == 3 and splitted_text[1].startswith("package ")): continue @@ -172,9 +178,9 @@ def __call__(self, module: Module) -> str: self._current_todo_msgs: set[str] = set() self.module = module self.class_generics: list = [] - return self._create_module_string(module) + return self._create_module_string() - def _create_module_string(self, module: Module) -> str: + def _create_module_string(self) -> str: # Create package info package_info = self._get_shortest_public_reexport() package_info_camel_case = _convert_name_to_convention(package_info, self.naming_convention) @@ -184,24 +190,29 @@ def _create_module_string(self, module: Module) -> str: module_name_info = f'@PythonModule("{package_info}")\n' module_header = f"{module_name_info}package {package_info_camel_case}\n" + # Create docstring + docstring = self._create_sds_docstring_description(self.module.docstring, "") + if docstring: + docstring += "\n" + # Create global functions and properties - for function in module.global_functions: + for function in self.module.global_functions: if function.is_public: module_text += f"\n{self._create_function_string(function, is_method=False)}\n" # Create classes, class attr. & class methods - for class_ in module.classes: + for class_ in self.module.classes: if class_.is_public and not class_.inherits_from_exception: module_text += f"\n{self._create_class_string(class_)}\n" # Create enums & enum instances - for enum in module.enums: + for enum in self.module.enums: module_text += f"\n{self._create_enum_string(enum)}\n" # Create imports - We have to create them last, since we have to check all used types in this module first module_header += self._create_imports_string() - return module_header + module_text + return docstring + module_header + module_text def _create_imports_string(self) -> str: if not self.module_imports: @@ -230,7 +241,6 @@ def _create_imports_string(self) -> str: def _create_class_string(self, class_: Class, class_indentation: str = "") -> str: inner_indentations = class_indentation + "\t" - class_text = "" # Constructor parameter if class_.is_abstract: @@ -324,7 +334,7 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st ) # Attributes - class_text += self._create_class_attribute_string(class_.attributes, inner_indentations) + class_text = self._create_class_attribute_string(class_.attributes, inner_indentations) # Inner classes for inner_class in class_.classes: @@ -336,14 +346,17 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st # Methods class_text += self._create_class_method_string(class_.methods, inner_indentations) - # If the does not have a body, we just return the signature line + # Docstring + docstring = self._create_sds_docstring(class_.docstring, "", node=class_) + + # If the does not have a body, we just return the docstring and signature line if not class_text: - return class_signature + return docstring + class_signature # Close class class_text += f"{class_indentation}}}" - return f"{class_signature} {{{class_text}" + return f"{docstring}{class_signature} {{{class_text}" def _create_class_method_string( self, @@ -409,10 +422,13 @@ def _create_class_attribute_string(self, attributes: list[Attribute], inner_inde if not type_string: self._current_todo_msgs.add("attr without type") + # Create docstring text + docstring = self._create_sds_docstring(attribute.docstring, inner_indentations) + # Create attribute string class_attributes.append( f"{self._create_todo_msg(inner_indentations)}" - f"{inner_indentations}{attr_name_annotation}" + f"{docstring}{inner_indentations}{attr_name_annotation}" f"{static_string}attr {attr_name_camel_case}" f"{type_string}", ) @@ -461,6 +477,9 @@ def _create_function_string(self, function: Function, indentations: str = "", is type_var_string = ", ".join(type_var_names) type_var_info = f"<{type_var_string}>" + # Docstring + docstring = self._create_sds_docstring(function.docstring, indentations, function) + # Convert function name to camelCase name = function.name camel_case_name = _convert_name_to_convention(name, self.naming_convention) @@ -476,6 +495,7 @@ def _create_function_string(self, function: Function, indentations: str = "", is # Create string and return return ( f"{self._create_todo_msg(indentations)}" + f"{docstring}" f"{indentations}@Pure\n" f"{function_name_annotation}" f"{indentations}{static}fun {camel_case_name}{type_var_info}" @@ -496,6 +516,9 @@ def _create_property_function_string(self, function: Function, indentations: str # Escape keywords camel_case_name = _replace_if_safeds_keyword(camel_case_name) + # Docstring + docstring = self._create_sds_docstring_description(function.docstring.description, indentations) + # Create type information result_types = [result.type for result in function.results if result.type is not None] result_union = UnionType(types=result_types) @@ -505,6 +528,7 @@ def _create_property_function_string(self, function: Function, indentations: str return ( f"{self._create_todo_msg(indentations)}" + f"{docstring}" f"{indentations}{function_name_annotation}" f"attr {camel_case_name}{type_string}" ) @@ -617,8 +641,11 @@ def _create_parameter_string( return "" def _create_enum_string(self, enum_data: Enum) -> str: + # Docstring + docstring = self._create_sds_docstring(enum_data.docstring, "") + # Signature - enum_signature = f"enum {enum_data.name}" + enum_signature = f"{docstring}enum {enum_data.name}" # Enum body enum_text = "" @@ -917,6 +944,85 @@ def _module_name_check(name: str, string: str) -> bool: return module_qname return ".".join(shortest_id) + @staticmethod + def _create_sds_docstring_description(description: str, indentations: str) -> str: + if not description: + return "" + + description = description.rstrip("\n") + description = description.lstrip("\n") + description = description.replace("\n", f"\n{indentations} * ") + return f"{indentations}/**\n{indentations} * {description}\n{indentations} */\n" + + def _create_sds_docstring( + self, + docstring: ClassDocstring | FunctionDocstring | AttributeDocstring, + indentations: str, + node: Class | Function | None = None, + ) -> str: + full_docstring = "" + + # Description + if docstring.description: + docstring_description = docstring.description.rstrip("\n") + docstring_description = docstring_description.lstrip("\n") + docstring_description = docstring_description.replace("\n", f"\n{indentations} * ") + full_docstring += f"{indentations} * {docstring_description}\n" + + # Parameters + full_parameter_docstring = "" + if node is not None: + parameters = [] + if isinstance(node, Class): + if node.constructor is not None: + parameters = node.constructor.parameters + else: + parameters = node.parameters + + if parameters: + parameter_docstrings = [] + for parameter in parameters: + param_desc = parameter.docstring.description + if not param_desc: + continue + + param_desc = f"\n{indentations} * ".join(param_desc.split("\n")) + + parameter_name = _convert_name_to_convention(parameter.name, self.naming_convention) + parameter_docstrings.append(f"{indentations} * @param {parameter_name} {param_desc}\n") + + full_parameter_docstring = "".join(parameter_docstrings) + + if full_parameter_docstring and full_docstring: + full_parameter_docstring = f"{indentations} *\n{full_parameter_docstring}" + full_docstring += full_parameter_docstring + + # Results + full_result_docstring = "" + if isinstance(node, Function): + result_docstrings = [] + for result in node.results: + result_desc = result.docstring.description + if not result_desc: + continue + + result_desc = f"\n{indentations} * ".join(result_desc.split("\n")) + + result_name = _convert_name_to_convention(result.name, self.naming_convention) + result_docstrings.append(f"{indentations} * @result {result_name} {result_desc}\n") + + full_result_docstring = "".join(result_docstrings) + + if full_result_docstring and full_docstring: + full_result_docstring = f"{indentations} *\n{full_result_docstring}" + full_docstring += full_result_docstring + + # Open and close the docstring + if full_docstring: + full_docstring = f"{indentations}/**\n{full_docstring}{indentations} */\n" + + return full_docstring + def _callable_type_name_generator() -> Generator: """Generate a name for callable type parameters starting from 'a' until 'zz'.""" diff --git a/tests/conftest.py b/tests/conftest.py index dd00dc7e..b890149e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,4 @@ +import re from typing import Any import pytest @@ -10,7 +11,8 @@ class SdsStubExtension(SingleFileSnapshotExtension): _file_extension = "sdsstub" def serialize(self, data: str, **_kwargs: Any) -> SerializedData: - return bytes(data, encoding="utf8") + normalized_data = re.sub(r"\r?\n", "\n", data) + return bytes(normalized_data, encoding="utf8") @pytest.fixture() diff --git a/tests/data/docstring_parser_package/epydoc.py b/tests/data/docstring_parser_package/epydoc.py index 1464c9ab..b1b834ed 100644 --- a/tests/data/docstring_parser_package/epydoc.py +++ b/tests/data/docstring_parser_package/epydoc.py @@ -1,3 +1,11 @@ +""" +Test module for docstring tests. + +A module for testing the various docstring types. +""" +from enum import Enum + + class ClassWithDocumentation: """ Lorem ipsum. Code:: @@ -36,7 +44,7 @@ class ClassWithParameters: @type p: int """ - def __init__(self) -> None: + def __init__(self, p) -> None: pass @@ -48,7 +56,11 @@ class ClassWithAttributes: @ivar p: foo defaults to 1 @type p: int + @ivar q: foo defaults to 1 + @type q: int """ + p: int + q = 1 def __init__(self) -> None: pass @@ -61,20 +73,21 @@ class ClassWithAttributesNoType: Dolor sit amet. @ivar p: foo defaults to 1 + @ivar q: foo defaults to 1 """ + p: int + q = 1 def __init__(self) -> None: pass -def function_with_parameters() -> None: +def function_with_parameters(no_type_no_default, type_no_default, with_default, *args, **kwargs) -> None: """ Lorem ipsum. Dolor sit amet. - Parameters - ---------- @param no_type_no_default: no type and no default @param type_no_default: type but no default @type type_no_default: int @@ -83,14 +96,14 @@ def function_with_parameters() -> None: """ -def function_with_result_value_and_type() -> None: +def function_with_result_value_and_type() -> bool: """ Lorem ipsum. Dolor sit amet. @return: return value - @rtype: float + @rtype: bool """ @@ -104,7 +117,41 @@ def function_with_result_value_no_type() -> None: """ -def function_without_result_value() -> None: +def function_without_result_value(): + """ + Lorem ipsum. + + Dolor sit amet. + """ + + +class ClassWithMethod: + def method_with_docstring(self, a) -> bool: + """ + Lorem ipsum. + + Dolor sit amet. + + @param a: type but no default + @type a: int + + @return: return value + @rtype: bool + """ + + @property + def property_method_with_docstring(self) -> bool: + """ + Lorem ipsum. + + Dolor sit amet. + + @return: return value + @rtype: bool + """ + + +class EnumDocstring(Enum): """ Lorem ipsum. diff --git a/tests/data/docstring_parser_package/full_docstring.py b/tests/data/docstring_parser_package/full_docstring.py index 1dc35230..b049d1c0 100644 --- a/tests/data/docstring_parser_package/full_docstring.py +++ b/tests/data/docstring_parser_package/full_docstring.py @@ -1,13 +1,20 @@ +""" +Test module for full docstring tests. + +A module for testing the various docstring types. +""" + + class ClassWithMultiLineDocumentation: """ - Lorem ipsum. + ClassWithMultiLineDocumentation. Dolor sit amet. """ class ClassWithSingleLineDocumentation: - """Lorem ipsum.""" + """ClassWithSingleLineDocumentation.""" class ClassWithoutDocumentation: @@ -16,14 +23,14 @@ class ClassWithoutDocumentation: def function_with_multi_line_documentation() -> None: """ - Lorem ipsum. + function_with_multi_line_documentation. Dolor sit amet. """ def function_with_single_line_documentation() -> None: - """Lorem ipsum.""" + """function_with_single_line_documentation.""" def function_without_documentation() -> None: diff --git a/tests/data/docstring_parser_package/googledoc.py b/tests/data/docstring_parser_package/googledoc.py index 5c4d822c..36703abf 100644 --- a/tests/data/docstring_parser_package/googledoc.py +++ b/tests/data/docstring_parser_package/googledoc.py @@ -1,6 +1,13 @@ +"""Test module for Google docstring tests. + +A module for testing the various docstring types. +""" +from enum import Enum + + class ClassWithDocumentation: """ - Lorem ipsum. Code:: + ClassWithDocumentation. Code:: pass @@ -14,7 +21,7 @@ class ClassWithoutDocumentation: def function_with_documentation() -> None: """ - Lorem ipsum. Code:: + function_with_documentation. Code:: pass @@ -27,7 +34,7 @@ def function_without_documentation() -> None: class ClassWithParameters: - """Lorem ipsum. + """ClassWithParameters. Dolor sit amet. @@ -35,12 +42,12 @@ class ClassWithParameters: p (int): foo. Defaults to 1. """ - def __init__(self) -> None: + def __init__(self, p) -> None: pass -def function_with_parameters() -> None: - """Lorem ipsum. +def function_with_parameters(no_type_no_default, type_no_default, with_default, *args, **kwargs) -> None: + """function_with_parameters. Dolor sit amet. @@ -53,8 +60,8 @@ def function_with_parameters() -> None: """ -def function_with_attributes_and_parameters() -> None: - """Lorem ipsum. +def function_with_attributes_and_parameters(q) -> None: + """function_with_attributes_and_parameters. Dolor sit amet. @@ -63,42 +70,78 @@ def function_with_attributes_and_parameters() -> None: Args: q (int): foo. Defaults to 2. - """ class ClassWithAttributes: - """Lorem ipsum. + """ClassWithAttributes. Dolor sit amet. Attributes: p (int): foo. Defaults to 1. + q (int): foo. Defaults to 1. """ + p: int + q = 1 -def function_with_return_value_and_type() -> None: - """Lorem ipsum. +def function_with_return_value_and_type() -> bool: + """function_with_return_value_and_type. Dolor sit amet. Returns: - int: this will be the return value. + bool: this will be the return value. """ def function_with_return_value_no_type() -> None: - """Lorem ipsum. + """function_with_return_value_no_type. Dolor sit amet. Returns: - int + None + """ + + +def function_without_return_value(): + """function_without_return_value. + + Dolor sit amet. """ -def function_without_return_value() -> None: - """Lorem ipsum. +class ClassWithMethod: + def method_with_docstring(self, a) -> bool: + """ + method_with_docstring. + + Dolor sit amet. + + Args: + a (int): foo + + Returns: + bool: this will be the return value. + """ + + @property + def property_method_with_docstring(self) -> bool: + """ + property_method_with_docstring. + + Dolor sit amet. + + Returns: + bool: this will be the return value. + """ + + +class EnumDocstring(Enum): + """ + EnumDocstring. Dolor sit amet. """ diff --git a/tests/data/docstring_parser_package/numpydoc.py b/tests/data/docstring_parser_package/numpydoc.py index 9204cfa6..3b577c84 100644 --- a/tests/data/docstring_parser_package/numpydoc.py +++ b/tests/data/docstring_parser_package/numpydoc.py @@ -1,6 +1,15 @@ +""" +Test module for Numpy docstring tests. + +A module for testing the various docstring types. +""" +from typing import Any, Optional +from enum import Enum + + class ClassWithDocumentation: """ - Lorem ipsum. Code:: + ClassWithDocumentation. Code:: pass @@ -14,7 +23,7 @@ class ClassWithoutDocumentation: def function_with_documentation() -> None: """ - Lorem ipsum. Code:: + function_with_documentation. Code:: pass @@ -28,7 +37,7 @@ def function_without_documentation() -> None: class ClassWithParameters: """ - Lorem ipsum. + ClassWithParameters. Dolor sit amet. @@ -38,13 +47,16 @@ class ClassWithParameters: foo """ - def __init__(self) -> None: + def __init__(self, p) -> None: pass -def function_with_parameters() -> None: +def function_with_parameters( + no_type_no_default, type_no_default, optional_unknown_default, with_default_syntax_1, with_default_syntax_2, + with_default_syntax_3, grouped_parameter_1, grouped_parameter_2, *args, **kwargs +) -> None: """ - Lorem ipsum. + function_with_parameters. Dolor sit amet. @@ -73,8 +85,12 @@ def function_with_parameters() -> None: """ -class ClassAndFunctionWithParameters: +class ClassAndConstructorWithParameters: """ + ClassAndConstructorWithParameters + + Dolor sit amet. + Parameters ---------- x: str @@ -96,28 +112,32 @@ def __init__(self, x, y, z) -> None: class ClassWithParametersAndAttributes: """ - Lorem ipsum. + ClassWithParametersAndAttributes. Dolor sit amet. Parameters ---------- - p : int, default=1 + x : int, default=1 foo Attributes ---------- + p : int, default=1 + foo q : int, default=1 foo """ + p: int + q = 1 - def __init__(self) -> None: + def __init__(self, x) -> None: pass class ClassWithAttributes: """ - Lorem ipsum. + ClassWithAttributes. Dolor sit amet. @@ -140,27 +160,86 @@ class ClassWithAttributes: grouped_attribute_1, grouped_attribute_2 : int, default=4 foo: grouped_attribute_1 and grouped_attribute_2 """ + no_type_no_default: Any + type_no_default: int + optional_unknown_default: Optional[int] + with_default_syntax_1 = 1 + with_default_syntax_2: int + with_default_syntax_3: int = 3 + grouped_attribute_1, grouped_attribute_2 = 4, 4 def __init__(self) -> None: pass -def function_with_result_value_and_type() -> None: +def function_with_result_value_and_type() -> bool: + """ + function_with_result_value_and_type. + + Dolor sit amet. + + Returns + ------- + bool + this will be the return value + """ + + +def function_with_named_result() -> bool: """ - Lorem ipsum. + function_with_named_result. Dolor sit amet. Returns ------- - int + named_result : bool this will be the return value """ -def function_without_result_value() -> None: +def function_without_result_value(): + """ + function_without_result_value. + + Dolor sit amet. + """ + + +class ClassWithMethod: + def method_with_docstring(self, a) -> bool: + """ + method_with_docstring. + + Dolor sit amet. + + Parameters + ---------- + a: str + + Returns + ------- + named_result : bool + this will be the return value + """ + + @property + def property_method_with_docstring(self) -> bool: + """ + property_method_with_docstring. + + Dolor sit amet. + + Returns + ------- + named_result : bool + this will be the return value + """ + + +class EnumDocstring(Enum): """ - Lorem ipsum. + EnumDocstring. Dolor sit amet. """ diff --git a/tests/data/docstring_parser_package/plaintext.py b/tests/data/docstring_parser_package/plaintext.py index d8387b2e..04c7580e 100644 --- a/tests/data/docstring_parser_package/plaintext.py +++ b/tests/data/docstring_parser_package/plaintext.py @@ -1,6 +1,12 @@ +"""Test module for plaintext docstring tests. + +A module for testing the various docstring types. +""" + + class ClassWithDocumentation: """ - Lorem ipsum. + ClassWithDocumentation. Dolor sit amet. """ @@ -15,7 +21,7 @@ class ClassWithoutDocumentation: def function_with_documentation(p: int) -> None: """ - Lorem ipsum. + function_with_documentation. Dolor sit amet. """ diff --git a/tests/data/docstring_parser_package/restdoc.py b/tests/data/docstring_parser_package/restdoc.py index c7bcc5ef..30c66762 100644 --- a/tests/data/docstring_parser_package/restdoc.py +++ b/tests/data/docstring_parser_package/restdoc.py @@ -1,6 +1,14 @@ +""" +Test module for ReST docstring tests. + +A module for testing the various docstring types. +""" +from enum import Enum + + class ClassWithDocumentation: """ - Lorem ipsum. Code:: + ClassWithDocumentation. Code:: pass @@ -14,7 +22,7 @@ class ClassWithoutDocumentation: def function_with_documentation() -> None: """ - Lorem ipsum. Code:: + function_with_documentation. Code:: pass @@ -28,7 +36,7 @@ def function_without_documentation() -> None: class ClassWithParameters: """ - Lorem ipsum. + ClassWithParameters. Dolor sit amet. @@ -36,13 +44,13 @@ class ClassWithParameters: :type p: int """ - def __init__(self) -> None: + def __init__(self, p) -> None: pass -def function_with_parameters() -> None: +def function_with_parameters(no_type_no_default, type_no_default, with_default, *args, **kwargs) -> None: """ - Lorem ipsum. + function_with_parameters. Dolor sit amet. @@ -58,9 +66,9 @@ def function_with_parameters() -> None: """ -def function_with_return_value_and_type() -> None: +def function_with_return_value_and_type() -> bool: """ - Lorem ipsum. + function_with_return_value_and_type. Dolor sit amet. @@ -71,7 +79,7 @@ def function_with_return_value_and_type() -> None: def function_with_return_value_no_type() -> None: """ - Lorem ipsum. + function_with_return_value_no_type. Dolor sit amet. @@ -79,9 +87,43 @@ def function_with_return_value_no_type() -> None: """ -def function_without_return_value() -> None: +def function_without_return_value(): + """ + function_without_return_value. + + Dolor sit amet. + """ + + +class ClassWithMethod: + def method_with_docstring(self, a) -> bool: + """ + method_with_docstring. + + Dolor sit amet. + + :param a: type but no default + :type a: int + + :return: return value + :rtype: bool + """ + + @property + def property_method_with_docstring(self) -> bool: + """ + property_method_with_docstring. + + Dolor sit amet. + + :return: return value + :rtype: bool + """ + + +class EnumDocstring(Enum): """ - Lorem ipsum. + EnumDocstring. Dolor sit amet. """ diff --git a/tests/safeds_stubgen/api_analyzer/__snapshots__/test__get_api.ambr b/tests/safeds_stubgen/api_analyzer/__snapshots__/test__get_api.ambr index b2256837..59b97ce0 100644 --- a/tests/safeds_stubgen/api_analyzer/__snapshots__/test__get_api.ambr +++ b/tests/safeds_stubgen/api_analyzer/__snapshots__/test__get_api.ambr @@ -6573,7 +6573,7 @@ list([ ]) # --- -# name: test_modules[__init__0] +# name: test_modules[__init__] dict({ 'classes': list([ ]), @@ -6633,122 +6633,6 @@ ]), }) # --- -# name: test_modules[__init__1] - dict({ - 'classes': list([ - ]), - 'docstring': '', - 'enums': list([ - ]), - 'functions': list([ - ]), - 'id': 'tests/data/various_modules_package/file_creation', - 'name': '__init__', - 'qualified_imports': list([ - dict({ - 'alias': None, - 'qualified_name': '_module_2._private_reexported', - }), - dict({ - 'alias': None, - 'qualified_name': '_module_3.Reexported', - }), - dict({ - 'alias': None, - 'qualified_name': '_module_6.public_reexported', - }), - dict({ - 'alias': None, - 'qualified_name': 'tests.data.various_modules_package.another_path._reexported_from_another_package_2.ReexportedInAnotherPackageClass2', - }), - dict({ - 'alias': None, - 'qualified_name': 'tests.data.various_modules_package.another_path._reexported_from_another_package_2.reexported_in_another_package_function2', - }), - dict({ - 'alias': 'reexported_from_another_package_3', - 'qualified_name': 'tests.data.various_modules_package.another_path._reexported_from_another_package_3', - }), - ]), - 'wildcard_imports': list([ - dict({ - 'module_name': 'tests.data.various_modules_package.another_path._reexported_from_another_package', - }), - ]), - }) -# --- -# name: test_modules[_module_2] - dict({ - 'classes': list([ - ]), - 'docstring': '', - 'enums': list([ - ]), - 'functions': list([ - 'tests/data/various_modules_package/file_creation/_module_2/_private_reexported', - ]), - 'id': 'tests/data/various_modules_package/file_creation/_module_2', - 'name': '_module_2', - 'qualified_imports': list([ - ]), - 'wildcard_imports': list([ - ]), - }) -# --- -# name: test_modules[_module_3] - dict({ - 'classes': list([ - 'tests/data/various_modules_package/file_creation/_module_3/Reexported', - ]), - 'docstring': '', - 'enums': list([ - ]), - 'functions': list([ - ]), - 'id': 'tests/data/various_modules_package/file_creation/_module_3', - 'name': '_module_3', - 'qualified_imports': list([ - ]), - 'wildcard_imports': list([ - ]), - }) -# --- -# name: test_modules[_module_4] - dict({ - 'classes': list([ - 'tests/data/various_modules_package/file_creation/_module_4/_Private', - ]), - 'docstring': '', - 'enums': list([ - ]), - 'functions': list([ - ]), - 'id': 'tests/data/various_modules_package/file_creation/_module_4', - 'name': '_module_4', - 'qualified_imports': list([ - ]), - 'wildcard_imports': list([ - ]), - }) -# --- -# name: test_modules[_module_6] - dict({ - 'classes': list([ - ]), - 'docstring': '', - 'enums': list([ - ]), - 'functions': list([ - 'tests/data/various_modules_package/file_creation/_module_6/public_reexported', - ]), - 'id': 'tests/data/various_modules_package/file_creation/_module_6', - 'name': '_module_6', - 'qualified_imports': list([ - ]), - 'wildcard_imports': list([ - ]), - }) -# --- # name: test_modules[_reexport_module_1] dict({ 'classes': list([ @@ -6846,168 +6730,168 @@ ]), }) # --- -# name: test_modules[_reexported_from_another_package] +# name: test_modules[abstract_module] dict({ 'classes': list([ - 'tests/data/various_modules_package/another_path/_reexported_from_another_package/ReexportedInAnotherPackageClass', + 'tests/data/various_modules_package/abstract_module/AbstractModuleClass', ]), 'docstring': '', 'enums': list([ ]), 'functions': list([ - 'tests/data/various_modules_package/another_path/_reexported_from_another_package/reexported_in_another_package_function', - 'tests/data/various_modules_package/another_path/_reexported_from_another_package/_still_internal_function', ]), - 'id': 'tests/data/various_modules_package/another_path/_reexported_from_another_package', - 'name': '_reexported_from_another_package', + 'id': 'tests/data/various_modules_package/abstract_module', + 'name': 'abstract_module', 'qualified_imports': list([ + dict({ + 'alias': None, + 'qualified_name': 'abc.ABC', + }), + dict({ + 'alias': None, + 'qualified_name': 'abc.abstractmethod', + }), ]), 'wildcard_imports': list([ ]), }) # --- -# name: test_modules[_reexported_from_another_package_2] +# name: test_modules[aliasing/aliasing_module_1] dict({ 'classes': list([ - 'tests/data/various_modules_package/another_path/_reexported_from_another_package_2/ReexportedInAnotherPackageClass2', + 'tests/data/various_modules_package/aliasing/aliasing_module_1/_AliasingModuleClassA', + 'tests/data/various_modules_package/aliasing/aliasing_module_1/AliasingModuleClassB', + 'tests/data/various_modules_package/aliasing/aliasing_module_1/AliasingModuleClassC', ]), 'docstring': '', 'enums': list([ ]), 'functions': list([ - 'tests/data/various_modules_package/another_path/_reexported_from_another_package_2/reexported_in_another_package_function2', - 'tests/data/various_modules_package/another_path/_reexported_from_another_package_2/_still_internal_function2', ]), - 'id': 'tests/data/various_modules_package/another_path/_reexported_from_another_package_2', - 'name': '_reexported_from_another_package_2', + 'id': 'tests/data/various_modules_package/aliasing/aliasing_module_1', + 'name': 'aliasing_module_1', 'qualified_imports': list([ + dict({ + 'alias': 'AliasModule2', + 'qualified_name': 'aliasing_module_2.AliasingModule2ClassA', + }), + dict({ + 'alias': 'ImportMeAlias', + 'qualified_name': 'aliasing_module_3.ImportMeAliasingModuleClass', + }), ]), 'wildcard_imports': list([ ]), }) # --- -# name: test_modules[_reexported_from_another_package_3] +# name: test_modules[aliasing/aliasing_module_2] dict({ 'classes': list([ - 'tests/data/various_modules_package/another_path/_reexported_from_another_package_3/ReexportedInAnotherPackageClass3', + 'tests/data/various_modules_package/aliasing/aliasing_module_2/AliasingModule2ClassA', + 'tests/data/various_modules_package/aliasing/aliasing_module_2/AliasingModuleClassB', + 'tests/data/various_modules_package/aliasing/aliasing_module_2/ImportMeAliasingModuleClass', + 'tests/data/various_modules_package/aliasing/aliasing_module_2/AliasingModuleClassC', ]), 'docstring': '', 'enums': list([ ]), 'functions': list([ - 'tests/data/various_modules_package/another_path/_reexported_from_another_package_3/reexported_in_another_package_function3', - 'tests/data/various_modules_package/another_path/_reexported_from_another_package_3/_still_internal_function3', ]), - 'id': 'tests/data/various_modules_package/another_path/_reexported_from_another_package_3', - 'name': '_reexported_from_another_package_3', + 'id': 'tests/data/various_modules_package/aliasing/aliasing_module_2', + 'name': 'aliasing_module_2', 'qualified_imports': list([ + dict({ + 'alias': None, + 'qualified_name': 'aliasing_module_1.AliasingModuleClassC', + }), ]), 'wildcard_imports': list([ ]), }) # --- -# name: test_modules[abstract_module] +# name: test_modules[aliasing/aliasing_module_3] dict({ 'classes': list([ - 'tests/data/various_modules_package/abstract_module/AbstractModuleClass', + 'tests/data/various_modules_package/aliasing/aliasing_module_3/ImportMeAliasingModuleClass', ]), 'docstring': '', 'enums': list([ ]), 'functions': list([ ]), - 'id': 'tests/data/various_modules_package/abstract_module', - 'name': 'abstract_module', + 'id': 'tests/data/various_modules_package/aliasing/aliasing_module_3', + 'name': 'aliasing_module_3', 'qualified_imports': list([ dict({ - 'alias': None, - 'qualified_name': 'abc.ABC', - }), - dict({ - 'alias': None, - 'qualified_name': 'abc.abstractmethod', + 'alias': 'ImportMeAlias', + 'qualified_name': 'aliasing_module_2.ImportMeAliasingModuleClass', }), ]), 'wildcard_imports': list([ ]), }) # --- -# name: test_modules[aliasing_module_1] +# name: test_modules[another_path/_reexported_from_another_package] dict({ 'classes': list([ - 'tests/data/various_modules_package/aliasing/aliasing_module_1/_AliasingModuleClassA', - 'tests/data/various_modules_package/aliasing/aliasing_module_1/AliasingModuleClassB', - 'tests/data/various_modules_package/aliasing/aliasing_module_1/AliasingModuleClassC', + 'tests/data/various_modules_package/another_path/_reexported_from_another_package/ReexportedInAnotherPackageClass', ]), 'docstring': '', 'enums': list([ ]), 'functions': list([ + 'tests/data/various_modules_package/another_path/_reexported_from_another_package/reexported_in_another_package_function', + 'tests/data/various_modules_package/another_path/_reexported_from_another_package/_still_internal_function', ]), - 'id': 'tests/data/various_modules_package/aliasing/aliasing_module_1', - 'name': 'aliasing_module_1', + 'id': 'tests/data/various_modules_package/another_path/_reexported_from_another_package', + 'name': '_reexported_from_another_package', 'qualified_imports': list([ - dict({ - 'alias': 'AliasModule2', - 'qualified_name': 'aliasing_module_2.AliasingModule2ClassA', - }), - dict({ - 'alias': 'ImportMeAlias', - 'qualified_name': 'aliasing_module_3.ImportMeAliasingModuleClass', - }), ]), 'wildcard_imports': list([ ]), }) # --- -# name: test_modules[aliasing_module_2] +# name: test_modules[another_path/_reexported_from_another_package_2] dict({ 'classes': list([ - 'tests/data/various_modules_package/aliasing/aliasing_module_2/AliasingModule2ClassA', - 'tests/data/various_modules_package/aliasing/aliasing_module_2/AliasingModuleClassB', - 'tests/data/various_modules_package/aliasing/aliasing_module_2/ImportMeAliasingModuleClass', - 'tests/data/various_modules_package/aliasing/aliasing_module_2/AliasingModuleClassC', + 'tests/data/various_modules_package/another_path/_reexported_from_another_package_2/ReexportedInAnotherPackageClass2', ]), 'docstring': '', 'enums': list([ ]), 'functions': list([ + 'tests/data/various_modules_package/another_path/_reexported_from_another_package_2/reexported_in_another_package_function2', + 'tests/data/various_modules_package/another_path/_reexported_from_another_package_2/_still_internal_function2', ]), - 'id': 'tests/data/various_modules_package/aliasing/aliasing_module_2', - 'name': 'aliasing_module_2', + 'id': 'tests/data/various_modules_package/another_path/_reexported_from_another_package_2', + 'name': '_reexported_from_another_package_2', 'qualified_imports': list([ - dict({ - 'alias': None, - 'qualified_name': 'aliasing_module_1.AliasingModuleClassC', - }), ]), 'wildcard_imports': list([ ]), }) # --- -# name: test_modules[aliasing_module_3] +# name: test_modules[another_path/_reexported_from_another_package_3] dict({ 'classes': list([ - 'tests/data/various_modules_package/aliasing/aliasing_module_3/ImportMeAliasingModuleClass', + 'tests/data/various_modules_package/another_path/_reexported_from_another_package_3/ReexportedInAnotherPackageClass3', ]), 'docstring': '', 'enums': list([ ]), 'functions': list([ + 'tests/data/various_modules_package/another_path/_reexported_from_another_package_3/reexported_in_another_package_function3', + 'tests/data/various_modules_package/another_path/_reexported_from_another_package_3/_still_internal_function3', ]), - 'id': 'tests/data/various_modules_package/aliasing/aliasing_module_3', - 'name': 'aliasing_module_3', + 'id': 'tests/data/various_modules_package/another_path/_reexported_from_another_package_3', + 'name': '_reexported_from_another_package_3', 'qualified_imports': list([ - dict({ - 'alias': 'ImportMeAlias', - 'qualified_name': 'aliasing_module_2.ImportMeAliasingModuleClass', - }), ]), 'wildcard_imports': list([ ]), }) # --- -# name: test_modules[another_module] +# name: test_modules[another_path/another_module] dict({ 'classes': list([ 'tests/data/various_modules_package/another_path/another_module/AnotherClass', @@ -7157,6 +7041,158 @@ ]), }) # --- +# name: test_modules[file_creation/__init__] + dict({ + 'classes': list([ + ]), + 'docstring': '', + 'enums': list([ + ]), + 'functions': list([ + ]), + 'id': 'tests/data/various_modules_package/file_creation', + 'name': '__init__', + 'qualified_imports': list([ + dict({ + 'alias': None, + 'qualified_name': '_module_2._private_reexported', + }), + dict({ + 'alias': None, + 'qualified_name': '_module_3.Reexported', + }), + dict({ + 'alias': None, + 'qualified_name': '_module_6.public_reexported', + }), + dict({ + 'alias': None, + 'qualified_name': 'tests.data.various_modules_package.another_path._reexported_from_another_package_2.ReexportedInAnotherPackageClass2', + }), + dict({ + 'alias': None, + 'qualified_name': 'tests.data.various_modules_package.another_path._reexported_from_another_package_2.reexported_in_another_package_function2', + }), + dict({ + 'alias': 'reexported_from_another_package_3', + 'qualified_name': 'tests.data.various_modules_package.another_path._reexported_from_another_package_3', + }), + ]), + 'wildcard_imports': list([ + dict({ + 'module_name': 'tests.data.various_modules_package.another_path._reexported_from_another_package', + }), + ]), + }) +# --- +# name: test_modules[file_creation/_module_2] + dict({ + 'classes': list([ + ]), + 'docstring': '', + 'enums': list([ + ]), + 'functions': list([ + 'tests/data/various_modules_package/file_creation/_module_2/_private_reexported', + ]), + 'id': 'tests/data/various_modules_package/file_creation/_module_2', + 'name': '_module_2', + 'qualified_imports': list([ + ]), + 'wildcard_imports': list([ + ]), + }) +# --- +# name: test_modules[file_creation/_module_3] + dict({ + 'classes': list([ + 'tests/data/various_modules_package/file_creation/_module_3/Reexported', + ]), + 'docstring': '', + 'enums': list([ + ]), + 'functions': list([ + ]), + 'id': 'tests/data/various_modules_package/file_creation/_module_3', + 'name': '_module_3', + 'qualified_imports': list([ + ]), + 'wildcard_imports': list([ + ]), + }) +# --- +# name: test_modules[file_creation/_module_4] + dict({ + 'classes': list([ + 'tests/data/various_modules_package/file_creation/_module_4/_Private', + ]), + 'docstring': '', + 'enums': list([ + ]), + 'functions': list([ + ]), + 'id': 'tests/data/various_modules_package/file_creation/_module_4', + 'name': '_module_4', + 'qualified_imports': list([ + ]), + 'wildcard_imports': list([ + ]), + }) +# --- +# name: test_modules[file_creation/_module_6] + dict({ + 'classes': list([ + ]), + 'docstring': '', + 'enums': list([ + ]), + 'functions': list([ + 'tests/data/various_modules_package/file_creation/_module_6/public_reexported', + ]), + 'id': 'tests/data/various_modules_package/file_creation/_module_6', + 'name': '_module_6', + 'qualified_imports': list([ + ]), + 'wildcard_imports': list([ + ]), + }) +# --- +# name: test_modules[file_creation/module_1] + dict({ + 'classes': list([ + 'tests/data/various_modules_package/file_creation/module_1/C', + ]), + 'docstring': '', + 'enums': list([ + ]), + 'functions': list([ + ]), + 'id': 'tests/data/various_modules_package/file_creation/module_1', + 'name': 'module_1', + 'qualified_imports': list([ + ]), + 'wildcard_imports': list([ + ]), + }) +# --- +# name: test_modules[file_creation/package_1/module_5] + dict({ + 'classes': list([ + 'tests/data/various_modules_package/file_creation/package_1/module_5/C', + ]), + 'docstring': '', + 'enums': list([ + ]), + 'functions': list([ + ]), + 'id': 'tests/data/various_modules_package/file_creation/package_1/module_5', + 'name': 'module_5', + 'qualified_imports': list([ + ]), + 'wildcard_imports': list([ + ]), + }) +# --- # name: test_modules[function_module] dict({ 'classes': list([ @@ -7317,42 +7353,6 @@ ]), }) # --- -# name: test_modules[module_1] - dict({ - 'classes': list([ - 'tests/data/various_modules_package/file_creation/module_1/C', - ]), - 'docstring': '', - 'enums': list([ - ]), - 'functions': list([ - ]), - 'id': 'tests/data/various_modules_package/file_creation/module_1', - 'name': 'module_1', - 'qualified_imports': list([ - ]), - 'wildcard_imports': list([ - ]), - }) -# --- -# name: test_modules[module_5] - dict({ - 'classes': list([ - 'tests/data/various_modules_package/file_creation/package_1/module_5/C', - ]), - 'docstring': '', - 'enums': list([ - ]), - 'functions': list([ - ]), - 'id': 'tests/data/various_modules_package/file_creation/package_1/module_5', - 'name': 'module_5', - 'qualified_imports': list([ - ]), - 'wildcard_imports': list([ - ]), - }) -# --- # name: test_modules[type_var_module] dict({ 'classes': list([ diff --git a/tests/safeds_stubgen/api_analyzer/test__get_api.py b/tests/safeds_stubgen/api_analyzer/test__get_api.py index 20c0bb83..e98c9605 100644 --- a/tests/safeds_stubgen/api_analyzer/test__get_api.py +++ b/tests/safeds_stubgen/api_analyzer/test__get_api.py @@ -59,7 +59,7 @@ def _get_specific_module_data(module_name: str, docstring_style: str = "plaintex for module in api_data["modules"]: if module["name"] == module_name: return module - raise AssertionError + raise pytest.fail(f"Could not find module data for '{module_name}'.") def _get_specific_class_data( @@ -73,7 +73,7 @@ def _get_specific_class_data( for class_ in api_data[data_type]: if module_name in class_["id"] and class_["id"].endswith(f"/{class_name}"): return class_ - raise AssertionError + raise pytest.fail(f"Could not find class data for '{class_name}' in module '{module_name}'.") def get_api_data(docstring_style: str) -> dict: @@ -100,7 +100,7 @@ def _get_specific_function_data( for function in api_data["functions"]: if function["id"].endswith(f"{parent_class_name}/{function_name}"): return function - raise AssertionError + raise pytest.fail(f"Could not find function data for '{function_name}' in module '{module_name}'.") _function_module_name = "function_module" @@ -121,7 +121,7 @@ def _python_files() -> Generator: def _python_file_ids() -> Generator: files = package_root.rglob(pattern="*.py") for file in files: - yield file.parts[-1].split(".py")[0] + yield str(file.relative_to(package_root).as_posix()).removesuffix(".py") @pytest.mark.parametrize("python_file", _python_files(), ids=_python_file_ids()) @@ -140,11 +140,11 @@ def test_modules(python_file: Path, snapshot: SnapshotAssertion) -> None: for module in api_data["modules"]: is_init_file = is_package and module_id.endswith(module["id"]) - is_module_file = str(python_file).replace("\\", "/").endswith(f"{module['id']}.py") + is_module_file = "/".join(python_file.parts).endswith(f"{module['id']}.py") if is_init_file or is_module_file: assert module == snapshot return - raise AssertionError + raise pytest.fail(f"Could not find module data for '{file_name}'.") # Todo new tests after issue #38 diff --git a/tests/safeds_stubgen/docstring_parsing/test_epydoc_parser.py b/tests/safeds_stubgen/docstring_parsing/test_epydoc_parser.py index e816617f..271a98c3 100644 --- a/tests/safeds_stubgen/docstring_parsing/test_epydoc_parser.py +++ b/tests/safeds_stubgen/docstring_parsing/test_epydoc_parser.py @@ -270,7 +270,7 @@ def xtest_get_attribute_documentation( [ ( "function_with_result_value_and_type", - ResultDocstring(type="float", description="return value"), + ResultDocstring(type="bool", description="return value"), ), ( "function_with_result_value_no_type", diff --git a/tests/safeds_stubgen/docstring_parsing/test_get_full_docstring.py b/tests/safeds_stubgen/docstring_parsing/test_get_full_docstring.py index ce14f131..42d7b67f 100644 --- a/tests/safeds_stubgen/docstring_parsing/test_get_full_docstring.py +++ b/tests/safeds_stubgen/docstring_parsing/test_get_full_docstring.py @@ -29,11 +29,11 @@ [ ( "ClassWithMultiLineDocumentation", - "Lorem ipsum.\n\nDolor sit amet.", + "ClassWithMultiLineDocumentation.\n\nDolor sit amet.", ), ( "ClassWithSingleLineDocumentation", - "Lorem ipsum.", + "ClassWithSingleLineDocumentation.", ), ( "ClassWithoutDocumentation", @@ -41,11 +41,11 @@ ), ( "function_with_multi_line_documentation", - "Lorem ipsum.\n\nDolor sit amet.", + "function_with_multi_line_documentation.\n\nDolor sit amet.", ), ( "function_with_single_line_documentation", - "Lorem ipsum.", + "function_with_single_line_documentation.", ), ( "function_without_documentation", diff --git a/tests/safeds_stubgen/docstring_parsing/test_googledoc_parser.py b/tests/safeds_stubgen/docstring_parsing/test_googledoc_parser.py index d370d501..23da965a 100644 --- a/tests/safeds_stubgen/docstring_parsing/test_googledoc_parser.py +++ b/tests/safeds_stubgen/docstring_parsing/test_googledoc_parser.py @@ -44,8 +44,8 @@ def googlestyledoc_parser() -> GoogleDocParser: ( "ClassWithDocumentation", ClassDocstring( - description="Lorem ipsum. Code::\n\npass\n\nDolor sit amet.", - full_docstring="Lorem ipsum. Code::\n\n pass\n\nDolor sit amet.", + description="ClassWithDocumentation. Code::\n\npass\n\nDolor sit amet.", + full_docstring="ClassWithDocumentation. Code::\n\n pass\n\nDolor sit amet.", ), ), ( @@ -79,8 +79,8 @@ def test_get_class_documentation( ( "function_with_documentation", FunctionDocstring( - description="Lorem ipsum. Code::\n\npass\n\nDolor sit amet.", - full_docstring="Lorem ipsum. Code::\n\n pass\n\nDolor sit amet.", + description="function_with_documentation. Code::\n\npass\n\nDolor sit amet.", + full_docstring="function_with_documentation. Code::\n\n pass\n\nDolor sit amet.", ), ), ( @@ -319,11 +319,11 @@ def test_get_attribute_documentation( [ ( "function_with_return_value_and_type", - ResultDocstring(type="int", description="this will be the return value."), + ResultDocstring(type="bool", description="this will be the return value."), ), ( "function_with_return_value_no_type", - ResultDocstring(type="", description="int"), + ResultDocstring(type="", description="None"), ), ("function_without_return_value", ResultDocstring(type="", description="")), ], diff --git a/tests/safeds_stubgen/docstring_parsing/test_numpydoc_parser.py b/tests/safeds_stubgen/docstring_parsing/test_numpydoc_parser.py index 156513e4..49a25a2d 100644 --- a/tests/safeds_stubgen/docstring_parsing/test_numpydoc_parser.py +++ b/tests/safeds_stubgen/docstring_parsing/test_numpydoc_parser.py @@ -45,8 +45,8 @@ def numpydoc_parser() -> NumpyDocParser: ( "ClassWithDocumentation", ClassDocstring( - description="Lorem ipsum. Code::\n\npass\n\nDolor sit amet.", - full_docstring="Lorem ipsum. Code::\n\n pass\n\nDolor sit amet.", + description="ClassWithDocumentation. Code::\n\npass\n\nDolor sit amet.", + full_docstring="ClassWithDocumentation. Code::\n\n pass\n\nDolor sit amet.", ), ), ( @@ -80,8 +80,8 @@ def test_get_class_documentation( ( "function_with_documentation", FunctionDocstring( - description="Lorem ipsum. Code::\n\npass\n\nDolor sit amet.", - full_docstring="Lorem ipsum. Code::\n\n pass\n\nDolor sit amet.", + description="function_with_documentation. Code::\n\npass\n\nDolor sit amet.", + full_docstring="function_with_documentation. Code::\n\n pass\n\nDolor sit amet.", ), ), ( @@ -244,7 +244,7 @@ def test_get_function_documentation( ParameterDocstring(type="", default_value="", description=""), ), ( - "ClassAndFunctionWithParameters", + "ClassAndConstructorWithParameters", True, "x", ParameterAssignment.POSITION_OR_NAME, @@ -255,7 +255,7 @@ def test_get_function_documentation( ), ), ( - "ClassAndFunctionWithParameters", + "ClassAndConstructorWithParameters", True, "y", ParameterAssignment.POSITION_OR_NAME, @@ -266,7 +266,7 @@ def test_get_function_documentation( ), ), ( - "ClassAndFunctionWithParameters", + "ClassAndConstructorWithParameters", True, "z", ParameterAssignment.POSITION_OR_NAME, @@ -279,7 +279,7 @@ def test_get_function_documentation( ( "ClassWithParametersAndAttributes", True, - "p", + "x", ParameterAssignment.POSITION_OR_NAME, ParameterDocstring( type="int", @@ -430,7 +430,7 @@ def test_get_parameter_documentation( ), ( "ClassWithParametersAndAttributes", - "p", + "r", AttributeDocstring( type="", default_value="", @@ -486,7 +486,7 @@ def test_get_attribute_documentation( [ ( "function_with_result_value_and_type", - ResultDocstring(type="int", description="this will be the return value"), + ResultDocstring(type="bool", description="this will be the return value"), ), ("function_without_result_value", ResultDocstring(type="", description="")), ], diff --git a/tests/safeds_stubgen/docstring_parsing/test_plaintext_docstring_parser.py b/tests/safeds_stubgen/docstring_parsing/test_plaintext_docstring_parser.py index 4b762264..67fb52b2 100644 --- a/tests/safeds_stubgen/docstring_parsing/test_plaintext_docstring_parser.py +++ b/tests/safeds_stubgen/docstring_parsing/test_plaintext_docstring_parser.py @@ -43,8 +43,8 @@ def plaintext_docstring_parser() -> PlaintextDocstringParser: ( "ClassWithDocumentation", ClassDocstring( - description="Lorem ipsum.\n\nDolor sit amet.", - full_docstring="Lorem ipsum.\n\nDolor sit amet.", + description="ClassWithDocumentation.\n\nDolor sit amet.", + full_docstring="ClassWithDocumentation.\n\nDolor sit amet.", ), ), ( @@ -78,8 +78,8 @@ def test_get_class_documentation( ( "function_with_documentation", FunctionDocstring( - description="Lorem ipsum.\n\nDolor sit amet.", - full_docstring="Lorem ipsum.\n\nDolor sit amet.", + description="function_with_documentation.\n\nDolor sit amet.", + full_docstring="function_with_documentation.\n\nDolor sit amet.", ), ), ( diff --git a/tests/safeds_stubgen/docstring_parsing/test_restdoc_parser.py b/tests/safeds_stubgen/docstring_parsing/test_restdoc_parser.py index 61f5019a..4f6ed851 100644 --- a/tests/safeds_stubgen/docstring_parsing/test_restdoc_parser.py +++ b/tests/safeds_stubgen/docstring_parsing/test_restdoc_parser.py @@ -41,8 +41,8 @@ def restdoc_parser() -> RestDocParser: ( "ClassWithDocumentation", ClassDocstring( - description="Lorem ipsum. Code::\n\npass\n\nDolor sit amet.", - full_docstring="Lorem ipsum. Code::\n\n pass\n\nDolor sit amet.", + description="ClassWithDocumentation. Code::\n\npass\n\nDolor sit amet.", + full_docstring="ClassWithDocumentation. Code::\n\n pass\n\nDolor sit amet.", ), ), ( @@ -76,8 +76,8 @@ def test_get_class_documentation( ( "function_with_documentation", FunctionDocstring( - description="Lorem ipsum. Code::\n\npass\n\nDolor sit amet.", - full_docstring="Lorem ipsum. Code::\n\n pass\n\nDolor sit amet.", + description="function_with_documentation. Code::\n\npass\n\nDolor sit amet.", + full_docstring="function_with_documentation. Code::\n\n pass\n\nDolor sit amet.", ), ), ( diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[another_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[another_module].sdsstub index 7b9bf87b..14fd56bf 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[another_module].sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[another_module].sdsstub @@ -1,3 +1,9 @@ +/** + * Another Module Docstring. + * + * Full Docstring Description + */ + @PythonModule("tests.data.various_modules_package.another_path.another_module") package tests.data.variousModulesPackage.anotherPath.anotherModule diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[docstring_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[docstring_module].sdsstub index d11a07b0..6abcb3db 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[docstring_module].sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[docstring_module].sdsstub @@ -1,12 +1,36 @@ +/** + * Test module for docstring tests. + * + * A module for testing the various docstring types. + */ + @PythonModule("tests.data.various_modules_package.docstring_module") package tests.data.variousModulesPackage.docstringModule +/** + * A class with a variety of different methods for calculations. (Epydoc). + * + * @ivar attr_1: Attribute of the calculator. (Epydoc) + * @type attr_1: str + * @param param_1: Parameter of the calculator. (Epydoc) + * @type param_1: str + */ class EpydocDocstringClass( @PythonName("param_1") param1: String ) { @PythonName("attr_1") static attr attr1: String + /** + * This function checks if the sum of x and y is less than the value 10 and returns True if it is. (Epydoc). + * + * @param x: First integer value for the calculation. (Epydoc) + * @type x: int + * @param y: Second integer value for the calculation. (Epydoc) + * @type y: int + * @return: Checks if the sum of x and y is greater than 10. (Epydoc) + * @rtype: bool + */ @Pure @PythonName("epydoc_docstring_func") fun epydocDocstringFunc( @@ -15,12 +39,31 @@ class EpydocDocstringClass( ) -> result1: Boolean } +/** + * A class with a variety of different methods for calculations. (ReST). + * + * :param attr_1: Attribute of the calculator. (ReST) + * :type attr_1: str + * :param param_1: Parameter of the calculator. (ReST) + * :type param_1: str + */ class RestDocstringClass( @PythonName("param_1") param1: String ) { @PythonName("attr_1") static attr attr1: String + /** + * This function checks if the sum of x and y is less than the value 10 + * and returns True if it is. (ReST). + * + * :param x: First integer value for the calculation. (ReST) + * :type x: int + * :param y: Second integer value for the calculation. (ReST) + * :type y: int + * :returns: Checks if the sum of x and y is greater than 10. (ReST) + * :rtype: bool + */ @Pure @PythonName("rest_docstring_func") fun restDocstringFunc( @@ -29,12 +72,44 @@ class RestDocstringClass( ) -> result1: Boolean } +/** + * A class that calculates stuff. (Numpy). + * + * A class with a variety of different methods for calculations. (Numpy) + * + * Attributes + * ---------- + * attr_1 : str + * Attribute of the calculator. (Numpy) + * + * Parameters + * ---------- + * param_1 : str + * Parameter of the calculator. (Numpy) + */ class NumpyDocstringClass( @PythonName("param_1") param1: String ) { @PythonName("attr_1") static attr attr1: String + /** + * Checks if the sum of two variables is over the value of 10. (Numpy). + * + * This function checks if the sum of `x` and `y` is less than the value 10 and returns True if it is. (Numpy) + * + * Parameters + * ---------- + * x : int + * First integer value for the calculation. (Numpy) + * y : int + * Second integer value for the calculation. (Numpy) + * + * Returns + * ------- + * bool + * Checks if the sum of `x` and `y` is greater than 10. (Numpy) + */ @Pure @PythonName("numpy_docstring_func") fun numpyDocstringFunc( @@ -43,12 +118,37 @@ class NumpyDocstringClass( ) -> result1: Boolean } +/** + * A class that calculates stuff. (Google Style). + * + * A class with a variety of different methods for calculations. (Google Style) + * + * Attributes: + * attr_1 (str): Attribute of the calculator. (Google Style) + * + * Args: + * param_1 (str): Parameter of the calculator. (Google Style) + */ class GoogleDocstringClass( @PythonName("param_1") param1: String ) { @PythonName("attr_1") static attr attr1: String + /** + * Checks if the sum of two variables is over the value of 10. (Google Style). + * + * This function checks if the sum of x and y is less than the value 10 + * and returns True if it is. (Google Style) + * + * Args: + * x (int): First integer value for the calculation. (Google Style) + * y (int): Second integer value for the calculation. (Google Style) + * + * Returns: + * bool: Checks if the sum of x and y is greater than 10 and returns + * a boolean value. (Google Style) + */ @Pure @PythonName("google_docstring_func") fun googleDocstringFunc( diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[enum_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[enum_module].sdsstub index 4a4d75c1..54fe8e8f 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[enum_module].sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[enum_module].sdsstub @@ -1,8 +1,16 @@ @PythonModule("tests.data.various_modules_package") package tests.data.variousModulesPackage +/** + * Nothing's here. + */ enum _ReexportedEmptyEnum +/** + * Enum Docstring. + * + * Full Docstring Description + */ enum EnumTest { ONE TWO diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[infer_types_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[infer_types_module].sdsstub index 57ac673c..7d89d8fa 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[infer_types_module].sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[infer_types_module].sdsstub @@ -53,6 +53,9 @@ class InferMyTypes( @PythonName("infer_param_2") inferParam2: Int = "Something" ) -> (result1: union, result2: union, result3: Float) + /** + * Test for inferring results with just one possible result, and not a tuple of results. + */ @Pure @PythonName("infer_function_2") static fun inferFunction2( diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[epydoc-EPYDOC].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[epydoc-EPYDOC].sdsstub new file mode 100644 index 00000000..336a88ca --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[epydoc-EPYDOC].sdsstub @@ -0,0 +1,153 @@ +/** + * Test module for docstring tests. + * + * A module for testing the various docstring types. + */ + +@PythonModule("tests.data.docstring_parser_package.epydoc") +package tests.data.docstringParserPackage.epydoc + +// TODO Result type information missing. +/** + * Lorem ipsum. Code:: + * + * pass + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_documentation") +fun functionWithDocumentation() + +// TODO Result type information missing. +@Pure +@PythonName("function_without_documentation") +fun functionWithoutDocumentation() + +// TODO Result type information missing. +// TODO Safe-DS does not support variadic parameters. +// TODO Some parameter have no type information. +/** + * Lorem ipsum. + * + * Dolor sit amet. + * + * @param noTypeNoDefault no type and no default + * @param typeNoDefault type but no default + * @param withDefault foo that defaults to 2 + */ +@Pure +@PythonName("function_with_parameters") +fun functionWithParameters( + @PythonName("no_type_no_default") noTypeNoDefault, + @PythonName("type_no_default") typeNoDefault, + @PythonName("with_default") withDefault, + args: List, + kwargs: Map +) + +/** + * Lorem ipsum. + * + * Dolor sit amet. + * + * @result result1 return value + */ +@Pure +@PythonName("function_with_result_value_and_type") +fun functionWithResultValueAndType() -> result1: Boolean + +// TODO Result type information missing. +/** + * Lorem ipsum. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_result_value_no_type") +fun functionWithResultValueNoType() + +// TODO Result type information missing. +/** + * Lorem ipsum. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_without_result_value") +fun functionWithoutResultValue() + +/** + * Lorem ipsum. Code:: + * + * pass + * + * Dolor sit amet. + */ +class ClassWithDocumentation() + +class ClassWithoutDocumentation() + +/** + * Lorem ipsum. + * + * Dolor sit amet. + * + * @param p foo defaults to 1 + */ +// TODO Some parameter have no type information. +class ClassWithParameters( + p +) + +/** + * Lorem ipsum. + * + * Dolor sit amet. + */ +class ClassWithAttributes() { + static attr p: Int + static attr q: Int +} + +/** + * Lorem ipsum. + * + * Dolor sit amet. + */ +class ClassWithAttributesNoType() { + static attr p: Int + static attr q: Int +} + +class ClassWithMethod() { + /** + * Lorem ipsum. + * + * Dolor sit amet. + */ + @PythonName("property_method_with_docstring") attr propertyMethodWithDocstring: Boolean + + // TODO Some parameter have no type information. + /** + * Lorem ipsum. + * + * Dolor sit amet. + * + * @param a type but no default + * + * @result result1 return value + */ + @Pure + @PythonName("method_with_docstring") + fun methodWithDocstring( + a + ) -> result1: Boolean +} + +/** + * Lorem ipsum. + * + * Dolor sit amet. + */ +enum EnumDocstring diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[full_docstring-PLAINTEXT].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[full_docstring-PLAINTEXT].sdsstub new file mode 100644 index 00000000..814d5d4a --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[full_docstring-PLAINTEXT].sdsstub @@ -0,0 +1,45 @@ +/** + * Test module for full docstring tests. + * + * A module for testing the various docstring types. + */ + +@PythonModule("tests.data.docstring_parser_package.full_docstring") +package tests.data.docstringParserPackage.fullDocstring + +// TODO Result type information missing. +/** + * function_with_multi_line_documentation. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_multi_line_documentation") +fun functionWithMultiLineDocumentation() + +// TODO Result type information missing. +/** + * function_with_single_line_documentation. + */ +@Pure +@PythonName("function_with_single_line_documentation") +fun functionWithSingleLineDocumentation() + +// TODO Result type information missing. +@Pure +@PythonName("function_without_documentation") +fun functionWithoutDocumentation() + +/** + * ClassWithMultiLineDocumentation. + * + * Dolor sit amet. + */ +class ClassWithMultiLineDocumentation() + +/** + * ClassWithSingleLineDocumentation. + */ +class ClassWithSingleLineDocumentation() + +class ClassWithoutDocumentation() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[googledoc-GOOGLE].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[googledoc-GOOGLE].sdsstub new file mode 100644 index 00000000..08b7c904 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[googledoc-GOOGLE].sdsstub @@ -0,0 +1,164 @@ +/** + * Test module for Google docstring tests. + * + * A module for testing the various docstring types. + */ + +@PythonModule("tests.data.docstring_parser_package.googledoc") +package tests.data.docstringParserPackage.googledoc + +// TODO Result type information missing. +/** + * function_with_documentation. Code:: + * + * pass + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_documentation") +fun functionWithDocumentation() + +// TODO Result type information missing. +@Pure +@PythonName("function_without_documentation") +fun functionWithoutDocumentation() + +// TODO Result type information missing. +// TODO Safe-DS does not support variadic parameters. +// TODO Some parameter have no type information. +/** + * function_with_parameters. + * + * Dolor sit amet. + * + * @param noTypeNoDefault no type and no default. + * @param typeNoDefault type but no default. + * @param withDefault foo. Defaults to 2. + */ +@Pure +@PythonName("function_with_parameters") +fun functionWithParameters( + @PythonName("no_type_no_default") noTypeNoDefault, + @PythonName("type_no_default") typeNoDefault, + @PythonName("with_default") withDefault, + args: List, + kwargs: Map +) + +// TODO Result type information missing. +// TODO Some parameter have no type information. +/** + * function_with_attributes_and_parameters. + * + * Dolor sit amet. + * + * @param q foo. Defaults to 2. + */ +@Pure +@PythonName("function_with_attributes_and_parameters") +fun functionWithAttributesAndParameters( + q +) + +/** + * function_with_return_value_and_type. + * + * Dolor sit amet. + * + * @result result1 this will be the return value. + */ +@Pure +@PythonName("function_with_return_value_and_type") +fun functionWithReturnValueAndType() -> result1: Boolean + +// TODO Result type information missing. +/** + * function_with_return_value_no_type. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_return_value_no_type") +fun functionWithReturnValueNoType() + +// TODO Result type information missing. +/** + * function_without_return_value. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_without_return_value") +fun functionWithoutReturnValue() + +/** + * ClassWithDocumentation. Code:: + * + * pass + * + * Dolor sit amet. + */ +class ClassWithDocumentation() + +class ClassWithoutDocumentation() + +/** + * ClassWithParameters. + * + * Dolor sit amet. + * + * @param p foo. Defaults to 1. + */ +// TODO Some parameter have no type information. +class ClassWithParameters( + p +) + +/** + * ClassWithAttributes. + * + * Dolor sit amet. + */ +class ClassWithAttributes() { + /** + * foo. Defaults to 1. + */ + static attr p: Int + /** + * foo. Defaults to 1. + */ + static attr q: Int +} + +class ClassWithMethod() { + /** + * property_method_with_docstring. + * + * Dolor sit amet. + */ + @PythonName("property_method_with_docstring") attr propertyMethodWithDocstring: Boolean + + // TODO Some parameter have no type information. + /** + * method_with_docstring. + * + * Dolor sit amet. + * + * @param a foo + * + * @result result1 this will be the return value. + */ + @Pure + @PythonName("method_with_docstring") + fun methodWithDocstring( + a + ) -> result1: Boolean +} + +/** + * EnumDocstring. + * + * Dolor sit amet. + */ +enum EnumDocstring diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[numpydoc-NUMPYDOC].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[numpydoc-NUMPYDOC].sdsstub new file mode 100644 index 00000000..1d5a91e4 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[numpydoc-NUMPYDOC].sdsstub @@ -0,0 +1,233 @@ +/** + * Test module for Numpy docstring tests. + * + * A module for testing the various docstring types. + */ + +@PythonModule("tests.data.docstring_parser_package.numpydoc") +package tests.data.docstringParserPackage.numpydoc + +// TODO Result type information missing. +/** + * function_with_documentation. Code:: + * + * pass + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_documentation") +fun functionWithDocumentation() + +// TODO Result type information missing. +@Pure +@PythonName("function_without_documentation") +fun functionWithoutDocumentation() + +// TODO Result type information missing. +// TODO Safe-DS does not support variadic parameters. +// TODO Some parameter have no type information. +/** + * function_with_parameters. + * + * Dolor sit amet. + * + * @param noTypeNoDefault foo: no_type_no_default. Code:: + * + * pass + * @param typeNoDefault foo: type_no_default + * @param optionalUnknownDefault foo: optional_unknown_default + * @param withDefaultSyntax1 foo: with_default_syntax_1 + * @param withDefaultSyntax2 foo: with_default_syntax_2 + * @param withDefaultSyntax3 foo: with_default_syntax_3 + * @param groupedParameter1 foo: grouped_parameter_1 and grouped_parameter_2 + * @param groupedParameter2 foo: grouped_parameter_1 and grouped_parameter_2 + * @param args foo: *args + * @param kwargs foo: **kwargs + */ +@Pure +@PythonName("function_with_parameters") +fun functionWithParameters( + @PythonName("no_type_no_default") noTypeNoDefault, + @PythonName("type_no_default") typeNoDefault, + @PythonName("optional_unknown_default") optionalUnknownDefault, + @PythonName("with_default_syntax_1") withDefaultSyntax1, + @PythonName("with_default_syntax_2") withDefaultSyntax2, + @PythonName("with_default_syntax_3") withDefaultSyntax3, + @PythonName("grouped_parameter_1") groupedParameter1, + @PythonName("grouped_parameter_2") groupedParameter2, + args: List, + kwargs: Map +) + +/** + * function_with_result_value_and_type. + * + * Dolor sit amet. + * + * @result result1 this will be the return value + */ +@Pure +@PythonName("function_with_result_value_and_type") +fun functionWithResultValueAndType() -> result1: Boolean + +/** + * function_with_named_result. + * + * Dolor sit amet. + * + * @result result1 this will be the return value + */ +@Pure +@PythonName("function_with_named_result") +fun functionWithNamedResult() -> result1: Boolean + +// TODO Result type information missing. +/** + * function_without_result_value. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_without_result_value") +fun functionWithoutResultValue() + +/** + * ClassWithDocumentation. Code:: + * + * pass + * + * Dolor sit amet. + */ +class ClassWithDocumentation() + +class ClassWithoutDocumentation() + +/** + * ClassWithParameters. + * + * Dolor sit amet. + * + * @param p foo + */ +// TODO Some parameter have no type information. +class ClassWithParameters( + p +) + +/** + * ClassAndConstructorWithParameters + * + * Dolor sit amet. + * + * @param x Lorem ipsum 1. + * @param y Lorem ipsum 2. + * @param z Lorem ipsum 3. + */ +// TODO Some parameter have no type information. +class ClassAndConstructorWithParameters( + x, + y, + z +) + +/** + * ClassWithParametersAndAttributes. + * + * Dolor sit amet. + * + * @param x foo + */ +// TODO Some parameter have no type information. +class ClassWithParametersAndAttributes( + x +) { + /** + * foo + */ + static attr p: Int + /** + * foo + */ + static attr q: Int +} + +/** + * ClassWithAttributes. + * + * Dolor sit amet. + */ +class ClassWithAttributes() { + /** + * foo: no_type_no_default. Code:: + * + * pass + */ + @PythonName("no_type_no_default") + static attr noTypeNoDefault: Any + /** + * foo: type_no_default + */ + @PythonName("type_no_default") + static attr typeNoDefault: Int + /** + * foo: optional_unknown_default + */ + @PythonName("optional_unknown_default") + static attr optionalUnknownDefault: Int? + /** + * foo: with_default_syntax_1 + */ + @PythonName("with_default_syntax_1") + static attr withDefaultSyntax1: Int + /** + * foo: with_default_syntax_2 + */ + @PythonName("with_default_syntax_2") + static attr withDefaultSyntax2: Int + /** + * foo: with_default_syntax_3 + */ + @PythonName("with_default_syntax_3") + static attr withDefaultSyntax3: Int + /** + * foo: grouped_attribute_1 and grouped_attribute_2 + */ + @PythonName("grouped_attribute_1") + static attr groupedAttribute1: Int + /** + * foo: grouped_attribute_1 and grouped_attribute_2 + */ + @PythonName("grouped_attribute_2") + static attr groupedAttribute2: Int +} + +class ClassWithMethod() { + /** + * property_method_with_docstring. + * + * Dolor sit amet. + */ + @PythonName("property_method_with_docstring") attr propertyMethodWithDocstring: Boolean + + // TODO Some parameter have no type information. + /** + * method_with_docstring. + * + * Dolor sit amet. + * + * @result result1 this will be the return value + */ + @Pure + @PythonName("method_with_docstring") + fun methodWithDocstring( + a + ) -> result1: Boolean +} + +/** + * EnumDocstring. + * + * Dolor sit amet. + */ +enum EnumDocstring diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[plaintext-PLAINTEXT].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[plaintext-PLAINTEXT].sdsstub new file mode 100644 index 00000000..6a267567 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[plaintext-PLAINTEXT].sdsstub @@ -0,0 +1,38 @@ +/** + * Test module for plaintext docstring tests. + * + * A module for testing the various docstring types. + */ + +@PythonModule("tests.data.docstring_parser_package.plaintext") +package tests.data.docstringParserPackage.plaintext + +// TODO Result type information missing. +/** + * function_with_documentation. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_documentation") +fun functionWithDocumentation( + p: Int +) + +// TODO Result type information missing. +@Pure +@PythonName("function_without_documentation") +fun functionWithoutDocumentation( + p: Int +) + +/** + * ClassWithDocumentation. + * + * Dolor sit amet. + */ +class ClassWithDocumentation( + p: Int +) + +class ClassWithoutDocumentation() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[restdoc-REST].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[restdoc-REST].sdsstub new file mode 100644 index 00000000..5a760196 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_docstring_creation[restdoc-REST].sdsstub @@ -0,0 +1,133 @@ +/** + * Test module for ReST docstring tests. + * + * A module for testing the various docstring types. + */ + +@PythonModule("tests.data.docstring_parser_package.restdoc") +package tests.data.docstringParserPackage.restdoc + +// TODO Result type information missing. +/** + * function_with_documentation. Code:: + * + * pass + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_documentation") +fun functionWithDocumentation() + +// TODO Result type information missing. +@Pure +@PythonName("function_without_documentation") +fun functionWithoutDocumentation() + +// TODO Result type information missing. +// TODO Safe-DS does not support variadic parameters. +// TODO Some parameter have no type information. +/** + * function_with_parameters. + * + * Dolor sit amet. + * + * @param noTypeNoDefault no type and no default + * @param typeNoDefault type but no default + * @param withDefault foo that defaults to 2 + */ +@Pure +@PythonName("function_with_parameters") +fun functionWithParameters( + @PythonName("no_type_no_default") noTypeNoDefault, + @PythonName("type_no_default") typeNoDefault, + @PythonName("with_default") withDefault, + args: List, + kwargs: Map +) + +/** + * function_with_return_value_and_type. + * + * Dolor sit amet. + * + * @result result1 return value + */ +@Pure +@PythonName("function_with_return_value_and_type") +fun functionWithReturnValueAndType() -> result1: Boolean + +// TODO Result type information missing. +/** + * function_with_return_value_no_type. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_with_return_value_no_type") +fun functionWithReturnValueNoType() + +// TODO Result type information missing. +/** + * function_without_return_value. + * + * Dolor sit amet. + */ +@Pure +@PythonName("function_without_return_value") +fun functionWithoutReturnValue() + +/** + * ClassWithDocumentation. Code:: + * + * pass + * + * Dolor sit amet. + */ +class ClassWithDocumentation() + +class ClassWithoutDocumentation() + +/** + * ClassWithParameters. + * + * Dolor sit amet. + * + * @param p foo defaults to 1 + */ +// TODO Some parameter have no type information. +class ClassWithParameters( + p +) + +class ClassWithMethod() { + /** + * property_method_with_docstring. + * + * Dolor sit amet. + */ + @PythonName("property_method_with_docstring") attr propertyMethodWithDocstring: Boolean + + // TODO Some parameter have no type information. + /** + * method_with_docstring. + * + * Dolor sit amet. + * + * @param a type but no default + * + * @result result1 return value + */ + @Pure + @PythonName("method_with_docstring") + fun methodWithDocstring( + a + ) -> result1: Boolean +} + +/** + * EnumDocstring. + * + * Dolor sit amet. + */ +enum EnumDocstring diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 878f8520..3c896159 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -5,6 +5,7 @@ import pytest from safeds_stubgen.api_analyzer import get_api +from safeds_stubgen.docstring_parsing import DocstringStyle from safeds_stubgen.stubs_generator import generate_stubs # noinspection PyProtectedMember @@ -28,6 +29,9 @@ _out_dir = Path(_lib_dir / "data" / "out") _out_dir_stubs = Path(_out_dir / "tests/data" / _test_package_name) +_docstring_package_name = "docstring_parser_package" +_docstring_package_dir = Path(_lib_dir / "data" / _docstring_package_name) + api = get_api(_test_package_name, _test_package_dir, is_test_run=True) stubs_generator = StubsStringGenerator(api, naming_convention=NamingConvention.SAFE_DS) stubs_data = _generate_stubs_data(api, _out_dir, stubs_generator) @@ -104,7 +108,7 @@ def test_stub_creation(self, python_file: Path, snapshot_sds_stub: SnapshotAsser if file_name in {"__init__", "_module_2", "_module_4", "_reexport_module_5"}: return - raise AssertionError(f"Stub file not found for '{file_name}'.") + raise pytest.fail(f"Stub file not found for '{file_name}'.") @pytest.mark.parametrize( @@ -135,3 +139,36 @@ def test_convert_name_to_convention( _convert_name_to_convention(name=name, naming_convention=naming_convention, is_class_name=is_class_name) == expected_result ) + + +@pytest.mark.parametrize( + ("filename", "docstring_style"), + [ + ("epydoc", DocstringStyle.EPYDOC), + ("full_docstring", DocstringStyle.PLAINTEXT), + ("googledoc", DocstringStyle.GOOGLE), + ("numpydoc", DocstringStyle.NUMPYDOC), + ("plaintext", DocstringStyle.PLAINTEXT), + ("restdoc", DocstringStyle.REST), + ], +) +def test_stub_docstring_creation( + filename: str, + docstring_style: DocstringStyle, + snapshot_sds_stub: SnapshotAssertion, +) -> None: + docstring_api = get_api( + _docstring_package_name, + _docstring_package_dir, + docstring_style=docstring_style, + is_test_run=True, + ) + docstring_stubs_generator = StubsStringGenerator(docstring_api, naming_convention=NamingConvention.SAFE_DS) + docstring_stubs_data = _generate_stubs_data(docstring_api, _out_dir, docstring_stubs_generator) + + for stub_text in docstring_stubs_data: + if stub_text[1] == filename: + assert stub_text[2] == snapshot_sds_stub + return + + raise pytest.fail(f"Could not find data for '{filename}'.")