From e4c9d07304cf7185dad966ed995ca060f926022a Mon Sep 17 00:00:00 2001 From: Arsam Date: Wed, 28 Feb 2024 21:21:38 +0100 Subject: [PATCH 01/25] now limited stubs are created for the imported classes from other packages, if they are imported --- .../stubs_generator/_generate_stubs.py | 297 +++++++++++------- .../test_class_attribute_creation.sdsstub | 2 + .../test_function_creation.sdsstub | 2 + .../stubs_generator/test_generate_stubs.py | 43 +-- 4 files changed, 200 insertions(+), 144 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index e99d91b7..6076c8a9 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -51,7 +51,7 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: module_text = stubs_generator(module) - # Each text block we create ends with "\n", therefore, is there is only the package information + # Each text block we create ends with "\n", therefore, if there is only the package information # 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. @@ -70,6 +70,58 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: with file_path.open("w") as f: f.write(module_text) + for class_ in stubs_generator.classes_outside_package: + _create_outside_package_class(class_, out_path, convert_identifiers) + + +def _create_outside_package_class(class_path: str, out_path: Path, convert_identifiers: bool) -> None: + path_parts = class_path.split(".") + class_name = path_parts.pop(-1) + module_name = path_parts[-1] + module_path = "/".join(path_parts) + + module_dir = Path(out_path / module_path) + module_dir.mkdir(parents=True, exist_ok=True) + + file_path = Path(module_dir / f"{module_name}.sdsstub") + if Path.exists(file_path): + with file_path.open("a") as f: + f.write(_create_outside_package_class_text(class_name, convert_identifiers)) + else: + with file_path.open("w") as f: + module_text = "" + + # package name & annotation + python_module_path = ".".join(path_parts) + module_path_camel_case = python_module_path + if convert_identifiers: + module_path_camel_case = _convert_snake_to_camel_case(python_module_path) + module_name_info = "" + if python_module_path != module_path_camel_case: + module_text += f'@PythonModule("{python_module_path}")\n' + module_text += f"{module_name_info}package {module_path_camel_case}\n" + + module_text += _create_outside_package_class_text(class_name, convert_identifiers) + + f.write(module_text) + + +def _create_outside_package_class_text(class_name, convert_identifiers): + # to camel case + camel_case_name = class_name + if convert_identifiers: + camel_case_name = _convert_snake_to_camel_case(class_name) + + # add name annotation + class_annotation = "" + if class_name != camel_case_name: + class_annotation = f"\n{_create_name_annotation(class_name)}" + + # check for identifiers + safe_class_name = _replace_if_safeds_keyword(camel_case_name) + + return f"{class_annotation}\nclass {safe_class_name}()\n" + class StubsStringGenerator: """Generate Safe-DS stub strings. @@ -79,13 +131,12 @@ class StubsStringGenerator: """ def __init__(self, api: API, convert_identifiers: bool) -> None: - self.module_imports: set[str] = set() self.api = api self.convert_identifiers = convert_identifiers + self.classes_outside_package: set[str] = set() def __call__(self, module: Module) -> str: - # Reset the module_imports list - self.module_imports = set() + self.module_imports: set[str] = set() self._current_todo_msgs: set[str] = set() self.module = module return self._create_module_string(module) @@ -93,7 +144,9 @@ def __call__(self, module: Module) -> str: def _create_module_string(self, module: Module) -> str: # Create package info package_info = module.id.replace("/", ".") - package_info_camel_case = self._convert_snake_to_camel_case(package_info) + package_info_camel_case = package_info + if self.convert_identifiers: + package_info_camel_case = _convert_snake_to_camel_case(package_info) module_name_info = "" module_text = "" if package_info != package_info_camel_case: @@ -163,7 +216,7 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st if superclasses and not class_.is_abstract: superclass_names = [] for superclass in superclasses: - superclass_names.append(self._split_import_id(superclass)[1]) + superclass_names.append(superclass.split(".")[-1]) self._add_to_imports(superclass) superclass_info = f" sub {', '.join(superclass_names)}" @@ -185,8 +238,10 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st }[variance.variance.name] # Convert name to camelCase and check for keywords - variance_name_camel_case = self._convert_snake_to_camel_case(variance.name) - variance_name_camel_case = self._replace_if_safeds_keyword(variance_name_camel_case) + variance_name_camel_case = variance.name + if self.convert_identifiers: + variance_name_camel_case = _convert_snake_to_camel_case(variance.name) + variance_name_camel_case = _replace_if_safeds_keyword(variance_name_camel_case) variance_item = f"{variance_direction}{variance_name_camel_case}" if variance_direction == out: @@ -199,10 +254,12 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st # Class name - Convert to camelCase and check for keywords class_name = class_.name python_name_info = "" - class_name_camel_case = self._convert_snake_to_camel_case(class_name, is_class_name=True) + class_name_camel_case = class_name + if self.convert_identifiers: + class_name_camel_case = _convert_snake_to_camel_case(class_name, is_class_name=True) if class_name_camel_case != class_name: - python_name_info = f"{class_indentation}{self._create_name_annotation(class_name)}\n" - class_name_camel_case = self._replace_if_safeds_keyword(class_name_camel_case) + python_name_info = f"{class_indentation}{_create_name_annotation(class_name)}\n" + class_name_camel_case = _replace_if_safeds_keyword(class_name_camel_case) # Class signature line class_signature = ( @@ -269,13 +326,15 @@ def _create_class_attribute_string(self, attributes: list[Attribute], inner_inde # Convert name to camelCase and add PythonName annotation attr_name = attribute.name - attr_name_camel_case = self._convert_snake_to_camel_case(attr_name) + attr_name_camel_case = attr_name + if self.convert_identifiers: + attr_name_camel_case = _convert_snake_to_camel_case(attr_name) attr_name_annotation = "" if attr_name_camel_case != attr_name: - attr_name_annotation = f"{self._create_name_annotation(attr_name)}\n{inner_indentations}" + attr_name_annotation = f"{_create_name_annotation(attr_name)}\n{inner_indentations}" # Check if name is a Safe-DS keyword and escape it if necessary - attr_name_camel_case = self._replace_if_safeds_keyword(attr_name_camel_case) + attr_name_camel_case = _replace_if_safeds_keyword(attr_name_camel_case) # Create type information attr_type = self._create_type_string(attribute_type) @@ -319,13 +378,15 @@ def _create_function_string(self, function: Function, indentations: str = "", is # Convert function name to camelCase name = function.name - camel_case_name = self._convert_snake_to_camel_case(name) + camel_case_name = name + if self.convert_identifiers: + camel_case_name = _convert_snake_to_camel_case(name) function_name_annotation = "" if camel_case_name != name: - function_name_annotation = f"{indentations}{self._create_name_annotation(name)}\n" + function_name_annotation = f"{indentations}{_create_name_annotation(name)}\n" # Escape keywords - camel_case_name = self._replace_if_safeds_keyword(camel_case_name) + camel_case_name = _replace_if_safeds_keyword(camel_case_name) result_string = self._create_result_string(function.results) @@ -344,13 +405,15 @@ def _create_property_function_string(self, function: Function, indentations: str Functions or methods with the @property decorator are handled the same way as class attributes. """ name = function.name - camel_case_name = self._convert_snake_to_camel_case(name) + camel_case_name = name + if self.convert_identifiers: + camel_case_name = _convert_snake_to_camel_case(name) function_name_annotation = "" if camel_case_name != name: - function_name_annotation = f"{self._create_name_annotation(name)} " + function_name_annotation = f"{_create_name_annotation(name)} " # Escape keywords - camel_case_name = self._replace_if_safeds_keyword(camel_case_name) + camel_case_name = _replace_if_safeds_keyword(camel_case_name) # Create type information result_types = [result.type for result in function.results if result.type is not None] @@ -374,8 +437,10 @@ def _create_result_string(self, function_results: list[Result]) -> str: result_type = result.type.to_dict() ret_type = self._create_type_string(result_type) type_string = f": {ret_type}" if ret_type else "" - result_name = self._convert_snake_to_camel_case(result.name) - result_name = self._replace_if_safeds_keyword(result_name) + result_name = result.name + if self.convert_identifiers: + result_name = _convert_snake_to_camel_case(result.name) + result_name = _replace_if_safeds_keyword(result_name) if type_string: results.append( f"{result_name}{type_string}", @@ -452,14 +517,16 @@ def _create_parameter_string( # Convert to camelCase if necessary name = parameter.name - camel_case_name = self._convert_snake_to_camel_case(name) + camel_case_name = name + if self.convert_identifiers: + camel_case_name = _convert_snake_to_camel_case(name) name_annotation = "" if camel_case_name != name: # Memorize the changed name for the @PythonName() annotation - name_annotation = f"{self._create_name_annotation(name)} " + name_annotation = f"{_create_name_annotation(name)} " # Check if it's a Safe-DS keyword and escape it - camel_case_name = self._replace_if_safeds_keyword(camel_case_name) + camel_case_name = _replace_if_safeds_keyword(camel_case_name) # Create string and append to the list parameters_data.append( @@ -486,13 +553,15 @@ def _create_enum_string(self, enum_data: Enum) -> str: name = enum_instance.name # Convert snake_case names to camelCase - camel_case_name = self._convert_snake_to_camel_case(name) + camel_case_name = name + if self.convert_identifiers: + camel_case_name = _convert_snake_to_camel_case(name) annotation = "" if camel_case_name != name: - annotation = f"{self._create_name_annotation(name)} " + annotation = f"{_create_name_annotation(name)} " # Check if the name is a Safe-DS keyword and escape it - camel_case_name = self._replace_if_safeds_keyword(camel_case_name) + camel_case_name = _replace_if_safeds_keyword(camel_case_name) enum_text += f"\t{annotation}{camel_case_name}\n" return f"{enum_signature} {{{enum_text}}}" @@ -530,7 +599,7 @@ def _create_type_string(self, type_data: dict | None) -> str: elif kind == "FinalType": return self._create_type_string(type_data["type"]) elif kind == "CallableType": - name_generator = self._callable_type_name_generator() + name_generator = _callable_type_name_generator() params = [ f"{next(name_generator)}: {self._create_type_string(parameter_type)}" @@ -653,26 +722,19 @@ def _add_to_imports(self, qname: str) -> None: # We need the full path for an import from the same package, but we sometimes don't get enough information, # therefore we have to search for the class and get its id qname_path = qname.replace(".", "/") + in_package = False for class_ in self.api.classes: if class_.endswith(qname_path): qname = class_.replace("/", ".") - qname = self._convert_snake_to_camel_case(qname) - self.module_imports.add(qname) + if self.convert_identifiers: + qname = _convert_snake_to_camel_case(qname) + in_package = True break - # Todo Currently deactivated, since imports from other packages don't have stubs - see issue #66 - # If the issue is resolved, remove the "self.module_imports.add(qname)" above - # self.module_imports.add(qname) + if not in_package: + self.classes_outside_package.add(qname) - @staticmethod - def _callable_type_name_generator() -> Generator: - """Generate a name for callable type parameters starting from 'a' until 'zz'.""" - while True: - for x in range(1, 27): - yield string.ascii_lowercase[x - 1] - for x in range(1, 27): # pragma: no cover - for y in range(1, 27): - yield string.ascii_lowercase[x - 1] + string.ascii_lowercase[y - 1] + self.module_imports.add(qname) def _create_todo_msg(self, indentations: str) -> str: if not self._current_todo_msgs: @@ -704,78 +766,79 @@ def _create_todo_msg(self, indentations: str) -> str: return indentations + f"\n{indentations}".join(todo_msgs) + "\n" - @staticmethod - def _split_import_id(id_: str) -> tuple[str, str]: - split_qname = id_.split(".") - name = split_qname.pop(-1) - import_path = ".".join(split_qname) - return import_path, name - - @staticmethod - def _create_name_annotation(name: str) -> str: - return f'@PythonName("{name}")' - - @staticmethod - def _replace_if_safeds_keyword(keyword: str) -> str: - if keyword in { - "as", - "from", - "import", - "literal", - "union", - "where", - "yield", - "false", - "null", - "true", - "annotation", - "attr", - "class", - "enum", - "fun", - "package", - "pipeline", - "schema", - "segment", - "val", - "const", - "in", - "internal", - "out", - "private", - "static", - "and", - "not", - "or", - "sub", - "super", - "_", - }: - return f"`{keyword}`" - return keyword - - def _convert_snake_to_camel_case(self, name: str, is_class_name: bool = False) -> str: - if not self.convert_identifiers: - return name - - if name == "_": - return name - - # Count underscores in front and behind the name - underscore_count_start = len(name) - len(name.lstrip("_")) - underscore_count_end = len(name) - len(name.rstrip("_")) - - if underscore_count_end == 0: - cleaned_name = name[underscore_count_start:] - else: - cleaned_name = name[underscore_count_start:-underscore_count_end] - - # Remove underscores and join in camelCase - name_parts = cleaned_name.split("_") - - # UpperCamelCase for class names - if is_class_name: - return "".join(part[0].upper() + part[1:] for part in name_parts if part) - # Normal camelCase for everything else - return name_parts[0] + "".join(part[0].upper() + part[1:] for part in name_parts[1:] if part) +def _callable_type_name_generator() -> Generator: + """Generate a name for callable type parameters starting from 'a' until 'zz'.""" + while True: + for x in range(1, 27): + yield string.ascii_lowercase[x - 1] + for x in range(1, 27): # pragma: no cover + for y in range(1, 27): + yield string.ascii_lowercase[x - 1] + string.ascii_lowercase[y - 1] + + +def _create_name_annotation(name: str) -> str: + return f'@PythonName("{name}")' + + +def _replace_if_safeds_keyword(keyword: str) -> str: + if keyword in { + "as", + "from", + "import", + "literal", + "union", + "where", + "yield", + "false", + "null", + "true", + "annotation", + "attr", + "class", + "enum", + "fun", + "package", + "pipeline", + "schema", + "segment", + "val", + "const", + "in", + "internal", + "out", + "private", + "static", + "and", + "not", + "or", + "sub", + "super", + "_", + }: + return f"`{keyword}`" + return keyword + + +def _convert_snake_to_camel_case(name: str, is_class_name: bool = False) -> str: + if name == "_": + return name + + # Count underscores in front and behind the name + underscore_count_start = len(name) - len(name.lstrip("_")) + underscore_count_end = len(name) - len(name.rstrip("_")) + + if underscore_count_end == 0: + cleaned_name = name[underscore_count_start:] + else: + cleaned_name = name[underscore_count_start:-underscore_count_end] + + # Remove underscores and join in camelCase + name_parts = cleaned_name.split("_") + + # UpperCamelCase for class names + if is_class_name: + return "".join(part[0].upper() + part[1:] for part in name_parts if part) + + # Normal camelCase for everything else + return name_parts[0] + "".join(part[0].upper() + part[1:] for part in name_parts[1:] if part) diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub index 858101a2..4548f3e4 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub @@ -1,6 +1,8 @@ @PythonModule("various_modules_package.attribute_module") package variousModulesPackage.attributeModule +from tests.data.main_package.another_path.another_module import AnotherClass + class AttributesClassA() class AttributesClassB() { diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub index d63a22d9..47274739 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub @@ -1,6 +1,8 @@ @PythonModule("various_modules_package.function_module") package variousModulesPackage.functionModule +from tests.data.main_package.another_path.another_module import AnotherClass + // TODO Result type information missing. @Pure @PythonName("public_no_params_no_result") diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 0a3fa63b..1a5ae412 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -4,11 +4,11 @@ from typing import TYPE_CHECKING import pytest -from safeds_stubgen.api_analyzer import API, get_api +from safeds_stubgen.api_analyzer import get_api from safeds_stubgen.stubs_generator import generate_stubs # noinspection PyProtectedMember -from safeds_stubgen.stubs_generator._generate_stubs import StubsStringGenerator +from safeds_stubgen.stubs_generator._generate_stubs import _convert_snake_to_camel_case if TYPE_CHECKING: from syrupy import SnapshotAssertion @@ -111,31 +111,20 @@ def test_alias_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> @pytest.mark.parametrize( - ("name", "expected_result", "is_class_name", "convert_identifiers"), + ("name", "expected_result", "is_class_name"), [ - ("", "", False, True), - ("_", "_", False, True), - ("__get_function_name__", "getFunctionName", False, True), - ("__get_function_name", "getFunctionName", False, True), - ("get_function_name__", "getFunctionName", False, True), - ("__getFunction_name__", "getFunctionName", False, True), - ("__get__function___name__", "getFunctionName", False, True), - ("__get_funCtion_NamE__", "getFunCtionNamE", False, True), - ("getFunctionName", "getFunctionName", False, True), - ("a_a_A_aAAaA_1_1_2_aAa", "aAAAAAaA112AAa", False, True), - ("some_class_name", "SomeClassName", True, True), - ("some_function_name", "some_function_name", False, False), - ("some_class_name", "some_class_name", True, False), + ("", "", False), + ("_", "_", False), + ("__get_function_name__", "getFunctionName", False), + ("__get_function_name", "getFunctionName", False), + ("get_function_name__", "getFunctionName", False), + ("__getFunction_name__", "getFunctionName", False), + ("__get__function___name__", "getFunctionName", False), + ("__get_funCtion_NamE__", "getFunCtionNamE", False), + ("getFunctionName", "getFunctionName", False), + ("a_a_A_aAAaA_1_1_2_aAa", "aAAAAAaA112AAa", False), + ("some_class_name", "SomeClassName", True), ], ) -def test_convert_snake_to_camel_case( - name: str, - expected_result: str, - is_class_name: bool, - convert_identifiers: bool, -) -> None: - stubs_string_generator = StubsStringGenerator( - api=API(distribution="", package=_test_package_name, version=""), - convert_identifiers=convert_identifiers, - ) - assert stubs_string_generator._convert_snake_to_camel_case(name, is_class_name) == expected_result +def test_convert_snake_to_camel_case(name: str, expected_result: str, is_class_name: bool) -> None: + assert _convert_snake_to_camel_case(name, is_class_name=is_class_name) == expected_result From c0e13ea8d6877ee06936c01cc0df6e943eac8643 Mon Sep 17 00:00:00 2001 From: Arsam Date: Thu, 29 Feb 2024 14:40:08 +0100 Subject: [PATCH 02/25] Refactoring: Removed type hints from docs --- .../stubs_generator/_generate_stubs.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 6076c8a9..eda9f2e3 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -29,12 +29,12 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: Parameters ---------- - api : API + api The API object from which the stubs - out_path : Path + out_path The path in which the stub files should be created. If no such path exists this function creates the directory files. - convert_identifiers : bool + convert_identifiers Set this True if the identifiers should be converted to Safe-DS standard (UpperCamelCase for classes and camelCase for everything else). """ @@ -120,7 +120,7 @@ def _create_outside_package_class_text(class_name, convert_identifiers): # check for identifiers safe_class_name = _replace_if_safeds_keyword(camel_case_name) - return f"{class_annotation}\nclass {safe_class_name}()\n" + return f"{class_annotation}\nclass {safe_class_name}\n" class StubsStringGenerator: @@ -703,12 +703,8 @@ def _add_to_imports(self, qname: str) -> None: Paramters --------- - qname : str + qname The qualified name of a module/class/etc. - - Returns - ------- - None """ if qname == "": # pragma: no cover raise ValueError("Type has no import source.") From 59de1576649520505059792c1d8740b0d5eaed06 Mon Sep 17 00:00:00 2001 From: Arsam Date: Thu, 29 Feb 2024 14:53:56 +0100 Subject: [PATCH 03/25] bug fixes and added tests --- .../stubs_generator/_generate_stubs.py | 22 ++++-- .../another_path/another_module.py | 4 ++ .../various_modules_package/class_module.py | 5 +- .../__snapshots__/test_main.ambr | 70 +++++++++++++++++++ .../__snapshots__/test__get_api.ambr | 5 ++ .../test_class_creation.sdsstub | 4 +- ...tion_limited_stubs_outside_package.sdsstub | 4 ++ .../stubs_generator/test_generate_stubs.py | 8 +++ 8 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index eda9f2e3..ccc18a2e 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -70,21 +70,33 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: with file_path.open("w") as f: f.write(module_text) - for class_ in stubs_generator.classes_outside_package: - _create_outside_package_class(class_, out_path, convert_identifiers) + created_module_paths = set() + classes_outside_package = list(stubs_generator.classes_outside_package) + classes_outside_package.sort() + for class_ in classes_outside_package: + created_module_paths = _create_outside_package_class( + class_, out_path, convert_identifiers, created_module_paths + ) -def _create_outside_package_class(class_path: str, out_path: Path, convert_identifiers: bool) -> None: +def _create_outside_package_class( + class_path: str, out_path: Path, convert_identifiers: bool, created_module_paths: set[str] +) -> set[str]: path_parts = class_path.split(".") class_name = path_parts.pop(-1) module_name = path_parts[-1] module_path = "/".join(path_parts) + first_creation = False + if module_path not in created_module_paths: + created_module_paths.add(module_path) + first_creation = True + module_dir = Path(out_path / module_path) module_dir.mkdir(parents=True, exist_ok=True) file_path = Path(module_dir / f"{module_name}.sdsstub") - if Path.exists(file_path): + if Path.exists(file_path) and not first_creation: with file_path.open("a") as f: f.write(_create_outside_package_class_text(class_name, convert_identifiers)) else: @@ -105,6 +117,8 @@ def _create_outside_package_class(class_path: str, out_path: Path, convert_ident f.write(module_text) + return created_module_paths + def _create_outside_package_class_text(class_name, convert_identifiers): # to camel case diff --git a/tests/data/main_package/another_path/another_module.py b/tests/data/main_package/another_path/another_module.py index 0d53fe84..d7fb5bc0 100644 --- a/tests/data/main_package/another_path/another_module.py +++ b/tests/data/main_package/another_path/another_module.py @@ -6,3 +6,7 @@ class AnotherClass: pass + + +class YetAnotherClass: + def another_function(self) -> str: ... diff --git a/tests/data/various_modules_package/class_module.py b/tests/data/various_modules_package/class_module.py index fdc1de62..06a84ad5 100644 --- a/tests/data/various_modules_package/class_module.py +++ b/tests/data/various_modules_package/class_module.py @@ -1,3 +1,6 @@ +from tests.data.main_package.another_path.another_module import YetAnotherClass + + class ClassModuleEmptyClassA: ... @@ -8,7 +11,7 @@ def __init__(self, a: int, b: ClassModuleEmptyClassA | None): ... def f(self): ... -class ClassModuleClassC(ClassModuleEmptyClassA, ClassModuleClassB): +class ClassModuleClassC(ClassModuleEmptyClassA, ClassModuleClassB, YetAnotherClass): attr_1: int attr_2: int diff --git a/tests/safeds_stubgen/__snapshots__/test_main.ambr b/tests/safeds_stubgen/__snapshots__/test_main.ambr index e7a0dfb9..db3a3a3c 100644 --- a/tests/safeds_stubgen/__snapshots__/test_main.ambr +++ b/tests/safeds_stubgen/__snapshots__/test_main.ambr @@ -122,6 +122,29 @@ 'type_parameters': list([ ]), }), + dict({ + 'attributes': list([ + ]), + 'classes': list([ + ]), + 'constructor': None, + 'docstring': dict({ + 'description': '', + 'full_docstring': '', + }), + 'id': 'main_package/another_path/another_module/YetAnotherClass', + 'is_public': True, + 'methods': list([ + 'main_package/another_path/another_module/YetAnotherClass/another_function', + ]), + 'name': 'YetAnotherClass', + 'reexported_by': list([ + ]), + 'superclasses': list([ + ]), + 'type_parameters': list([ + ]), + }), dict({ 'attributes': list([ 'main_package/main_module/ModuleClass/attr_1', @@ -307,6 +330,26 @@ 'enums': list([ ]), 'functions': list([ + dict({ + 'docstring': dict({ + 'description': '', + 'full_docstring': '', + }), + 'id': 'main_package/another_path/another_module/YetAnotherClass/another_function', + 'is_class_method': False, + 'is_property': False, + 'is_public': True, + 'is_static': False, + 'name': 'another_function', + 'parameters': list([ + 'main_package/another_path/another_module/YetAnotherClass/another_function/self', + ]), + 'reexported_by': list([ + ]), + 'results': list([ + 'main_package/another_path/another_module/YetAnotherClass/another_function/result_1', + ]), + }), dict({ 'docstring': dict({ 'description': '', @@ -495,6 +538,7 @@ dict({ 'classes': list([ 'main_package/another_path/another_module/AnotherClass', + 'main_package/another_path/another_module/YetAnotherClass', ]), 'docstring': ''' Another Module Docstring. @@ -554,6 +598,19 @@ ]), 'package': 'main_package', 'parameters': list([ + dict({ + 'assigned_by': 'IMPLICIT', + 'default_value': None, + 'docstring': dict({ + 'default_value': '', + 'description': '', + 'type': '', + }), + 'id': 'main_package/another_path/another_module/YetAnotherClass/another_function/self', + 'is_optional': False, + 'name': 'self', + 'type': None, + }), dict({ 'assigned_by': 'POSITION_OR_NAME', 'default_value': None, @@ -729,6 +786,19 @@ }), ]), 'results': list([ + dict({ + 'docstring': dict({ + 'description': '', + 'type': '', + }), + 'id': 'main_package/another_path/another_module/YetAnotherClass/another_function/result_1', + 'name': 'result_1', + 'type': dict({ + 'kind': 'NamedType', + 'name': 'str', + 'qname': 'builtins.str', + }), + }), dict({ 'docstring': dict({ 'description': '', 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 6165c319..971a1395 100644 --- a/tests/safeds_stubgen/api_analyzer/__snapshots__/test__get_api.ambr +++ b/tests/safeds_stubgen/api_analyzer/__snapshots__/test__get_api.ambr @@ -2025,6 +2025,7 @@ 'superclasses': list([ 'tests.data.various_modules_package.class_module.ClassModuleEmptyClassA', 'tests.data.various_modules_package.class_module.ClassModuleClassB', + 'tests.data.main_package.another_path.another_module.YetAnotherClass', ]), 'type_parameters': list([ ]), @@ -6337,6 +6338,10 @@ 'id': 'various_modules_package/class_module', 'name': 'class_module', 'qualified_imports': list([ + dict({ + 'alias': None, + 'qualified_name': 'tests.data.main_package.another_path.another_module.YetAnotherClass', + }), ]), 'wildcard_imports': list([ ]), diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub index d601410b..2e9df233 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub @@ -1,6 +1,8 @@ @PythonModule("various_modules_package.class_module") package variousModulesPackage.classModule +from tests.data.main_package.another_path.another_module import YetAnotherClass + class ClassModuleEmptyClassA() class ClassModuleClassB( @@ -13,7 +15,7 @@ class ClassModuleClassB( } // TODO Safe-DS does not support multiple inheritance. -class ClassModuleClassC() sub ClassModuleEmptyClassA, ClassModuleClassB { +class ClassModuleClassC() sub ClassModuleEmptyClassA, ClassModuleClassB, YetAnotherClass { @PythonName("attr_1") static attr attr1: Int @PythonName("attr_2") diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub new file mode 100644 index 00000000..def2cbef --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub @@ -0,0 +1,4 @@ +@PythonModule("tests.data.main_package.another_path.another_module") +package tests.data.mainPackage.anotherPath.anotherModule + +class AnotherClass diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 1a5ae412..42ef4eea 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -68,6 +68,14 @@ def test_file_creation() -> None: ) +def test_file_creation_limited_stubs_outside_package(snapshot_sds_stub: SnapshotAssertion) -> None: + path = Path(_out_dir / "tests/data/main_package/another_path/another_module/another_module.sdsstub") + assert path.is_file() + + with path.open("r") as f: + assert f.read() == snapshot_sds_stub + + def test_class_creation(snapshot_sds_stub: SnapshotAssertion) -> None: assert_stubs_snapshot("class_module", snapshot_sds_stub) From e6bed74f6c8d14a4be048ecc5fd59e9af28b22d2 Mon Sep 17 00:00:00 2001 From: Arsam Date: Thu, 29 Feb 2024 14:57:10 +0100 Subject: [PATCH 04/25] Imports in stubs are camel case and checked for safeds keyword --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 7 +++++++ .../test_class_attribute_creation.sdsstub | 2 +- .../test_generate_stubs/test_class_creation.sdsstub | 2 +- .../test_generate_stubs/test_function_creation.sdsstub | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index ccc18a2e..b8cdcbc5 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -194,8 +194,15 @@ def _create_imports_string(self) -> str: for import_ in self.module_imports: import_parts = import_.split(".") + from_ = ".".join(import_parts[0:-1]) + from_ = _convert_snake_to_camel_case(from_) + from_ = _replace_if_safeds_keyword(from_) + name = import_parts[-1] + name = _convert_snake_to_camel_case(name) + name = _replace_if_safeds_keyword(name) + import_strings.append(f"from {from_} import {name}") # We have to sort for the snapshot tests diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub index 4548f3e4..51b6ce97 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub @@ -1,7 +1,7 @@ @PythonModule("various_modules_package.attribute_module") package variousModulesPackage.attributeModule -from tests.data.main_package.another_path.another_module import AnotherClass +from tests.data.mainPackage.anotherPath.anotherModule import AnotherClass class AttributesClassA() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub index 2e9df233..5b8c0ffc 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub @@ -1,7 +1,7 @@ @PythonModule("various_modules_package.class_module") package variousModulesPackage.classModule -from tests.data.main_package.another_path.another_module import YetAnotherClass +from tests.data.mainPackage.anotherPath.anotherModule import YetAnotherClass class ClassModuleEmptyClassA() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub index 47274739..efd8c3e7 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub @@ -1,7 +1,7 @@ @PythonModule("various_modules_package.function_module") package variousModulesPackage.functionModule -from tests.data.main_package.another_path.another_module import AnotherClass +from tests.data.mainPackage.anotherPath.anotherModule import AnotherClass // TODO Result type information missing. @Pure From 33ab05ed86cb2813c3089c1b146fdf2bf9c9af8b Mon Sep 17 00:00:00 2001 From: Arsam Date: Thu, 29 Feb 2024 15:04:32 +0100 Subject: [PATCH 05/25] linter fix --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index b8cdcbc5..136e0cd8 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -70,7 +70,7 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: with file_path.open("w") as f: f.write(module_text) - created_module_paths = set() + created_module_paths: set[str] = set() classes_outside_package = list(stubs_generator.classes_outside_package) classes_outside_package.sort() for class_ in classes_outside_package: From 96f759ca1734a76229ddc193f455c331c01cdcce Mon Sep 17 00:00:00 2001 From: Arsam Date: Thu, 29 Feb 2024 16:27:56 +0100 Subject: [PATCH 06/25] linter fix --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 136e0cd8..d415050a 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -120,7 +120,7 @@ def _create_outside_package_class( return created_module_paths -def _create_outside_package_class_text(class_name, convert_identifiers): +def _create_outside_package_class_text(class_name: str, convert_identifiers: bool) -> str: # to camel case camel_case_name = class_name if convert_identifiers: From b5b8d6cd82d902ae2ef4bd19089bdd6c77ea7875 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:29:34 +0000 Subject: [PATCH 07/25] style: apply automated linter fixes --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index d415050a..50e8d791 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -75,12 +75,12 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: classes_outside_package.sort() for class_ in classes_outside_package: created_module_paths = _create_outside_package_class( - class_, out_path, convert_identifiers, created_module_paths + class_, out_path, convert_identifiers, created_module_paths, ) def _create_outside_package_class( - class_path: str, out_path: Path, convert_identifiers: bool, created_module_paths: set[str] + class_path: str, out_path: Path, convert_identifiers: bool, created_module_paths: set[str], ) -> set[str]: path_parts = class_path.split(".") class_name = path_parts.pop(-1) From 8078d0c7a736657bff86908d525d35632281bac4 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:31:08 +0000 Subject: [PATCH 08/25] style: apply automated linter fixes --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 50e8d791..e2758d0a 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -75,12 +75,18 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: classes_outside_package.sort() for class_ in classes_outside_package: created_module_paths = _create_outside_package_class( - class_, out_path, convert_identifiers, created_module_paths, + class_, + out_path, + convert_identifiers, + created_module_paths, ) def _create_outside_package_class( - class_path: str, out_path: Path, convert_identifiers: bool, created_module_paths: set[str], + class_path: str, + out_path: Path, + convert_identifiers: bool, + created_module_paths: set[str], ) -> set[str]: path_parts = class_path.split(".") class_name = path_parts.pop(-1) From 9d53610dca712fb82ce4ca38f2a7c5821fdbde52 Mon Sep 17 00:00:00 2001 From: Arsam Date: Thu, 29 Feb 2024 16:42:21 +0100 Subject: [PATCH 09/25] added test case --- .../another_path/another_module.py | 2 +- .../various_modules_package/class_module.py | 4 ++-- .../__snapshots__/test_main.ambr | 18 +++++++++--------- .../__snapshots__/test__get_api.ambr | 4 ++-- .../test_class_creation.sdsstub | 4 ++-- ...ation_limited_stubs_outside_package.sdsstub | 2 ++ 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/tests/data/main_package/another_path/another_module.py b/tests/data/main_package/another_path/another_module.py index d7fb5bc0..2769375c 100644 --- a/tests/data/main_package/another_path/another_module.py +++ b/tests/data/main_package/another_path/another_module.py @@ -8,5 +8,5 @@ class AnotherClass: pass -class YetAnotherClass: +class yetAnotherClass: def another_function(self) -> str: ... diff --git a/tests/data/various_modules_package/class_module.py b/tests/data/various_modules_package/class_module.py index 06a84ad5..f4fe3650 100644 --- a/tests/data/various_modules_package/class_module.py +++ b/tests/data/various_modules_package/class_module.py @@ -1,4 +1,4 @@ -from tests.data.main_package.another_path.another_module import YetAnotherClass +from tests.data.main_package.another_path.another_module import yetAnotherClass class ClassModuleEmptyClassA: @@ -11,7 +11,7 @@ def __init__(self, a: int, b: ClassModuleEmptyClassA | None): ... def f(self): ... -class ClassModuleClassC(ClassModuleEmptyClassA, ClassModuleClassB, YetAnotherClass): +class ClassModuleClassC(ClassModuleEmptyClassA, ClassModuleClassB, yetAnotherClass): attr_1: int attr_2: int diff --git a/tests/safeds_stubgen/__snapshots__/test_main.ambr b/tests/safeds_stubgen/__snapshots__/test_main.ambr index db3a3a3c..644f4266 100644 --- a/tests/safeds_stubgen/__snapshots__/test_main.ambr +++ b/tests/safeds_stubgen/__snapshots__/test_main.ambr @@ -132,12 +132,12 @@ 'description': '', 'full_docstring': '', }), - 'id': 'main_package/another_path/another_module/YetAnotherClass', + 'id': 'main_package/another_path/another_module/yetAnotherClass', 'is_public': True, 'methods': list([ - 'main_package/another_path/another_module/YetAnotherClass/another_function', + 'main_package/another_path/another_module/yetAnotherClass/another_function', ]), - 'name': 'YetAnotherClass', + 'name': 'yetAnotherClass', 'reexported_by': list([ ]), 'superclasses': list([ @@ -335,19 +335,19 @@ 'description': '', 'full_docstring': '', }), - 'id': 'main_package/another_path/another_module/YetAnotherClass/another_function', + 'id': 'main_package/another_path/another_module/yetAnotherClass/another_function', 'is_class_method': False, 'is_property': False, 'is_public': True, 'is_static': False, 'name': 'another_function', 'parameters': list([ - 'main_package/another_path/another_module/YetAnotherClass/another_function/self', + 'main_package/another_path/another_module/yetAnotherClass/another_function/self', ]), 'reexported_by': list([ ]), 'results': list([ - 'main_package/another_path/another_module/YetAnotherClass/another_function/result_1', + 'main_package/another_path/another_module/yetAnotherClass/another_function/result_1', ]), }), dict({ @@ -538,7 +538,7 @@ dict({ 'classes': list([ 'main_package/another_path/another_module/AnotherClass', - 'main_package/another_path/another_module/YetAnotherClass', + 'main_package/another_path/another_module/yetAnotherClass', ]), 'docstring': ''' Another Module Docstring. @@ -606,7 +606,7 @@ 'description': '', 'type': '', }), - 'id': 'main_package/another_path/another_module/YetAnotherClass/another_function/self', + 'id': 'main_package/another_path/another_module/yetAnotherClass/another_function/self', 'is_optional': False, 'name': 'self', 'type': None, @@ -791,7 +791,7 @@ 'description': '', 'type': '', }), - 'id': 'main_package/another_path/another_module/YetAnotherClass/another_function/result_1', + 'id': 'main_package/another_path/another_module/yetAnotherClass/another_function/result_1', 'name': 'result_1', 'type': dict({ 'kind': 'NamedType', 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 971a1395..24ef865a 100644 --- a/tests/safeds_stubgen/api_analyzer/__snapshots__/test__get_api.ambr +++ b/tests/safeds_stubgen/api_analyzer/__snapshots__/test__get_api.ambr @@ -2025,7 +2025,7 @@ 'superclasses': list([ 'tests.data.various_modules_package.class_module.ClassModuleEmptyClassA', 'tests.data.various_modules_package.class_module.ClassModuleClassB', - 'tests.data.main_package.another_path.another_module.YetAnotherClass', + 'tests.data.main_package.another_path.another_module.yetAnotherClass', ]), 'type_parameters': list([ ]), @@ -6340,7 +6340,7 @@ 'qualified_imports': list([ dict({ 'alias': None, - 'qualified_name': 'tests.data.main_package.another_path.another_module.YetAnotherClass', + 'qualified_name': 'tests.data.main_package.another_path.another_module.yetAnotherClass', }), ]), 'wildcard_imports': list([ diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub index 5b8c0ffc..c4059ac1 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub @@ -1,7 +1,7 @@ @PythonModule("various_modules_package.class_module") package variousModulesPackage.classModule -from tests.data.mainPackage.anotherPath.anotherModule import YetAnotherClass +from tests.data.mainPackage.anotherPath.anotherModule import yetAnotherClass class ClassModuleEmptyClassA() @@ -15,7 +15,7 @@ class ClassModuleClassB( } // TODO Safe-DS does not support multiple inheritance. -class ClassModuleClassC() sub ClassModuleEmptyClassA, ClassModuleClassB, YetAnotherClass { +class ClassModuleClassC() sub ClassModuleEmptyClassA, ClassModuleClassB, yetAnotherClass { @PythonName("attr_1") static attr attr1: Int @PythonName("attr_2") diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub index def2cbef..5bed1e8b 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub @@ -2,3 +2,5 @@ package tests.data.mainPackage.anotherPath.anotherModule class AnotherClass + +class yetAnotherClass From 9cf0eb03fad8e21776aba73ab631b07364d2768c Mon Sep 17 00:00:00 2001 From: Arsam Date: Thu, 29 Feb 2024 17:01:27 +0100 Subject: [PATCH 10/25] fixed tests --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 2 +- .../test_file_creation_limited_stubs_outside_package.sdsstub | 3 ++- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index e2758d0a..d57954c7 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -130,7 +130,7 @@ def _create_outside_package_class_text(class_name: str, convert_identifiers: boo # to camel case camel_case_name = class_name if convert_identifiers: - camel_case_name = _convert_snake_to_camel_case(class_name) + camel_case_name = _convert_snake_to_camel_case(class_name, is_class_name=True) # add name annotation class_annotation = "" diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub index 5bed1e8b..e736c1fd 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_file_creation_limited_stubs_outside_package.sdsstub @@ -3,4 +3,5 @@ package tests.data.mainPackage.anotherPath.anotherModule class AnotherClass -class yetAnotherClass +@PythonName("yetAnotherClass") +class YetAnotherClass diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 42ef4eea..00660350 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -69,6 +69,8 @@ def test_file_creation() -> None: def test_file_creation_limited_stubs_outside_package(snapshot_sds_stub: SnapshotAssertion) -> None: + # Somehow the stubs get overwritten by other tests, therefore we have to call the function before asserting + generate_stubs(api, _out_dir, convert_identifiers=True) path = Path(_out_dir / "tests/data/main_package/another_path/another_module/another_module.sdsstub") assert path.is_file() From b6950d6eafe049ae01157ddc0cbe3d9fc722507b Mon Sep 17 00:00:00 2001 From: Arsam Date: Fri, 1 Mar 2024 01:49:57 +0100 Subject: [PATCH 11/25] fixed a bug which occurred with the main merge --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 55efb61f..ec185a47 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -414,8 +414,8 @@ def _create_function_string(self, function: Function, indentations: str = "", is if function.type_var_types: type_var_names = [] for type_var in function.type_var_types: - type_var_name = self._convert_snake_to_camel_case(type_var.name) - type_var_name = self._replace_if_safeds_keyword(type_var_name) + type_var_name = _convert_snake_to_camel_case(type_var.name) + type_var_name = _replace_if_safeds_keyword(type_var_name) # We don't have to display generic types in methods if they were already displayed in the class if not is_method or (is_method and type_var_name not in self.class_generics): @@ -742,8 +742,8 @@ def _create_type_string(self, type_data: dict | None) -> str: types.append(f"{literal_type}") return f"literal<{', '.join(types)}>" elif kind == "TypeVarType": - name = self._convert_snake_to_camel_case(type_data["name"]) - return self._replace_if_safeds_keyword(name) + name = _convert_snake_to_camel_case(type_data["name"]) + return _replace_if_safeds_keyword(name) raise ValueError(f"Unexpected type: {kind}") # pragma: no cover From 0e98955b5e3fe714968a86dc3209bebeb288b7a5 Mon Sep 17 00:00:00 2001 From: Arsam Date: Sat, 2 Mar 2024 20:41:57 +0100 Subject: [PATCH 12/25] Changed the way stub params are names (param1, param2, ...) and renamed the function _convert_snake_to_camel_case to _convert_name_to_convention --- .../stubs_generator/_generate_stubs.py | 46 +++++++++---------- .../test_class_attribute_creation.sdsstub | 2 +- .../test_function_creation.sdsstub | 4 +- .../test_type_inference.sdsstub | 2 +- .../stubs_generator/test_generate_stubs.py | 32 +++++++------ 5 files changed, 42 insertions(+), 44 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index ec185a47..53cef2aa 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -1,8 +1,7 @@ from __future__ import annotations -import string from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Literal from safeds_stubgen.api_analyzer import ( API, @@ -113,7 +112,7 @@ def _create_outside_package_class( python_module_path = ".".join(path_parts) module_path_camel_case = python_module_path if convert_identifiers: - module_path_camel_case = _convert_snake_to_camel_case(python_module_path) + module_path_camel_case = _convert_name_to_convention(python_module_path, "Safe-DS") module_name_info = "" if python_module_path != module_path_camel_case: module_text += f'@PythonModule("{python_module_path}")\n' @@ -130,7 +129,7 @@ def _create_outside_package_class_text(class_name: str, convert_identifiers: boo # to camel case camel_case_name = class_name if convert_identifiers: - camel_case_name = _convert_snake_to_camel_case(class_name, is_class_name=True) + camel_case_name = _convert_name_to_convention(class_name, "Safe-DS", is_class_name=True) # add name annotation class_annotation = "" @@ -167,7 +166,7 @@ def _create_module_string(self, module: Module) -> str: package_info = module.id.replace("/", ".") package_info_camel_case = package_info if self.convert_identifiers: - package_info_camel_case = _convert_snake_to_camel_case(package_info) + package_info_camel_case = _convert_name_to_convention(package_info, "Safe-DS") module_name_info = "" module_text = "" if package_info != package_info_camel_case: @@ -203,11 +202,11 @@ def _create_imports_string(self) -> str: import_parts = import_.split(".") from_ = ".".join(import_parts[0:-1]) - from_ = _convert_snake_to_camel_case(from_) + from_ = _convert_name_to_convention(from_, "Safe-DS") from_ = _replace_if_safeds_keyword(from_) name = import_parts[-1] - name = _convert_snake_to_camel_case(name) + name = _convert_name_to_convention(name, "Safe-DS") name = _replace_if_safeds_keyword(name) import_strings.append(f"from {from_} import {name}") @@ -269,7 +268,7 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st # Convert name to camelCase and check for keywords variance_name_camel_case = variance.name if self.convert_identifiers: - variance_name_camel_case = _convert_snake_to_camel_case(variance.name) + variance_name_camel_case = _convert_name_to_convention(variance.name, "Safe-DS") variance_name_camel_case = _replace_if_safeds_keyword(variance_name_camel_case) variance_item = f"{variance_direction}{variance_name_camel_case}" @@ -285,7 +284,7 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st python_name_info = "" class_name_camel_case = class_name if self.convert_identifiers: - class_name_camel_case = _convert_snake_to_camel_case(class_name, is_class_name=True) + class_name_camel_case = _convert_name_to_convention(class_name, "Safe-DS", is_class_name=True) if class_name_camel_case != class_name: python_name_info = f"{class_indentation}{_create_name_annotation(class_name)}\n" class_name_camel_case = _replace_if_safeds_keyword(class_name_camel_case) @@ -361,7 +360,7 @@ def _create_class_attribute_string(self, attributes: list[Attribute], inner_inde attr_name = attribute.name attr_name_camel_case = attr_name if self.convert_identifiers: - attr_name_camel_case = _convert_snake_to_camel_case(attr_name) + attr_name_camel_case = _convert_name_to_convention(attr_name, "Safe-DS") attr_name_annotation = "" if attr_name_camel_case != attr_name: attr_name_annotation = f"{_create_name_annotation(attr_name)}\n{inner_indentations}" @@ -414,7 +413,7 @@ def _create_function_string(self, function: Function, indentations: str = "", is if function.type_var_types: type_var_names = [] for type_var in function.type_var_types: - type_var_name = _convert_snake_to_camel_case(type_var.name) + type_var_name = _convert_name_to_convention(type_var.name, "Safe-DS") type_var_name = _replace_if_safeds_keyword(type_var_name) # We don't have to display generic types in methods if they were already displayed in the class @@ -431,7 +430,7 @@ def _create_function_string(self, function: Function, indentations: str = "", is name = function.name camel_case_name = name if self.convert_identifiers: - camel_case_name = _convert_snake_to_camel_case(name) + camel_case_name = _convert_name_to_convention(name, "Safe-DS") function_name_annotation = "" if camel_case_name != name: function_name_annotation = f"{indentations}{_create_name_annotation(name)}\n" @@ -458,7 +457,7 @@ def _create_property_function_string(self, function: Function, indentations: str name = function.name camel_case_name = name if self.convert_identifiers: - camel_case_name = _convert_snake_to_camel_case(name) + camel_case_name = _convert_name_to_convention(name, "Safe-DS") function_name_annotation = "" if camel_case_name != name: function_name_annotation = f"{_create_name_annotation(name)} " @@ -490,7 +489,7 @@ def _create_result_string(self, function_results: list[Result]) -> str: type_string = f": {ret_type}" if ret_type else "" result_name = result.name if self.convert_identifiers: - result_name = _convert_snake_to_camel_case(result.name) + result_name = _convert_name_to_convention(result.name, "Safe-DS") result_name = _replace_if_safeds_keyword(result_name) if type_string: results.append( @@ -570,7 +569,7 @@ def _create_parameter_string( name = parameter.name camel_case_name = name if self.convert_identifiers: - camel_case_name = _convert_snake_to_camel_case(name) + camel_case_name = _convert_name_to_convention(name, "Safe-DS") name_annotation = "" if camel_case_name != name: # Memorize the changed name for the @PythonName() annotation @@ -606,7 +605,7 @@ def _create_enum_string(self, enum_data: Enum) -> str: # Convert snake_case names to camelCase camel_case_name = name if self.convert_identifiers: - camel_case_name = _convert_snake_to_camel_case(name) + camel_case_name = _convert_name_to_convention(name, "Safe-DS") annotation = "" if camel_case_name != name: annotation = f"{_create_name_annotation(name)} " @@ -742,7 +741,7 @@ def _create_type_string(self, type_data: dict | None) -> str: types.append(f"{literal_type}") return f"literal<{', '.join(types)}>" elif kind == "TypeVarType": - name = _convert_snake_to_camel_case(type_data["name"]) + name = _convert_name_to_convention(type_data["name"], "Safe-DS") return _replace_if_safeds_keyword(name) raise ValueError(f"Unexpected type: {kind}") # pragma: no cover @@ -774,7 +773,7 @@ def _add_to_imports(self, qname: str) -> None: if class_.endswith(qname_path): qname = class_.replace("/", ".") if self.convert_identifiers: - qname = _convert_snake_to_camel_case(qname) + qname = _convert_name_to_convention(qname, "Safe-DS") in_package = True break @@ -817,11 +816,8 @@ def _create_todo_msg(self, indentations: str) -> str: def _callable_type_name_generator() -> Generator: """Generate a name for callable type parameters starting from 'a' until 'zz'.""" while True: - for x in range(1, 27): - yield string.ascii_lowercase[x - 1] - for x in range(1, 27): # pragma: no cover - for y in range(1, 27): - yield string.ascii_lowercase[x - 1] + string.ascii_lowercase[y - 1] + for x in range(1, 1000): + yield f"param{x}" def _create_name_annotation(name: str) -> str: @@ -867,8 +863,8 @@ def _replace_if_safeds_keyword(keyword: str) -> str: return keyword -def _convert_snake_to_camel_case(name: str, is_class_name: bool = False) -> str: - if name == "_": +def _convert_name_to_convention(name: str, convention: Literal["Safe-DS", "Python"], is_class_name: bool = False) -> str: + if name == "_" or convention == "Python": return name # Count underscores in front and behind the name diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub index 3a0707e6..f761891e 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub @@ -94,7 +94,7 @@ class AttributesClassB() { @PythonName("attr_type_from_outside_package") static attr attrTypeFromOutsidePackage: AnotherClass @PythonName("attr_default_value_from_outside_package") - static attr attrDefaultValueFromOutsidePackage: () -> a: AnotherClass + static attr attrDefaultValueFromOutsidePackage: () -> param1: AnotherClass @PythonName("init_attr") attr initAttr: Boolean diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub index bf27c090..8a41218c 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub @@ -232,8 +232,8 @@ fun anyResults() -> result1: Any @Pure @PythonName("callable_type") fun callableType( - param: (a: String) -> (b: Int, c: String) -) -> result1: (a: Int, b: Int) -> c: Int + param: (param1: String) -> (param2: Int, param3: String) +) -> result1: (param1: Int, param2: Int) -> param3: Int // TODO Result type information missing. // TODO Some parameter have no type information. diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_type_inference.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_type_inference.sdsstub index 22573858..03b492be 100644 --- a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_type_inference.sdsstub +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_type_inference.sdsstub @@ -21,7 +21,7 @@ class InferMyTypes( @PythonName("infer_none") static attr inferNone: Nothing? @PythonName("infer_obj") - static attr inferObj: () -> a: InferMe + static attr inferObj: () -> param1: InferMe // TODO Attribute has no type information. @PythonName("init_infer") attr initInfer diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 404e6a54..ff25864a 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -8,7 +8,7 @@ from safeds_stubgen.stubs_generator import generate_stubs # noinspection PyProtectedMember -from safeds_stubgen.stubs_generator._generate_stubs import _convert_snake_to_camel_case +from safeds_stubgen.stubs_generator._generate_stubs import _convert_name_to_convention if TYPE_CHECKING: from syrupy import SnapshotAssertion @@ -125,20 +125,22 @@ def test_alias_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> @pytest.mark.parametrize( - ("name", "expected_result", "is_class_name"), + ("name", "expected_result", "convention", "is_class_name"), [ - ("", "", False), - ("_", "_", False), - ("__get_function_name__", "getFunctionName", False), - ("__get_function_name", "getFunctionName", False), - ("get_function_name__", "getFunctionName", False), - ("__getFunction_name__", "getFunctionName", False), - ("__get__function___name__", "getFunctionName", False), - ("__get_funCtion_NamE__", "getFunCtionNamE", False), - ("getFunctionName", "getFunctionName", False), - ("a_a_A_aAAaA_1_1_2_aAa", "aAAAAAaA112AAa", False), - ("some_class_name", "SomeClassName", True), + ("", "", "Safe-DS", False), + ("_", "_", "Safe-DS", False), + ("__get_function_name__", "getFunctionName", "Safe-DS", False), + ("__get_function_name", "getFunctionName", "Safe-DS", False), + ("get_function_name__", "getFunctionName", "Safe-DS", False), + ("__getFunction_name__", "getFunctionName", "Safe-DS", False), + ("__get__function___name__", "getFunctionName", "Safe-DS", False), + ("__get_funCtion_NamE__", "getFunCtionNamE", "Safe-DS", False), + ("getFunctionName", "getFunctionName", "Safe-DS", False), + ("a_a_A_aAAaA_1_1_2_aAa", "aAAAAAaA112AAa", "Safe-DS", False), + ("some_class_name", "SomeClassName", "Safe-DS", True), + ("some_class_name", "some_class_name", "Python", True), + ("__get_function_name__", "__get_function_name__", "Python", False), ], ) -def test_convert_snake_to_camel_case(name: str, expected_result: str, is_class_name: bool) -> None: - assert _convert_snake_to_camel_case(name, is_class_name=is_class_name) == expected_result +def test_convert_name_to_convention(name: str, expected_result: str, convention, is_class_name: bool) -> None: + assert _convert_name_to_convention(name=name, convention=convention, is_class_name=is_class_name) == expected_result From 6d1df6049b04b013975bbee4bf7a9d76291c35c1 Mon Sep 17 00:00:00 2001 From: Arsam Date: Sat, 2 Mar 2024 20:48:33 +0100 Subject: [PATCH 13/25] linter fix --- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index ff25864a..bffd9635 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -1,7 +1,7 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Literal import pytest from safeds_stubgen.api_analyzer import get_api @@ -142,5 +142,7 @@ def test_alias_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> ("__get_function_name__", "__get_function_name__", "Python", False), ], ) -def test_convert_name_to_convention(name: str, expected_result: str, convention, is_class_name: bool) -> None: +def test_convert_name_to_convention( + name: str, expected_result: str, convention: Literal["Safe-DS", "Python"], is_class_name: bool +) -> None: assert _convert_name_to_convention(name=name, convention=convention, is_class_name=is_class_name) == expected_result From bea75fe8ab0a605342e770ae0ec6d02fed5473dd Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Sat, 2 Mar 2024 19:50:08 +0000 Subject: [PATCH 14/25] style: apply automated linter fixes --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 4 +++- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 53cef2aa..47a9ad69 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -863,7 +863,9 @@ def _replace_if_safeds_keyword(keyword: str) -> str: return keyword -def _convert_name_to_convention(name: str, convention: Literal["Safe-DS", "Python"], is_class_name: bool = False) -> str: +def _convert_name_to_convention( + name: str, convention: Literal["Safe-DS", "Python"], is_class_name: bool = False, +) -> str: if name == "_" or convention == "Python": return name diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index bffd9635..7ec26c09 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -143,6 +143,6 @@ def test_alias_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> ], ) def test_convert_name_to_convention( - name: str, expected_result: str, convention: Literal["Safe-DS", "Python"], is_class_name: bool + name: str, expected_result: str, convention: Literal["Safe-DS", "Python"], is_class_name: bool, ) -> None: assert _convert_name_to_convention(name=name, convention=convention, is_class_name=is_class_name) == expected_result From 2fdd2251b1c2673e0ceba8a9a217eee37ed794fd Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Sat, 2 Mar 2024 19:51:44 +0000 Subject: [PATCH 15/25] style: apply automated linter fixes --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 4 +++- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 47a9ad69..bdbe43a7 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -864,7 +864,9 @@ def _replace_if_safeds_keyword(keyword: str) -> str: def _convert_name_to_convention( - name: str, convention: Literal["Safe-DS", "Python"], is_class_name: bool = False, + name: str, + convention: Literal["Safe-DS", "Python"], + is_class_name: bool = False, ) -> str: if name == "_" or convention == "Python": return name diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 7ec26c09..4a05fd82 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -143,6 +143,9 @@ def test_alias_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> ], ) def test_convert_name_to_convention( - name: str, expected_result: str, convention: Literal["Safe-DS", "Python"], is_class_name: bool, + name: str, + expected_result: str, + convention: Literal["Safe-DS", "Python"], + is_class_name: bool, ) -> None: assert _convert_name_to_convention(name=name, convention=convention, is_class_name=is_class_name) == expected_result From 98afcc227de3916db5b1b67410085af4acee679b Mon Sep 17 00:00:00 2001 From: Arsam Date: Sat, 2 Mar 2024 21:28:06 +0100 Subject: [PATCH 16/25] split the stubs_generator function into three and refactored tests --- .../stubs_generator/_generate_stubs.py | 30 ++++-- ...st_stub_creation[abstract_module].sdsstub} | 0 ..._stub_creation[aliasing_module_1].sdsstub} | 0 ..._stub_creation[aliasing_module_2].sdsstub} | 0 ..._stub_creation[aliasing_module_3].sdsstub} | 0 ...t_stub_creation[attribute_module].sdsstub} | 0 ... test_stub_creation[class_module].sdsstub} | 0 ...> test_stub_creation[enum_module].sdsstub} | 0 ...st_stub_creation[function_module].sdsstub} | 0 ...test_stub_creation[import_module].sdsstub} | 0 ...stub_creation[infer_types_module].sdsstub} | 0 ...st_stub_creation[type_var_module].sdsstub} | 0 ...st_stub_creation[variance_module].sdsstub} | 0 .../stubs_generator/test_generate_stubs.py | 97 +++++++------------ 14 files changed, 59 insertions(+), 68 deletions(-) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_abstract_creation.sdsstub => test_stub_creation[abstract_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_alias_creation[aliasing_module_1].sdsstub => test_stub_creation[aliasing_module_1].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_alias_creation[aliasing_module_2].sdsstub => test_stub_creation[aliasing_module_2].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_alias_creation[aliasing_module_3].sdsstub => test_stub_creation[aliasing_module_3].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_class_attribute_creation.sdsstub => test_stub_creation[attribute_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_class_creation.sdsstub => test_stub_creation[class_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_enum_creation.sdsstub => test_stub_creation[enum_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_function_creation.sdsstub => test_stub_creation[function_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_import_creation.sdsstub => test_stub_creation[import_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_type_inference.sdsstub => test_stub_creation[infer_types_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_type_var_creation.sdsstub => test_stub_creation[type_var_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_variance_creation.sdsstub => test_stub_creation[variance_module].sdsstub} (100%) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 53cef2aa..35a41023 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -37,15 +37,17 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: Set this True if the identifiers should be converted to Safe-DS standard (UpperCamelCase for classes and camelCase for everything else). """ - modules = api.modules.values() - - Path(out_path / api.package).mkdir(parents=True, exist_ok=True) stubs_generator = StubsStringGenerator(api, convert_identifiers) + stubs_data = _generate_stubs_data(api, out_path, stubs_generator) + _generate_stubs_files(stubs_data, api, out_path, stubs_generator, convert_identifiers) - for module in modules: - module_name = module.name - if module_name == "__init__": +def _generate_stubs_data( + api: API, out_path: Path, stubs_generator: StubsStringGenerator +) -> list[tuple[Path, str, str]]: + stubs_data: list[tuple[Path, str, str]] = [] + for module in api.modules.values(): + if module.name == "__init__": continue module_text = stubs_generator(module) @@ -58,8 +60,22 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: if len(splitted_text) <= 2 or (len(splitted_text) == 3 and splitted_text[1].startswith("package ")): continue - # Create module dir module_dir = Path(out_path / module.id) + stubs_data.append((module_dir, module.name, module_text)) + return stubs_data + + +def _generate_stubs_files( + stubs_data: list[tuple[Path, str, str]], + api: API, + out_path: Path, + stubs_generator: StubsStringGenerator, + convert_identifiers: bool +) -> None: + Path(out_path / api.package).mkdir(parents=True, exist_ok=True) + + for module_dir, module_name, module_text in stubs_data: + # Create module dir module_dir.mkdir(parents=True, exist_ok=True) # Create and open module file diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_abstract_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[abstract_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_abstract_creation.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[abstract_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_alias_creation[aliasing_module_1].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_1].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_alias_creation[aliasing_module_1].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_1].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_alias_creation[aliasing_module_2].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_2].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_alias_creation[aliasing_module_2].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_2].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_alias_creation[aliasing_module_3].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_3].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_alias_creation[aliasing_module_3].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_3].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[attribute_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_attribute_creation.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[attribute_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[class_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_class_creation.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[class_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_enum_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[enum_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_enum_creation.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[enum_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[function_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_function_creation.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[function_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_import_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[import_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_import_creation.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[import_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_type_inference.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[infer_types_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_type_inference.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[infer_types_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_type_var_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[type_var_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_type_var_creation.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[type_var_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_variance_creation.sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[variance_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_variance_creation.sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[variance_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index bffd9635..15849e1e 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -8,7 +8,11 @@ from safeds_stubgen.stubs_generator import generate_stubs # noinspection PyProtectedMember -from safeds_stubgen.stubs_generator._generate_stubs import _convert_name_to_convention +from safeds_stubgen.stubs_generator._generate_stubs import ( + StubsStringGenerator, + _convert_name_to_convention, + _generate_stubs_data, +) if TYPE_CHECKING: from syrupy import SnapshotAssertion @@ -21,10 +25,16 @@ _out_dir_stubs = Path(_out_dir / _test_package_name) api = get_api(_test_package_name, _test_package_dir, is_test_run=True) -generate_stubs(api, _out_dir, convert_identifiers=True) +stubs_data = _generate_stubs_data(api, _out_dir, StubsStringGenerator(api, convert_identifiers=True)) + + +def test_file_creation() -> None: + _assert_file_creation_recursive( + python_path=Path(_test_package_dir / "file_creation"), + stub_path=Path(_out_dir_stubs / "file_creation"), + ) -# Utilites def _assert_file_creation_recursive(python_path: Path, stub_path: Path) -> None: assert python_path.is_dir() assert stub_path.is_dir() @@ -54,20 +64,6 @@ def _assert_file_creation_recursive(python_path: Path, stub_path: Path) -> None: _assert_file_creation_recursive(py_item, stub_item) -def assert_stubs_snapshot(filename: str, snapshot_sds_stub: SnapshotAssertion) -> None: - stubs_file = Path(_out_dir_stubs / filename / f"{filename}.sdsstub") - with stubs_file.open("r") as f: - assert f.read() == snapshot_sds_stub - - -# ############################## Tests ############################## # -def test_file_creation() -> None: - _assert_file_creation_recursive( - python_path=Path(_test_package_dir / "file_creation"), - stub_path=Path(_out_dir_stubs / "file_creation"), - ) - - def test_file_creation_limited_stubs_outside_package(snapshot_sds_stub: SnapshotAssertion) -> None: # Somehow the stubs get overwritten by other tests, therefore we have to call the function before asserting generate_stubs(api, _out_dir, convert_identifiers=True) @@ -78,50 +74,29 @@ def test_file_creation_limited_stubs_outside_package(snapshot_sds_stub: Snapshot assert f.read() == snapshot_sds_stub -def test_class_creation(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("class_module", snapshot_sds_stub) - - -def test_class_attribute_creation(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("attribute_module", snapshot_sds_stub) - - -def test_function_creation(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("function_module", snapshot_sds_stub) - - -def test_enum_creation(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("enum_module", snapshot_sds_stub) - - -def test_import_creation(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("import_module", snapshot_sds_stub) - - -def test_type_inference(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("infer_types_module", snapshot_sds_stub) - - -def test_variance_creation(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("variance_module", snapshot_sds_stub) - - -def test_abstract_creation(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("abstract_module", snapshot_sds_stub) - - -def test_type_var_creation(snapshot_sds_stub: SnapshotAssertion) -> None: - assert_stubs_snapshot("type_var_module", snapshot_sds_stub) - - -@pytest.mark.parametrize("file_name", ["aliasing_module_1", "aliasing_module_2", "aliasing_module_3"]) -def test_alias_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> None: - file_data = "" - stubs_file = Path(_out_dir_stubs / "aliasing" / f"{file_name}" / f"{file_name}.sdsstub") - with stubs_file.open("r") as f: - file_data += f.read() - - assert file_data == snapshot_sds_stub +@pytest.mark.parametrize( + "file_name", + [ + "aliasing_module_1", + "aliasing_module_2", + "aliasing_module_3", + "type_var_module", + "abstract_module", + "variance_module", + "infer_types_module", + "import_module", + "enum_module", + "function_module", + "attribute_module", + "class_module", + ] +) +def test_stub_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> None: + for stub_data in stubs_data: + if stub_data[1] == file_name: + assert stub_data[2] == snapshot_sds_stub + return + raise AssertionError(f"Stub file not found for '{file_name}'.") @pytest.mark.parametrize( From 2f45e796369d451f75d9d2c6236668bd97e4e93d Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Sat, 2 Mar 2024 20:29:47 +0000 Subject: [PATCH 17/25] style: apply automated linter fixes --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 4 ++-- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 83e7be6c..4d7c5589 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -43,7 +43,7 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: def _generate_stubs_data( - api: API, out_path: Path, stubs_generator: StubsStringGenerator + api: API, out_path: Path, stubs_generator: StubsStringGenerator, ) -> list[tuple[Path, str, str]]: stubs_data: list[tuple[Path, str, str]] = [] for module in api.modules.values(): @@ -70,7 +70,7 @@ def _generate_stubs_files( api: API, out_path: Path, stubs_generator: StubsStringGenerator, - convert_identifiers: bool + convert_identifiers: bool, ) -> None: Path(out_path / api.package).mkdir(parents=True, exist_ok=True) diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index ad2d09ac..464db4cb 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -89,7 +89,7 @@ def test_file_creation_limited_stubs_outside_package(snapshot_sds_stub: Snapshot "function_module", "attribute_module", "class_module", - ] + ], ) def test_stub_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> None: for stub_data in stubs_data: From 37558c12841a6e6d114d6f71f8e915575f02f089 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Sat, 2 Mar 2024 20:31:19 +0000 Subject: [PATCH 18/25] style: apply automated linter fixes --- src/safeds_stubgen/stubs_generator/_generate_stubs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 4d7c5589..4bbc8246 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -43,7 +43,9 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: def _generate_stubs_data( - api: API, out_path: Path, stubs_generator: StubsStringGenerator, + api: API, + out_path: Path, + stubs_generator: StubsStringGenerator, ) -> list[tuple[Path, str, str]]: stubs_data: list[tuple[Path, str, str]] = [] for module in api.modules.values(): From e048738e90fd86332a880aff32a9596af25bba1e Mon Sep 17 00:00:00 2001 From: Arsam Date: Sat, 2 Mar 2024 21:35:05 +0100 Subject: [PATCH 19/25] test fix --- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index ad2d09ac..66f48551 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -12,6 +12,7 @@ StubsStringGenerator, _convert_name_to_convention, _generate_stubs_data, + _generate_stubs_files, ) if TYPE_CHECKING: @@ -25,10 +26,12 @@ _out_dir_stubs = Path(_out_dir / _test_package_name) api = get_api(_test_package_name, _test_package_dir, is_test_run=True) -stubs_data = _generate_stubs_data(api, _out_dir, StubsStringGenerator(api, convert_identifiers=True)) +stubs_generator = StubsStringGenerator(api, convert_identifiers=True) +stubs_data = _generate_stubs_data(api, _out_dir, stubs_generator) def test_file_creation() -> None: + _generate_stubs_files(stubs_data, api, _out_dir, stubs_generator, convert_identifiers=True) _assert_file_creation_recursive( python_path=Path(_test_package_dir / "file_creation"), stub_path=Path(_out_dir_stubs / "file_creation"), From 454d317f78ddc43a2dab63f9c743da961b06875d Mon Sep 17 00:00:00 2001 From: Arsam Date: Sat, 2 Mar 2024 22:24:38 +0100 Subject: [PATCH 20/25] Changed logic of stubs generator tests, now every file is checked --- ...tion.test_stub_creation[_module_3].sdsstub | 4 ++ ...tion.test_stub_creation[_module_6].sdsstub | 7 +++ ..._stub_creation[_reexport_module_1].sdsstub | 4 ++ ..._stub_creation[_reexport_module_2].sdsstub | 9 +++ ..._stub_creation[_reexport_module_4].sdsstub | 4 ++ ...st_stub_creation[abstract_module].sdsstub} | 0 ..._stub_creation[aliasing_module_1].sdsstub} | 0 ..._stub_creation[aliasing_module_2].sdsstub} | 0 ..._stub_creation[aliasing_module_3].sdsstub} | 0 ...test_stub_creation[another_module].sdsstub | 4 ++ ...t_stub_creation[attribute_module].sdsstub} | 0 ....test_stub_creation[class_module].sdsstub} | 0 ...st_stub_creation[docstring_module].sdsstub | 58 +++++++++++++++++++ ...n.test_stub_creation[enum_module].sdsstub} | 0 ...st_stub_creation[function_module].sdsstub} | 0 ...test_stub_creation[import_module].sdsstub} | 0 ...stub_creation[infer_types_module].sdsstub} | 0 ...ation.test_stub_creation[module_1].sdsstub | 4 ++ ...ation.test_stub_creation[module_5].sdsstub | 4 ++ ...st_stub_creation[type_var_module].sdsstub} | 0 ...st_stub_creation[variance_module].sdsstub} | 0 .../stubs_generator/test_generate_stubs.py | 48 +++++++-------- 22 files changed, 123 insertions(+), 23 deletions(-) create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_module_3].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_module_6].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_1].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_2].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_4].sdsstub rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[abstract_module].sdsstub => TestStubFileGeneration.test_stub_creation[abstract_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[aliasing_module_1].sdsstub => TestStubFileGeneration.test_stub_creation[aliasing_module_1].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[aliasing_module_2].sdsstub => TestStubFileGeneration.test_stub_creation[aliasing_module_2].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[aliasing_module_3].sdsstub => TestStubFileGeneration.test_stub_creation[aliasing_module_3].sdsstub} (100%) create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[another_module].sdsstub rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[attribute_module].sdsstub => TestStubFileGeneration.test_stub_creation[attribute_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[class_module].sdsstub => TestStubFileGeneration.test_stub_creation[class_module].sdsstub} (100%) create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[docstring_module].sdsstub rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[enum_module].sdsstub => TestStubFileGeneration.test_stub_creation[enum_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[function_module].sdsstub => TestStubFileGeneration.test_stub_creation[function_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[import_module].sdsstub => TestStubFileGeneration.test_stub_creation[import_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[infer_types_module].sdsstub => TestStubFileGeneration.test_stub_creation[infer_types_module].sdsstub} (100%) create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[module_1].sdsstub create mode 100644 tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[module_5].sdsstub rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[type_var_module].sdsstub => TestStubFileGeneration.test_stub_creation[type_var_module].sdsstub} (100%) rename tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/{test_stub_creation[variance_module].sdsstub => TestStubFileGeneration.test_stub_creation[variance_module].sdsstub} (100%) diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_module_3].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_module_3].sdsstub new file mode 100644 index 00000000..13a5c6ae --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_module_3].sdsstub @@ -0,0 +1,4 @@ +@PythonModule("various_modules_package.file_creation._module_3") +package variousModulesPackage.fileCreation.Module3 + +class Reexported() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_module_6].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_module_6].sdsstub new file mode 100644 index 00000000..1a35cac7 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_module_6].sdsstub @@ -0,0 +1,7 @@ +@PythonModule("various_modules_package.file_creation._module_6") +package variousModulesPackage.fileCreation.Module6 + +// TODO Result type information missing. +@Pure +@PythonName("public_reexported") +fun publicReexported() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_1].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_1].sdsstub new file mode 100644 index 00000000..ae12122b --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_1].sdsstub @@ -0,0 +1,4 @@ +@PythonModule("various_modules_package._reexport_module_1") +package variousModulesPackage.ReexportModule1 + +class ReexportClass() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_2].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_2].sdsstub new file mode 100644 index 00000000..51c2cfb0 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_2].sdsstub @@ -0,0 +1,9 @@ +@PythonModule("various_modules_package._reexport_module_2") +package variousModulesPackage.ReexportModule2 + +// TODO Result type information missing. +@Pure +@PythonName("reexported_function_2") +fun reexportedFunction2() + +class AnotherReexportClass() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_4].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_4].sdsstub new file mode 100644 index 00000000..825344dd --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[_reexport_module_4].sdsstub @@ -0,0 +1,4 @@ +@PythonModule("various_modules_package._reexport_module_4") +package variousModulesPackage.ReexportModule4 + +class FourthReexportClass() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[abstract_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[abstract_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[abstract_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[abstract_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_1].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[aliasing_module_1].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_1].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[aliasing_module_1].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_2].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[aliasing_module_2].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_2].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[aliasing_module_2].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_3].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[aliasing_module_3].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[aliasing_module_3].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[aliasing_module_3].sdsstub 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 new file mode 100644 index 00000000..9427bd52 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[another_module].sdsstub @@ -0,0 +1,4 @@ +@PythonModule("various_modules_package.another_path.another_module") +package variousModulesPackage.anotherPath.anotherModule + +class AnotherClass() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[attribute_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[attribute_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[attribute_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[attribute_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[class_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[class_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[class_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[class_module].sdsstub 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 new file mode 100644 index 00000000..85efda92 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[docstring_module].sdsstub @@ -0,0 +1,58 @@ +@PythonModule("various_modules_package.docstring_module") +package variousModulesPackage.docstringModule + +class EpydocDocstringClass( + @PythonName("param_1") param1: String +) { + @PythonName("attr_1") + static attr attr1: String + + @Pure + @PythonName("epydoc_docstring_func") + fun epydocDocstringFunc( + x: Int, + y: Int + ) -> result1: Boolean +} + +class RestDocstringClass( + @PythonName("param_1") param1: String +) { + @PythonName("attr_1") + static attr attr1: String + + @Pure + @PythonName("rest_docstring_func") + fun restDocstringFunc( + x: Int, + y: Int + ) -> result1: Boolean +} + +class NumpyDocstringClass( + @PythonName("param_1") param1: String +) { + @PythonName("attr_1") + static attr attr1: String + + @Pure + @PythonName("numpy_docstring_func") + fun numpyDocstringFunc( + x: Int, + y: Int + ) -> result1: Boolean +} + +class GoogleDocstringClass( + @PythonName("param_1") param1: String +) { + @PythonName("attr_1") + static attr attr1: String + + @Pure + @PythonName("google_docstring_func") + fun googleDocstringFunc( + x: Int, + y: Int + ) -> result1: Boolean +} diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[enum_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[enum_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[enum_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[enum_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[function_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[function_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[function_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[function_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[import_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[import_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[import_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[import_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/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 similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[infer_types_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[infer_types_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[module_1].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[module_1].sdsstub new file mode 100644 index 00000000..fae86c54 --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[module_1].sdsstub @@ -0,0 +1,4 @@ +@PythonModule("various_modules_package.file_creation.module_1") +package variousModulesPackage.fileCreation.module1 + +class C() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[module_5].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[module_5].sdsstub new file mode 100644 index 00000000..7e20559d --- /dev/null +++ b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[module_5].sdsstub @@ -0,0 +1,4 @@ +@PythonModule("various_modules_package.file_creation.package_1.module_5") +package variousModulesPackage.fileCreation.package1.module5 + +class C() diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[type_var_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[type_var_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[type_var_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[type_var_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[variance_module].sdsstub b/tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[variance_module].sdsstub similarity index 100% rename from tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/test_stub_creation[variance_module].sdsstub rename to tests/safeds_stubgen/stubs_generator/__snapshots__/test_generate_stubs/TestStubFileGeneration.test_stub_creation[variance_module].sdsstub diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index e082fbdb..05e80c75 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -1,7 +1,7 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING, Literal +from typing import TYPE_CHECKING, Literal, Generator import pytest from safeds_stubgen.api_analyzer import get_api @@ -77,29 +77,31 @@ def test_file_creation_limited_stubs_outside_package(snapshot_sds_stub: Snapshot assert f.read() == snapshot_sds_stub -@pytest.mark.parametrize( - "file_name", - [ - "aliasing_module_1", - "aliasing_module_2", - "aliasing_module_3", - "type_var_module", - "abstract_module", - "variance_module", - "infer_types_module", - "import_module", - "enum_module", - "function_module", - "attribute_module", - "class_module", - ], -) -def test_stub_creation(file_name: str, snapshot_sds_stub: SnapshotAssertion) -> None: - for stub_data in stubs_data: - if stub_data[1] == file_name: - assert stub_data[2] == snapshot_sds_stub +def _python_files() -> Generator: + return Path(_test_package_dir).rglob(pattern="*.py") + + +def _python_file_ids() -> Generator: + files = Path(_test_package_dir).rglob(pattern="*.py") + for file in files: + yield file.parts[-1].split(".py")[0] + + +@pytest.mark.parametrize("python_file", _python_files(), ids=_python_file_ids()) +class TestStubFileGeneration: + def test_stub_creation(self, python_file: Path, snapshot_sds_stub: SnapshotAssertion) -> None: + file_name = python_file.parts[-1].split(".py")[0] + + for stub_data in stubs_data: + if stub_data[1] == file_name: + assert stub_data[2] == snapshot_sds_stub + return + + # For these files stubs won't get created, because they are either empty of private. + if file_name in {"__init__", "_reexport_module_3", "_module_2", "_module_4"}: return - raise AssertionError(f"Stub file not found for '{file_name}'.") + + raise AssertionError(f"Stub file not found for '{file_name}'.") @pytest.mark.parametrize( From 86201e1899297ce3c78b6351dad1e85e4ac652f7 Mon Sep 17 00:00:00 2001 From: Arsam Date: Sat, 2 Mar 2024 22:24:51 +0100 Subject: [PATCH 21/25] typo --- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 05e80c75..45923b3a 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -97,7 +97,7 @@ def test_stub_creation(self, python_file: Path, snapshot_sds_stub: SnapshotAsser assert stub_data[2] == snapshot_sds_stub return - # For these files stubs won't get created, because they are either empty of private. + # For these files stubs won't get created, because they are either empty or private. if file_name in {"__init__", "_reexport_module_3", "_module_2", "_module_4"}: return From a91bae33e907d0531b1e1cadf00ddd21346da9ec Mon Sep 17 00:00:00 2001 From: Arsam Date: Sat, 2 Mar 2024 22:28:36 +0100 Subject: [PATCH 22/25] linter fixes --- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 45923b3a..79a068e0 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -1,7 +1,7 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING, Literal, Generator +from typing import TYPE_CHECKING, Literal import pytest from safeds_stubgen.api_analyzer import get_api @@ -16,6 +16,7 @@ ) if TYPE_CHECKING: + from collections.abc import Generator from syrupy import SnapshotAssertion # Setup - Run API to create stub files From 08151c9a84f546857a572fd28372fb12f5279260 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Sat, 2 Mar 2024 21:30:08 +0000 Subject: [PATCH 23/25] style: apply automated linter fixes --- tests/safeds_stubgen/stubs_generator/test_generate_stubs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 79a068e0..a992d3f4 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -17,6 +17,7 @@ if TYPE_CHECKING: from collections.abc import Generator + from syrupy import SnapshotAssertion # Setup - Run API to create stub files From a920657b0d219c09f3c9e19742565399185c5ef2 Mon Sep 17 00:00:00 2001 From: Arsam Date: Sat, 2 Mar 2024 23:31:37 +0100 Subject: [PATCH 24/25] Refactoring the _convert_name_to_convention function and adding a NamingConvention Enum --- .../stubs_generator/_generate_stubs.py | 93 +++++++------------ .../stubs_generator/test_generate_stubs.py | 37 ++++---- 2 files changed, 56 insertions(+), 74 deletions(-) diff --git a/src/safeds_stubgen/stubs_generator/_generate_stubs.py b/src/safeds_stubgen/stubs_generator/_generate_stubs.py index 4bbc8246..b3b9a768 100644 --- a/src/safeds_stubgen/stubs_generator/_generate_stubs.py +++ b/src/safeds_stubgen/stubs_generator/_generate_stubs.py @@ -1,7 +1,8 @@ from __future__ import annotations +from enum import IntEnum from pathlib import Path -from typing import TYPE_CHECKING, Literal +from typing import TYPE_CHECKING from safeds_stubgen.api_analyzer import ( API, @@ -21,6 +22,11 @@ from collections.abc import Generator +class NamingConvention(IntEnum): + PYTHON = 1 + SAFE_DS = 2 + + def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: """Generate Safe-DS stubs. @@ -37,9 +43,10 @@ def generate_stubs(api: API, out_path: Path, convert_identifiers: bool) -> None: Set this True if the identifiers should be converted to Safe-DS standard (UpperCamelCase for classes and camelCase for everything else). """ - stubs_generator = StubsStringGenerator(api, convert_identifiers) + naming_convention = NamingConvention.SAFE_DS if convert_identifiers else NamingConvention.PYTHON + stubs_generator = StubsStringGenerator(api, naming_convention) stubs_data = _generate_stubs_data(api, out_path, stubs_generator) - _generate_stubs_files(stubs_data, api, out_path, stubs_generator, convert_identifiers) + _generate_stubs_files(stubs_data, api, out_path, stubs_generator, naming_convention) def _generate_stubs_data( @@ -72,7 +79,7 @@ def _generate_stubs_files( api: API, out_path: Path, stubs_generator: StubsStringGenerator, - convert_identifiers: bool, + naming_convention: NamingConvention, ) -> None: Path(out_path / api.package).mkdir(parents=True, exist_ok=True) @@ -91,18 +98,13 @@ def _generate_stubs_files( classes_outside_package = list(stubs_generator.classes_outside_package) classes_outside_package.sort() for class_ in classes_outside_package: - created_module_paths = _create_outside_package_class( - class_, - out_path, - convert_identifiers, - created_module_paths, - ) + created_module_paths = _create_outside_package_class(class_, out_path, naming_convention, created_module_paths) def _create_outside_package_class( class_path: str, out_path: Path, - convert_identifiers: bool, + naming_convention: NamingConvention, created_module_paths: set[str], ) -> set[str]: path_parts = class_path.split(".") @@ -121,33 +123,29 @@ def _create_outside_package_class( file_path = Path(module_dir / f"{module_name}.sdsstub") if Path.exists(file_path) and not first_creation: with file_path.open("a") as f: - f.write(_create_outside_package_class_text(class_name, convert_identifiers)) + f.write(_create_outside_package_class_text(class_name, naming_convention)) else: with file_path.open("w") as f: module_text = "" # package name & annotation python_module_path = ".".join(path_parts) - module_path_camel_case = python_module_path - if convert_identifiers: - module_path_camel_case = _convert_name_to_convention(python_module_path, "Safe-DS") + module_path_camel_case = _convert_name_to_convention(python_module_path, naming_convention) module_name_info = "" if python_module_path != module_path_camel_case: module_text += f'@PythonModule("{python_module_path}")\n' module_text += f"{module_name_info}package {module_path_camel_case}\n" - module_text += _create_outside_package_class_text(class_name, convert_identifiers) + module_text += _create_outside_package_class_text(class_name, naming_convention) f.write(module_text) return created_module_paths -def _create_outside_package_class_text(class_name: str, convert_identifiers: bool) -> str: +def _create_outside_package_class_text(class_name: str, naming_convention: NamingConvention) -> str: # to camel case - camel_case_name = class_name - if convert_identifiers: - camel_case_name = _convert_name_to_convention(class_name, "Safe-DS", is_class_name=True) + camel_case_name = _convert_name_to_convention(class_name, naming_convention, is_class_name=True) # add name annotation class_annotation = "" @@ -167,9 +165,9 @@ class StubsStringGenerator: method. """ - def __init__(self, api: API, convert_identifiers: bool) -> None: + def __init__(self, api: API, naming_convention: NamingConvention) -> None: self.api = api - self.convert_identifiers = convert_identifiers + self.naming_convention = naming_convention self.classes_outside_package: set[str] = set() def __call__(self, module: Module) -> str: @@ -182,9 +180,7 @@ def __call__(self, module: Module) -> str: def _create_module_string(self, module: Module) -> str: # Create package info package_info = module.id.replace("/", ".") - package_info_camel_case = package_info - if self.convert_identifiers: - package_info_camel_case = _convert_name_to_convention(package_info, "Safe-DS") + package_info_camel_case = _convert_name_to_convention(package_info, self.naming_convention) module_name_info = "" module_text = "" if package_info != package_info_camel_case: @@ -220,11 +216,11 @@ def _create_imports_string(self) -> str: import_parts = import_.split(".") from_ = ".".join(import_parts[0:-1]) - from_ = _convert_name_to_convention(from_, "Safe-DS") + from_ = _convert_name_to_convention(from_, self.naming_convention) from_ = _replace_if_safeds_keyword(from_) name = import_parts[-1] - name = _convert_name_to_convention(name, "Safe-DS") + name = _convert_name_to_convention(name, self.naming_convention) name = _replace_if_safeds_keyword(name) import_strings.append(f"from {from_} import {name}") @@ -284,9 +280,7 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st }[variance.variance.name] # Convert name to camelCase and check for keywords - variance_name_camel_case = variance.name - if self.convert_identifiers: - variance_name_camel_case = _convert_name_to_convention(variance.name, "Safe-DS") + variance_name_camel_case = _convert_name_to_convention(variance.name, self.naming_convention) variance_name_camel_case = _replace_if_safeds_keyword(variance_name_camel_case) variance_item = f"{variance_direction}{variance_name_camel_case}" @@ -300,9 +294,7 @@ def _create_class_string(self, class_: Class, class_indentation: str = "") -> st # Class name - Convert to camelCase and check for keywords class_name = class_.name python_name_info = "" - class_name_camel_case = class_name - if self.convert_identifiers: - class_name_camel_case = _convert_name_to_convention(class_name, "Safe-DS", is_class_name=True) + class_name_camel_case = _convert_name_to_convention(class_name, self.naming_convention, is_class_name=True) if class_name_camel_case != class_name: python_name_info = f"{class_indentation}{_create_name_annotation(class_name)}\n" class_name_camel_case = _replace_if_safeds_keyword(class_name_camel_case) @@ -376,9 +368,7 @@ def _create_class_attribute_string(self, attributes: list[Attribute], inner_inde # Convert name to camelCase and add PythonName annotation attr_name = attribute.name - attr_name_camel_case = attr_name - if self.convert_identifiers: - attr_name_camel_case = _convert_name_to_convention(attr_name, "Safe-DS") + attr_name_camel_case = _convert_name_to_convention(attr_name, self.naming_convention) attr_name_annotation = "" if attr_name_camel_case != attr_name: attr_name_annotation = f"{_create_name_annotation(attr_name)}\n{inner_indentations}" @@ -431,7 +421,7 @@ def _create_function_string(self, function: Function, indentations: str = "", is if function.type_var_types: type_var_names = [] for type_var in function.type_var_types: - type_var_name = _convert_name_to_convention(type_var.name, "Safe-DS") + type_var_name = _convert_name_to_convention(type_var.name, self.naming_convention) type_var_name = _replace_if_safeds_keyword(type_var_name) # We don't have to display generic types in methods if they were already displayed in the class @@ -446,9 +436,7 @@ def _create_function_string(self, function: Function, indentations: str = "", is # Convert function name to camelCase name = function.name - camel_case_name = name - if self.convert_identifiers: - camel_case_name = _convert_name_to_convention(name, "Safe-DS") + camel_case_name = _convert_name_to_convention(name, self.naming_convention) function_name_annotation = "" if camel_case_name != name: function_name_annotation = f"{indentations}{_create_name_annotation(name)}\n" @@ -473,9 +461,7 @@ def _create_property_function_string(self, function: Function, indentations: str Functions or methods with the @property decorator are handled the same way as class attributes. """ name = function.name - camel_case_name = name - if self.convert_identifiers: - camel_case_name = _convert_name_to_convention(name, "Safe-DS") + camel_case_name = _convert_name_to_convention(name, self.naming_convention) function_name_annotation = "" if camel_case_name != name: function_name_annotation = f"{_create_name_annotation(name)} " @@ -505,9 +491,7 @@ def _create_result_string(self, function_results: list[Result]) -> str: result_type = result.type.to_dict() ret_type = self._create_type_string(result_type) type_string = f": {ret_type}" if ret_type else "" - result_name = result.name - if self.convert_identifiers: - result_name = _convert_name_to_convention(result.name, "Safe-DS") + result_name = _convert_name_to_convention(result.name, self.naming_convention) result_name = _replace_if_safeds_keyword(result_name) if type_string: results.append( @@ -585,9 +569,7 @@ def _create_parameter_string( # Convert to camelCase if necessary name = parameter.name - camel_case_name = name - if self.convert_identifiers: - camel_case_name = _convert_name_to_convention(name, "Safe-DS") + camel_case_name = _convert_name_to_convention(name, self.naming_convention) name_annotation = "" if camel_case_name != name: # Memorize the changed name for the @PythonName() annotation @@ -621,9 +603,7 @@ def _create_enum_string(self, enum_data: Enum) -> str: name = enum_instance.name # Convert snake_case names to camelCase - camel_case_name = name - if self.convert_identifiers: - camel_case_name = _convert_name_to_convention(name, "Safe-DS") + camel_case_name = _convert_name_to_convention(name, self.naming_convention) annotation = "" if camel_case_name != name: annotation = f"{_create_name_annotation(name)} " @@ -759,7 +739,7 @@ def _create_type_string(self, type_data: dict | None) -> str: types.append(f"{literal_type}") return f"literal<{', '.join(types)}>" elif kind == "TypeVarType": - name = _convert_name_to_convention(type_data["name"], "Safe-DS") + name = _convert_name_to_convention(type_data["name"], self.naming_convention) return _replace_if_safeds_keyword(name) raise ValueError(f"Unexpected type: {kind}") # pragma: no cover @@ -790,8 +770,7 @@ def _add_to_imports(self, qname: str) -> None: for class_ in self.api.classes: if class_.endswith(qname_path): qname = class_.replace("/", ".") - if self.convert_identifiers: - qname = _convert_name_to_convention(qname, "Safe-DS") + qname = _convert_name_to_convention(qname, self.naming_convention) in_package = True break @@ -883,10 +862,10 @@ def _replace_if_safeds_keyword(keyword: str) -> str: def _convert_name_to_convention( name: str, - convention: Literal["Safe-DS", "Python"], + naming_convention: NamingConvention, is_class_name: bool = False, ) -> str: - if name == "_" or convention == "Python": + if name == "_" or naming_convention == NamingConvention.PYTHON: return name # Count underscores in front and behind the name diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index a992d3f4..19bdcb99 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -1,7 +1,7 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING, Literal +from typing import TYPE_CHECKING import pytest from safeds_stubgen.api_analyzer import get_api @@ -9,6 +9,7 @@ # noinspection PyProtectedMember from safeds_stubgen.stubs_generator._generate_stubs import ( + NamingConvention, StubsStringGenerator, _convert_name_to_convention, _generate_stubs_data, @@ -28,12 +29,12 @@ _out_dir_stubs = Path(_out_dir / _test_package_name) api = get_api(_test_package_name, _test_package_dir, is_test_run=True) -stubs_generator = StubsStringGenerator(api, convert_identifiers=True) +stubs_generator = StubsStringGenerator(api, naming_convention=NamingConvention.SAFE_DS) stubs_data = _generate_stubs_data(api, _out_dir, stubs_generator) def test_file_creation() -> None: - _generate_stubs_files(stubs_data, api, _out_dir, stubs_generator, convert_identifiers=True) + _generate_stubs_files(stubs_data, api, _out_dir, stubs_generator, naming_convention=NamingConvention.SAFE_DS) _assert_file_creation_recursive( python_path=Path(_test_package_dir / "file_creation"), stub_path=Path(_out_dir_stubs / "file_creation"), @@ -107,27 +108,29 @@ def test_stub_creation(self, python_file: Path, snapshot_sds_stub: SnapshotAsser @pytest.mark.parametrize( - ("name", "expected_result", "convention", "is_class_name"), + ("name", "expected_result", "naming_convention", "is_class_name"), [ ("", "", "Safe-DS", False), ("_", "_", "Safe-DS", False), - ("__get_function_name__", "getFunctionName", "Safe-DS", False), - ("__get_function_name", "getFunctionName", "Safe-DS", False), - ("get_function_name__", "getFunctionName", "Safe-DS", False), - ("__getFunction_name__", "getFunctionName", "Safe-DS", False), - ("__get__function___name__", "getFunctionName", "Safe-DS", False), - ("__get_funCtion_NamE__", "getFunCtionNamE", "Safe-DS", False), - ("getFunctionName", "getFunctionName", "Safe-DS", False), - ("a_a_A_aAAaA_1_1_2_aAa", "aAAAAAaA112AAa", "Safe-DS", False), - ("some_class_name", "SomeClassName", "Safe-DS", True), - ("some_class_name", "some_class_name", "Python", True), - ("__get_function_name__", "__get_function_name__", "Python", False), + ("__get_function_name__", "getFunctionName", NamingConvention.SAFE_DS, False), + ("__get_function_name", "getFunctionName", NamingConvention.SAFE_DS, False), + ("get_function_name__", "getFunctionName", NamingConvention.SAFE_DS, False), + ("__getFunction_name__", "getFunctionName", NamingConvention.SAFE_DS, False), + ("__get__function___name__", "getFunctionName", NamingConvention.SAFE_DS, False), + ("__get_funCtion_NamE__", "getFunCtionNamE", NamingConvention.SAFE_DS, False), + ("getFunctionName", "getFunctionName", NamingConvention.SAFE_DS, False), + ("a_a_A_aAAaA_1_1_2_aAa", "aAAAAAaA112AAa", NamingConvention.SAFE_DS, False), + ("some_class_name", "SomeClassName", NamingConvention.SAFE_DS, True), + ("some_class_name", "some_class_name", NamingConvention.PYTHON, True), + ("__get_function_name__", "__get_function_name__", NamingConvention.PYTHON, False), ], ) def test_convert_name_to_convention( name: str, expected_result: str, - convention: Literal["Safe-DS", "Python"], + naming_convention: NamingConvention, is_class_name: bool, ) -> None: - assert _convert_name_to_convention(name=name, convention=convention, is_class_name=is_class_name) == expected_result + assert _convert_name_to_convention( + name=name, naming_convention=naming_convention, is_class_name=is_class_name + ) == expected_result From b003965e93f326c8492beeb9c5c1add07c3b6133 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Sat, 2 Mar 2024 22:33:15 +0000 Subject: [PATCH 25/25] style: apply automated linter fixes --- .../safeds_stubgen/stubs_generator/test_generate_stubs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py index 19bdcb99..cb9a25ab 100644 --- a/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py +++ b/tests/safeds_stubgen/stubs_generator/test_generate_stubs.py @@ -131,6 +131,7 @@ def test_convert_name_to_convention( naming_convention: NamingConvention, is_class_name: bool, ) -> None: - assert _convert_name_to_convention( - name=name, naming_convention=naming_convention, is_class_name=is_class_name - ) == expected_result + assert ( + _convert_name_to_convention(name=name, naming_convention=naming_convention, is_class_name=is_class_name) + == expected_result + )