diff --git a/package-parser/package_parser/processing/migration/_migrate.py b/package-parser/package_parser/processing/migration/_migrate.py index b579323ab..7a04dfec2 100644 --- a/package-parser/package_parser/processing/migration/_migrate.py +++ b/package-parser/package_parser/processing/migration/_migrate.py @@ -15,6 +15,9 @@ from package_parser.processing.migration.annotations._migrate_move_annotation import ( migrate_move_annotation, ) +from package_parser.processing.migration.annotations._migrate_remove_annotation import ( + migrate_remove_annotation, +) from package_parser.processing.migration.model import Mapping @@ -60,6 +63,12 @@ def migrate_annotations( for annotation in migrate_rename_annotation(rename_annotation, mapping): migrated_annotation_store.add_annotation(annotation) + for remove_annotation in annotationsv1.removeAnnotations: + mapping = _get_mapping_from_annotation(remove_annotation, mappings) + if mapping is not None: + for annotation in migrate_remove_annotation(remove_annotation, mapping): + migrated_annotation_store.add_annotation(annotation) + for todo_annotation in annotationsv1.todoAnnotations: mapping = _get_mapping_from_annotation(todo_annotation, mappings) if mapping is not None: diff --git a/package-parser/package_parser/processing/migration/annotations/_get_annotated_api_element.py b/package-parser/package_parser/processing/migration/annotations/_get_annotated_api_element.py new file mode 100644 index 000000000..c4346508d --- /dev/null +++ b/package-parser/package_parser/processing/migration/annotations/_get_annotated_api_element.py @@ -0,0 +1,36 @@ +from typing import List, Optional, TypeVar, Union + +from package_parser.processing.annotations.model import AbstractAnnotation +from package_parser.processing.api.model import ( + Attribute, + Class, + Function, + Parameter, + Result, +) + +API_ELEMENTS = TypeVar("API_ELEMENTS", Class, Function, Parameter) + + +def get_annotated_api_element( + annotation: AbstractAnnotation, + api_element_list: List[Union[Attribute, Class, Function, Parameter, Result]], +) -> Optional[Union[Class, Function, Parameter]]: + for element in api_element_list: + if ( + isinstance(element, (Class, Function, Parameter)) + and element.id == annotation.target + ): + return element + return None + + +def get_annotated_api_element_by_type( + annotation: AbstractAnnotation, + api_element_list: List[Union[Attribute, Class, Function, Parameter, Result]], + api_type: type[API_ELEMENTS], +) -> Optional[API_ELEMENTS]: + for element in api_element_list: + if isinstance(element, api_type) and element.id == annotation.target: + return element + return None diff --git a/package-parser/package_parser/processing/migration/annotations/_migrate_move_annotation.py b/package-parser/package_parser/processing/migration/annotations/_migrate_move_annotation.py index 75d9e578f..d5f264e6a 100644 --- a/package-parser/package_parser/processing/migration/annotations/_migrate_move_annotation.py +++ b/package-parser/package_parser/processing/migration/annotations/_migrate_move_annotation.py @@ -20,6 +20,7 @@ ) from ._constants import migration_author +from ._get_annotated_api_element import get_annotated_api_element from ._get_migration_text import get_migration_text @@ -61,15 +62,9 @@ def migrate_move_annotation( move_annotation.target = element.id return [move_annotation] - annotated_apiv1_element = None - for element in mapping.get_apiv1_elements(): - if ( - not isinstance(element, (Attribute, Result)) - and move_annotation.target == element.id - ): - annotated_apiv1_element = element - break - + annotated_apiv1_element = get_annotated_api_element( + move_annotation, mapping.get_apiv1_elements() + ) if annotated_apiv1_element is None: return [] diff --git a/package-parser/package_parser/processing/migration/annotations/_migrate_remove_annotation.py b/package-parser/package_parser/processing/migration/annotations/_migrate_remove_annotation.py new file mode 100644 index 000000000..49d935064 --- /dev/null +++ b/package-parser/package_parser/processing/migration/annotations/_migrate_remove_annotation.py @@ -0,0 +1,91 @@ +from copy import deepcopy + +from package_parser.processing.annotations.model import ( + AbstractAnnotation, + EnumReviewResult, + RemoveAnnotation, + TodoAnnotation, +) +from package_parser.processing.api.model import ( + Attribute, + Class, + Function, + Parameter, + Result, +) +from package_parser.processing.migration.model import ( + ManyToOneMapping, + Mapping, + OneToOneMapping, +) + +from ._constants import migration_author +from ._get_annotated_api_element import get_annotated_api_element +from ._get_migration_text import get_migration_text + + +def is_removeable(element: Attribute | Class | Function | Parameter | Result) -> bool: + return isinstance(element, (Class, Function)) + + +def migrate_remove_annotation( + remove_annotation: RemoveAnnotation, mapping: Mapping +) -> list[AbstractAnnotation]: + remove_annotation = deepcopy(remove_annotation) + authors = remove_annotation.authors + authors.append(migration_author) + remove_annotation.authors = authors + migrate_text = get_migration_text(remove_annotation, mapping) + + if isinstance(mapping, (ManyToOneMapping, OneToOneMapping)): + element = mapping.get_apiv2_elements()[0] + if isinstance(element, (Attribute, Result)): + return [] + if not is_removeable(element): + return [ + TodoAnnotation( + element.id, + authors, + remove_annotation.reviewers, + remove_annotation.comment, + EnumReviewResult.NONE, + migrate_text, + ) + ] + remove_annotation.target = element.id + return [remove_annotation] + + annotated_apiv1_element = get_annotated_api_element( + remove_annotation, mapping.get_apiv1_elements() + ) + if annotated_apiv1_element is None: + return [] + + remove_annotations: list[AbstractAnnotation] = [] + for element in mapping.get_apiv2_elements(): + if ( + isinstance(element, type(annotated_apiv1_element)) + and is_removeable(element) + and not isinstance(element, (Attribute, Result)) + ): + remove_annotations.append( + RemoveAnnotation( + element.id, + authors, + remove_annotation.reviewers, + remove_annotation.comment, + EnumReviewResult.NONE, + ) + ) + elif not isinstance(element, (Attribute, Result)): + remove_annotations.append( + TodoAnnotation( + element.id, + authors, + remove_annotation.reviewers, + remove_annotation.comment, + EnumReviewResult.NONE, + migrate_text, + ) + ) + return remove_annotations diff --git a/package-parser/package_parser/processing/migration/annotations/_migrate_todo_annotation.py b/package-parser/package_parser/processing/migration/annotations/_migrate_todo_annotation.py index b294c5256..dc27d1b28 100644 --- a/package-parser/package_parser/processing/migration/annotations/_migrate_todo_annotation.py +++ b/package-parser/package_parser/processing/migration/annotations/_migrate_todo_annotation.py @@ -13,6 +13,7 @@ ) from ._constants import migration_author +from ._get_annotated_api_element import get_annotated_api_element from ._get_migration_text import get_migration_text @@ -34,15 +35,9 @@ def migrate_todo_annotation( migrate_text = get_migration_text(todo_annotation, mapping) - annotated_apiv1_element = None - for element in mapping.get_apiv1_elements(): - if ( - not isinstance(element, (Attribute, Result)) - and todo_annotation.target == element.id - ): - annotated_apiv1_element = element - break - + annotated_apiv1_element = get_annotated_api_element( + todo_annotation, mapping.get_apiv1_elements() + ) if annotated_apiv1_element is None: return [] diff --git a/package-parser/package_parser/processing/migration/annotations/_migrate_value_annotation.py b/package-parser/package_parser/processing/migration/annotations/_migrate_value_annotation.py index 12fcf00ce..5fa917d50 100644 --- a/package-parser/package_parser/processing/migration/annotations/_migrate_value_annotation.py +++ b/package-parser/package_parser/processing/migration/annotations/_migrate_value_annotation.py @@ -1,5 +1,5 @@ from copy import deepcopy -from typing import Optional, Tuple, TypeVar +from typing import Optional, Tuple from package_parser.processing.annotations.model import ( AbstractAnnotation, @@ -14,8 +14,6 @@ from package_parser.processing.api.model import ( AbstractType, Attribute, - Class, - Function, NamedType, Parameter, Result, @@ -30,6 +28,7 @@ ) from ._constants import migration_author +from ._get_annotated_api_element import get_annotated_api_element_by_type from ._get_migration_text import get_migration_text @@ -254,26 +253,6 @@ def _have_same_value( return None -API_ELEMENTS = TypeVar("API_ELEMENTS", Class, Function, Parameter) - - -def get_api_element_from_mapping( - annotation: AbstractAnnotation, mapping: Mapping, api_type: type[API_ELEMENTS] -) -> Optional[API_ELEMENTS]: - element_list = [ - element - for element in mapping.get_apiv1_elements() - if ( - isinstance(element, api_type) - and hasattr(element, "id") - and element.id == annotation.target - ) - ] - if len(element_list) != 1: - return None - return element_list[0] - - def migrate_constant_annotation( constant_annotation: ConstantAnnotation, parameterv2: Parameter, mapping: Mapping ) -> Optional[ConstantAnnotation]: @@ -291,7 +270,9 @@ def migrate_constant_annotation( constant_annotation.defaultValue, ) - parameterv1 = get_api_element_from_mapping(constant_annotation, mapping, Parameter) + parameterv1 = get_annotated_api_element_by_type( + constant_annotation, mapping.get_apiv1_elements(), Parameter + ) if parameterv1 is None: return None if _have_same_type( @@ -312,7 +293,9 @@ def migrate_constant_annotation( def migrate_omitted_annotation( omitted_annotation: OmittedAnnotation, parameterv2: Parameter, mapping: Mapping ) -> Optional[OmittedAnnotation]: - parameterv1 = get_api_element_from_mapping(omitted_annotation, mapping, Parameter) + parameterv1 = get_annotated_api_element_by_type( + omitted_annotation, mapping.get_apiv1_elements(), Parameter + ) if parameterv1 is None: return None type_and_same_value = _have_same_value(parameterv1, parameterv2) @@ -346,7 +329,9 @@ def migrate_omitted_annotation( def migrate_optional_annotation( optional_annotation: OptionalAnnotation, parameterv2: Parameter, mapping: Mapping ) -> Optional[OptionalAnnotation]: - parameterv1 = get_api_element_from_mapping(optional_annotation, mapping, Parameter) + parameterv1 = get_annotated_api_element_by_type( + optional_annotation, mapping.get_apiv1_elements(), Parameter + ) if parameterv1 is None: return None if parameterv2.type is not None and _have_same_type( @@ -380,7 +365,9 @@ def migrate_optional_annotation( def migrate_required_annotation( required_annotation: RequiredAnnotation, parameterv2: Parameter, mapping: Mapping ) -> Optional[RequiredAnnotation]: - parameterv1 = get_api_element_from_mapping(required_annotation, mapping, Parameter) + parameterv1 = get_annotated_api_element_by_type( + required_annotation, mapping.get_apiv1_elements(), Parameter + ) if parameterv1 is None: return None type_and_same_value = _have_same_value(parameterv1, parameterv2) diff --git a/package-parser/tests/processing/migration/annotations/test_move_annotation.py b/package-parser/tests/processing/migration/annotations/test_move_annotation.py index ba99a6ac4..dd48694b8 100644 --- a/package-parser/tests/processing/migration/annotations/test_move_annotation.py +++ b/package-parser/tests/processing/migration/annotations/test_move_annotation.py @@ -23,14 +23,15 @@ ) +# pylint: disable=duplicate-code def migrate_move_annotation_data_one_to_one_mapping__global_function() -> Tuple[ Mapping, AbstractAnnotation, list[AbstractAnnotation], ]: functionv1 = Function( - id="test/test.value.test1.test/test", - qname="test.value.test1.test/test", + id="test/test.move.test1.test/test", + qname="test.move.test1.test/test", decorators=[], parameters=[], results=[], @@ -41,8 +42,8 @@ def migrate_move_annotation_data_one_to_one_mapping__global_function() -> Tuple[ ) functionv2 = Function( - id="test/test.value.test1.test/new_test", - qname="test.value.test1.test/new_test", + id="test/test.move.test1.test/new_test", + qname="test.move.test1.test/new_test", decorators=[], parameters=[], results=[], @@ -55,20 +56,20 @@ def migrate_move_annotation_data_one_to_one_mapping__global_function() -> Tuple[ mapping = OneToOneMapping(1.0, functionv1, functionv2) annotationv1 = MoveAnnotation( - target="test/test.value.test1.test/test", + target="test/test.move.test1.test/test", authors=["testauthor"], reviewers=[], comment="", reviewResult=EnumReviewResult.NONE, - destination="test.value.test1.destination", + destination="test.move.test1.destination", ) annotationv2 = MoveAnnotation( - target="test/test.value.test1.test/new_test", + target="test/test.move.test1.test/new_test", authors=["testauthor", migration_author], reviewers=[], comment="", reviewResult=EnumReviewResult.NONE, - destination="test.value.test1.destination", + destination="test.move.test1.destination", ) return mapping, annotationv1, [annotationv2] @@ -80,8 +81,8 @@ def migrate_move_annotation_data_one_to_one_mapping__class() -> Tuple[ list[AbstractAnnotation], ]: classv1 = Class( - id_="test/test.value.test2.test/MoveTestClass", - qname="test.value.test2.test.TestClass", + id_="test/test.move.test2.test/MoveTestClass", + qname="test.move.test2.test.TestClass", decorators=[], superclasses=[], is_public=True, @@ -91,8 +92,8 @@ def migrate_move_annotation_data_one_to_one_mapping__class() -> Tuple[ instance_attributes=[], ) classv2 = Class( - id_="test/test.value.test2.test/NewMoveTestClass", - qname="test.value.test2.test.NewMoveTestClass", + id_="test/test.move.test2.test/NewMoveTestClass", + qname="test.move.test2.test.NewMoveTestClass", decorators=[], superclasses=[], is_public=True, @@ -105,20 +106,20 @@ def migrate_move_annotation_data_one_to_one_mapping__class() -> Tuple[ mapping = OneToOneMapping(1.0, classv1, classv2) annotationv1 = MoveAnnotation( - target="test/test.value.test2.test/MoveTestClass", + target="test/test.move.test2.test/MoveTestClass", authors=["testauthor"], reviewers=[], comment="", reviewResult=EnumReviewResult.NONE, - destination="test.value.test2.destination", + destination="test.move.test2.destination", ) annotationv2 = MoveAnnotation( - target="test/test.value.test2.test/NewMoveTestClass", + target="test/test.move.test2.test/NewMoveTestClass", authors=["testauthor", migration_author], reviewers=[], comment="", reviewResult=EnumReviewResult.NONE, - destination="test.value.test2.destination", + destination="test.move.test2.destination", ) return mapping, annotationv1, [annotationv2] @@ -130,8 +131,8 @@ def migrate_move_annotation_data_one_to_many_mapping() -> Tuple[ ]: functionv1 = Function( - id="test/test.value.test3.test/test", - qname="test.value.test3.test.test", + id="test/test.move.test3.test/test", + qname="test.move.test3.test.test", decorators=[], parameters=[], results=[], @@ -142,8 +143,8 @@ def migrate_move_annotation_data_one_to_many_mapping() -> Tuple[ ) functionv2_a = Function( - id="test/test.value.test3.test/new_test_a", - qname="test.value.test3.test.new_test_a", + id="test/test.move.test3.test/new_test_a", + qname="test.move.test3.test.new_test_a", decorators=[], parameters=[], results=[], @@ -154,8 +155,8 @@ def migrate_move_annotation_data_one_to_many_mapping() -> Tuple[ ) functionv2_b = Function( - id="test/test.value.test3.test/TestClass/new_test_b", - qname="test.value.test3.test.TestClass.new_test_b", + id="test/test.move.test3.test/TestClass/new_test_b", + qname="test.move.test3.test.TestClass.new_test_b", decorators=[], parameters=[], results=[], @@ -168,23 +169,23 @@ def migrate_move_annotation_data_one_to_many_mapping() -> Tuple[ mapping = OneToManyMapping(1.0, functionv1, [functionv2_a, functionv2_b]) annotationv1 = MoveAnnotation( - target="test/test.value.test3.test/test", + target="test/test.move.test3.test/test", authors=["testauthor"], reviewers=[], comment="", reviewResult=EnumReviewResult.NONE, - destination="test.value.test3.destination", + destination="test.move.test3.destination", ) annotationv2_a = MoveAnnotation( - target="test/test.value.test3.test/new_test_a", + target="test/test.move.test3.test/new_test_a", authors=["testauthor", migration_author], reviewers=[], comment="", reviewResult=EnumReviewResult.NONE, - destination="test.value.test3.destination", + destination="test.move.test3.destination", ) annotationv2_b = TodoAnnotation( - target="test/test.value.test3.test/TestClass/new_test_b", + target="test/test.move.test3.test/TestClass/new_test_b", authors=["testauthor", migration_author], reviewers=[], comment="", diff --git a/package-parser/tests/processing/migration/annotations/test_remove_migration.py b/package-parser/tests/processing/migration/annotations/test_remove_migration.py new file mode 100644 index 000000000..3ee6fe7ed --- /dev/null +++ b/package-parser/tests/processing/migration/annotations/test_remove_migration.py @@ -0,0 +1,158 @@ +from typing import Tuple + +from package_parser.processing.annotations.model import ( + AbstractAnnotation, + EnumReviewResult, + RemoveAnnotation, + TodoAnnotation, +) +from package_parser.processing.api.model import ( + Class, + ClassDocumentation, + Function, + FunctionDocumentation, +) +from package_parser.processing.migration import ( + Mapping, + OneToManyMapping, + OneToOneMapping, +) +from package_parser.processing.migration.annotations import ( + get_migration_text, + migration_author, +) + + +# pylint: disable=duplicate-code +def migrate_remove_annotation_data_one_to_one_mapping() -> Tuple[ + Mapping, + AbstractAnnotation, + list[AbstractAnnotation], +]: + functionv1 = Function( + id="test/test.remove.test1.test/test", + qname="test.remove.test1.test/test", + decorators=[], + parameters=[], + results=[], + is_public=True, + reexported_by=[], + documentation=FunctionDocumentation("", ""), + code="", + ) + + functionv2 = Function( + id="test/test.remove.test1.test/new_test", + qname="test.remove.test1.test/new_test", + decorators=[], + parameters=[], + results=[], + is_public=True, + reexported_by=[], + documentation=FunctionDocumentation("", ""), + code="", + ) + + mapping = OneToOneMapping(1.0, functionv1, functionv2) + + annotationv1 = RemoveAnnotation( + target="test/test.remove.test1.test/test", + authors=["testauthor"], + reviewers=[], + comment="", + reviewResult=EnumReviewResult.NONE, + ) + annotationv2 = RemoveAnnotation( + target="test/test.remove.test1.test/new_test", + authors=["testauthor", migration_author], + reviewers=[], + comment="", + reviewResult=EnumReviewResult.NONE, + ) + return mapping, annotationv1, [annotationv2] + + +# pylint: disable=duplicate-code +def migrate_remove_annotation_data_one_to_many_mapping() -> Tuple[ + Mapping, + AbstractAnnotation, + list[AbstractAnnotation], +]: + + classv1 = Class( + id_="test/test.remove.test2.test/RemoveTestClass", + qname="test.remove.test2.test.RemoveTestClass", + decorators=[], + superclasses=[], + is_public=True, + reexported_by=[], + documentation=ClassDocumentation("", ""), + code="class RemoveTestClass:\n pass", + instance_attributes=[], + ) + classv2_a = Class( + id_="test/test.remove.test2.test/NewRemoveTestClass", + qname="test.remove.test2.test.NewRemoveTestClass", + decorators=[], + superclasses=[], + is_public=True, + reexported_by=[], + documentation=ClassDocumentation("", ""), + code="class NewRemoveTestClass:\n pass", + instance_attributes=[], + ) + classv2_b = Class( + id_="test/test.remove.test2.test/NewRemoveTestClass2", + qname="test.remove.test2.test.NewRemoveTestClass2", + decorators=[], + superclasses=[], + is_public=True, + reexported_by=[], + documentation=ClassDocumentation("", ""), + code="class NewRemoveTestClass2:\n pass", + instance_attributes=[], + ) + functionv2 = Function( + id="test/test.remove.test2.test/TestClass/new_test", + qname="test.remove.test2.test.TestClass.new_test", + decorators=[], + parameters=[], + results=[], + is_public=True, + reexported_by=[], + documentation=FunctionDocumentation("", ""), + code="", + ) + + mapping = OneToManyMapping(1.0, classv1, [classv2_a, classv2_b, functionv2]) + + annotationv1 = RemoveAnnotation( + target="test/test.remove.test2.test/RemoveTestClass", + authors=["testauthor"], + reviewers=[], + comment="", + reviewResult=EnumReviewResult.NONE, + ) + annotationv2_a = RemoveAnnotation( + target="test/test.remove.test2.test/NewRemoveTestClass", + authors=["testauthor", migration_author], + reviewers=[], + comment="", + reviewResult=EnumReviewResult.NONE, + ) + annotationv2_b = RemoveAnnotation( + target="test/test.remove.test2.test/NewRemoveTestClass2", + authors=["testauthor", migration_author], + reviewers=[], + comment="", + reviewResult=EnumReviewResult.NONE, + ) + annotationv2_c = TodoAnnotation( + target="test/test.remove.test2.test/TestClass/new_test", + authors=["testauthor", migration_author], + reviewers=[], + comment="", + reviewResult=EnumReviewResult.NONE, + newTodo=get_migration_text(annotationv1, mapping), + ) + return mapping, annotationv1, [annotationv2_a, annotationv2_b, annotationv2_c] diff --git a/package-parser/tests/processing/migration/test_migration.py b/package-parser/tests/processing/migration/test_migration.py index 018fa860f..c6cae3b63 100644 --- a/package-parser/tests/processing/migration/test_migration.py +++ b/package-parser/tests/processing/migration/test_migration.py @@ -20,6 +20,10 @@ migrate_move_annotation_data_one_to_one_mapping__class, migrate_move_annotation_data_one_to_one_mapping__global_function, ) +from tests.processing.migration.annotations.test_remove_migration import ( + migrate_remove_annotation_data_one_to_many_mapping, + migrate_remove_annotation_data_one_to_one_mapping, +) from tests.processing.migration.annotations.test_rename_migration import ( migrate_rename_annotation_data_one_to_many_mapping, migrate_rename_annotation_data_one_to_many_mapping__with_changed_new_name, @@ -55,6 +59,9 @@ migrate_move_annotation_data_one_to_one_mapping__class(), migrate_move_annotation_data_one_to_one_mapping__global_function(), migrate_move_annotation_data_one_to_many_mapping(), + # remove annotation + migrate_remove_annotation_data_one_to_one_mapping(), + migrate_remove_annotation_data_one_to_many_mapping(), # rename annotation migrate_rename_annotation_data_one_to_many_mapping__with_changed_new_name(), migrate_rename_annotation_data_one_to_one_mapping(),