Skip to content
This repository was archived by the owner on Jan 19, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
40e82f1
add missing annotation classes
Aclrian Nov 12, 2022
9512403
complete missing annotations-to-json functions
Aclrian Nov 14, 2022
53ba7ac
add tests for import and export annotations
Aclrian Nov 14, 2022
443b6ce
add import of annotations during `migrate`
Aclrian Nov 14, 2022
9d3a756
refactor: using tuple and move import
Aclrian Nov 14, 2022
13aae59
refactor: from_json returns everywhere annotations
Aclrian Nov 14, 2022
f418c51
refactor: unused import
Aclrian Nov 14, 2022
6763e62
ci: disable import-error rule of pylint
lars-reimann Nov 10, 2022
54ae4c0
ci: add back default disabled rules
lars-reimann Nov 10, 2022
bbce028
ci: another attempt to configure pylint
lars-reimann Nov 10, 2022
05f8385
ci: another attempt to configure pylint
lars-reimann Nov 10, 2022
5200a31
ci: another attempt to configure pylint
lars-reimann Nov 10, 2022
d224364
ci: another attempt to configure pylint
lars-reimann Nov 10, 2022
56f3f1f
refactor: meaglinter and other warning
Aclrian Nov 14, 2022
e39ecff
disable cyclic-import, unused-arguments
Aclrian Nov 14, 2022
064a73f
add AbstractDiffer class
Aclrian Nov 15, 2022
f51cdf3
change return type to float
Aclrian Nov 15, 2022
7e1bc6b
make Differ Methods static
Aclrian Nov 15, 2022
4f0832b
get code block from function
Aclrian Nov 6, 2022
b4bb805
get code from class
Aclrian Nov 6, 2022
0228088
save code from api elements
Aclrian Nov 7, 2022
7983859
style: apply automated linter fixes
Aclrian Nov 7, 2022
cf75abf
add tests and change to lineno from fromlineno
Aclrian Nov 8, 2022
4a7162f
update api data
Aclrian Nov 8, 2022
f1dc3eb
add a comma
Aclrian Nov 8, 2022
f2db401
update api data
Aclrian Nov 9, 2022
395aaa2
ci: disable import-error rule of pylint
lars-reimann Nov 10, 2022
80ca8f7
ci: add back default disabled rules
lars-reimann Nov 10, 2022
64b5f2e
ci: another attempt to configure pylint
lars-reimann Nov 10, 2022
d4b4785
ci: another attempt to configure pylint
lars-reimann Nov 10, 2022
1bfb9d4
ci: another attempt to configure pylint
lars-reimann Nov 10, 2022
8e2548c
style: fix linter errors
lars-reimann Nov 10, 2022
8f88c28
ci: another attempt to configure pylint
lars-reimann Nov 10, 2022
c2f6dbf
style: apply automated linter fixes
lars-reimann Nov 10, 2022
bc216d0
applying requested changes
Aclrian Nov 10, 2022
3b68cd6
style: apply automated linter fixes
Aclrian Nov 10, 2022
b843cb3
add SimpleDiffer class
Aclrian Nov 15, 2022
1a4b265
Update _differ.py
Aclrian Nov 15, 2022
0790cfe
ci: configure pylint
Aclrian Nov 15, 2022
25b71ef
style: apply automated linter fixes
Aclrian Nov 15, 2022
1ef98a2
refactor: remove unwanted changes
Aclrian Nov 15, 2022
5147778
Merge branch '1113-create-a-differ-abstract-base-class' into 1114-cre…
Aclrian Nov 15, 2022
5e93e1f
style: apply automated linter fixes
Aclrian Nov 15, 2022
8d7030f
add functions diff_codes and diff_names
Aclrian Nov 16, 2022
0083962
Merge branch '1113-create-a-differ-abstract-base-class' into 1114-cre…
Aclrian Nov 16, 2022
0ee9f00
add diff_codes, changes in visability
Aclrian Nov 16, 2022
882cea0
Merge branch '1110-support-import-of-annotations' into 1114-create-a-…
Aclrian Nov 16, 2022
f5ca14a
refactor: SimpleDiffer extends AbstractDiffer
Aclrian Nov 16, 2022
3b3f86c
style: apply automated linter fixes
Aclrian Nov 16, 2022
84394ca
Merge branch 'main' into 1113-create-a-differ-abstract-base-class
lars-reimann Nov 16, 2022
abb19aa
apply requested changes
Aclrian Nov 16, 2022
819961f
style: apply automated linter fixes
Aclrian Nov 16, 2022
c7c23ef
Merge branch '1113-create-a-differ-abstract-base-class' into 1114-cre…
Aclrian Nov 16, 2022
3b81be6
adapt changes from merge
Aclrian Nov 16, 2022
080c4ed
style: apply automated linter fixes
Aclrian Nov 16, 2022
6ed5a63
refactor: removed duplicated file
Aclrian Nov 16, 2022
689add0
add class InstanceAttribute
Aclrian Nov 17, 2022
1506c4e
refactor: fix linter errors
Aclrian Nov 17, 2022
6cb3b35
style: apply automated linter fixes
Aclrian Nov 17, 2022
caf04a0
Merge branch '1113-create-a-differ-abstract-base-class' into 1114-cre…
Aclrian Nov 17, 2022
79d696e
similarity is now highest at 1
Aclrian Nov 17, 2022
130a66a
fix static parser error
Aclrian Nov 17, 2022
ad4d0d8
style: apply automated linter fixes
Aclrian Nov 17, 2022
ce7af15
add tests
Aclrian Nov 19, 2022
64d5f19
Squashed commit of the following:
Aclrian Nov 20, 2022
a206dc6
add Mapping classes
Aclrian Nov 20, 2022
7a6482b
add mapping, reduce, combine and merge methods
Aclrian Nov 21, 2022
3b5fd24
style: apply automated linter fixes
Aclrian Nov 21, 2022
6d01f68
switch to list comprehension for better reading
Aclrian Nov 21, 2022
e2e7de3
style: apply automated linter fixes
Aclrian Nov 21, 2022
e04e7f3
ref: use List instead of sequence
Aclrian Nov 22, 2022
87748de
rename mapping.py
Aclrian Nov 22, 2022
3708f98
adding tests for mapping
Aclrian Nov 22, 2022
cffa2fb
fix linter errors
Aclrian Nov 22, 2022
a282570
style: apply automated linter fixes
Aclrian Nov 22, 2022
73823a3
add documentation and renamings
Aclrian Nov 23, 2022
c967efa
style: apply automated linter fixes
Aclrian Nov 23, 2022
d965ac6
rename (Instance)Attribute and use AbstractType
Aclrian Nov 24, 2022
f3e6a3d
fix (already existing) linter errors
Aclrian Nov 25, 2022
558aef2
Merge branch '1113-create-a-differ-abstract-base-class' into 1114-cre…
Aclrian Nov 25, 2022
d9c8e38
rename (Instance)Attribute
Aclrian Nov 25, 2022
60a3944
adapt changes
Aclrian Nov 25, 2022
c43b024
style: apply automated linter fixes
Aclrian Nov 25, 2022
91e1c50
Merge branch '1114-create-a-simple-implementation-of-the-differ' into…
Aclrian Nov 25, 2022
104104d
style: apply automated linter fixes
Aclrian Nov 25, 2022
4112de3
create class APIMapping
Aclrian Nov 26, 2022
bc4d25a
fix linter errors
Aclrian Nov 26, 2022
d8a38cf
style: apply automated linter fixes
Aclrian Nov 26, 2022
f91f621
Merge branch 'main' into 1114-create-a-simple-implementation-of-the-d…
Aclrian Nov 29, 2022
3804c7b
Merge branch '1114-create-a-simple-implementation-of-the-differ' into…
Aclrian Nov 29, 2022
48a9c96
Merge branch 'main' into 1118-map-list-of-old-api-elements-to-list-of…
Aclrian Nov 30, 2022
a0bab02
use @dataclsss for mappings
Aclrian Nov 30, 2022
618588f
undo not necessary changes
Aclrian Nov 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
from ._differ import AbstractDiffer, SimpleDiffer
from ._mapping import (
APIMapping,
ManyToManyMapping,
ManyToOneMapping,
Mapping,
OneToManyMapping,
OneToOneMapping,
)
260 changes: 260 additions & 0 deletions package-parser/package_parser/processing/migration/_mapping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Callable, List, Optional, TypeVar, Union

from package_parser.processing.api.model import (
API,
Attribute,
Class,
Function,
Parameter,
Result,
)

from ._differ import AbstractDiffer

api_element = Union[Attribute, Class, Function, Parameter, Result]
API_ELEMENTS = TypeVar("API_ELEMENTS", Attribute, Class, Function, Parameter, Result)


@dataclass
class Mapping(ABC):
similarity: float

@abstractmethod
def get_apiv1_elements(self) -> list[api_element]:
pass

@abstractmethod
def get_apiv2_elements(self) -> list[api_element]:
pass

def get_similarity(self) -> float:
return self.similarity


@dataclass
class OneToOneMapping(Mapping):
apiv1_element: api_element
apiv2_element: api_element

def get_apiv1_elements(self) -> list[api_element]:
return [self.apiv1_element]

def get_apiv2_elements(self) -> list[api_element]:
return [self.apiv2_element]


@dataclass
class OneToManyMapping(Mapping):
apiv1_element: api_element
apiv2_elements: list[api_element]

def get_apiv1_elements(self) -> list[api_element]:
return [self.apiv1_element]

def get_apiv2_elements(self) -> list[api_element]:
return self.apiv2_elements


@dataclass
class ManyToOneMapping(Mapping):
apiv1_elements: list[api_element]
apiv2_element: api_element

def get_apiv1_elements(self) -> list[api_element]:
return self.apiv1_elements

def get_apiv2_elements(self) -> list[api_element]:
return [self.apiv2_element]


@dataclass
class ManyToManyMapping(Mapping):
apiv1_elements: list[api_element]
apiv2_elements: list[api_element]

def get_apiv1_elements(self) -> list[api_element]:
return self.apiv1_elements

def get_apiv2_elements(self) -> list[api_element]:
return self.apiv2_elements


def merge_mappings(mapping_a: Mapping, mapping_b: Mapping) -> Mapping:
similarity = (mapping_a.similarity + mapping_b.similarity) / 2
codomain: list[api_element] = list(
set(mapping_a.get_apiv2_elements()) | set(mapping_b.get_apiv2_elements())
)
domain: list[api_element] = list(
set(mapping_a.get_apiv1_elements()) | set(mapping_b.get_apiv1_elements())
)
if len(domain) == 1 and len(codomain) == 1:
return OneToOneMapping(similarity, domain[0], codomain[0])
if len(domain) == 1:
return OneToManyMapping(similarity, domain[0], codomain)
if len(codomain) == 1:
return ManyToOneMapping(similarity, domain, codomain[0])
return ManyToManyMapping(similarity, domain, codomain)


class APIMapping:
threshold_of_similarity_between_mappings: float
threshold_of_similarity_for_creation_of_mappings: float
apiv1: API
apiv2: API
differ: AbstractDiffer

def __init__(
self,
apiv1: API,
apiv2: API,
differ: AbstractDiffer,
threshold_of_similarity_for_creation_of_mappings=0.5,
threshold_of_similarity_between_mappings=0.05,
):
self.apiv1 = apiv1
self.apiv2 = apiv2
self.differ = differ
self.threshold_of_similarity_for_creation_of_mappings = (
threshold_of_similarity_for_creation_of_mappings
)
self.threshold_of_similarity_between_mappings = (
threshold_of_similarity_between_mappings
)

def _get_mappings_for_api_elements(
self,
api_elementv1_list: List[API_ELEMENTS],
api_elementv2_list: List[API_ELEMENTS],
compute_similarity: Callable[[API_ELEMENTS, API_ELEMENTS], float],
) -> list[Mapping]:
element_mappings: list[Mapping] = []
for api_elementv1 in api_elementv1_list:
mapping_for_class_1: list[Mapping] = []
for api_elementv2 in api_elementv2_list:
similarity = compute_similarity(api_elementv1, api_elementv2)
if similarity >= self.threshold_of_similarity_for_creation_of_mappings:
mapping_for_class_1.append(
OneToOneMapping(similarity, api_elementv1, api_elementv2)
)
mapping_for_class_1.sort(key=Mapping.get_similarity, reverse=True)
new_mapping = self._merge_similar_mappings(mapping_for_class_1)
if new_mapping is not None:
self._merge_mappings_with_same_elements(new_mapping, element_mappings)
return element_mappings

def map_api(self) -> List[Mapping]:
mappings: List[Mapping] = []
mappings.extend(
self._get_mappings_for_api_elements(
list(self.apiv1.classes.values()),
list(self.apiv2.classes.values()),
self.differ.compute_class_similarity,
)
)
mappings.extend(
self._get_mappings_for_api_elements(
list(self.apiv1.functions.values()),
list(self.apiv2.functions.values()),
self.differ.compute_function_similarity,
)
)
mappings.extend(
self._get_mappings_for_api_elements(
list(self.apiv1.parameters().values()),
list(self.apiv2.parameters().values()),
self.differ.compute_parameter_similarity,
)
)

mappings.extend(
self._get_mappings_for_api_elements(
[
attribute
for class_ in self.apiv1.classes.values()
for attribute in class_.instance_attributes
],
[
attribute
for class_ in self.apiv2.classes.values()
for attribute in class_.instance_attributes
],
self.differ.compute_attribute_similarity,
)
)

mappings.extend(
self._get_mappings_for_api_elements(
[
result
for function in self.apiv1.functions.values()
for result in function.results
],
[
result
for function in self.apiv2.functions.values()
for result in function.results
],
self.differ.compute_result_similarity,
)
)

mappings.sort(key=Mapping.get_similarity, reverse=True)
return mappings

def _merge_similar_mappings(self, mappings: List[Mapping]) -> Optional[Mapping]:
"""
Given a list of OneToOne(Many)Mappings which apiv1 element is the same, this method returns the best mapping
from this apiv1 element to apiv2 elements by merging the first and second elements recursively,
if the difference in similarity is smaller than THRESHOLD_OF_SIMILARITY_BETWEEN_MAPPINGS.

:param mappings: mappings sorted by decreasing similarity, which apiv1 element is the same
:return: the first element of the sorted list that could be a result of merged similar mappings
"""
if len(mappings) == 0:
return None
if len(mappings) == 1:
return mappings[0]
if (
mappings[0].similarity - mappings[1].similarity
< self.threshold_of_similarity_between_mappings
):
mappings[0] = merge_mappings(mappings[0], mappings[1])
mappings.pop(1)
return self._merge_similar_mappings(mappings)
return mappings[0]

def _merge_mappings_with_same_elements(
self, mapping_to_be_appended: Mapping, mappings: list[Mapping]
):
"""
This method prevents that an element in a mapping appears multiple times in a list of mappings
by merging the affected mappings and include the result in the list. If there is no such element,
the mapping will be included without any merge.

:param mapping_to_be_appended: the mapping that should be included in mappings
:param mappings: the list, in which mapping_to_be_appended should be appended
"""
duplicated: list[Mapping] = []
for mapping in mappings:
duplicated_element = False
for element in mapping.get_apiv2_elements():
for element_2 in mapping_to_be_appended.get_apiv2_elements():
if element == element_2:
duplicated_element = True
break
if duplicated_element:
duplicated.append(mapping)

if len(duplicated) == 0:
mappings.append(mapping_to_be_appended)
return

for conflicted_mapping in duplicated:
mapping_to_be_appended = merge_mappings(
mapping_to_be_appended, conflicted_mapping
)
mappings.remove(conflicted_mapping)

mappings.append(mapping_to_be_appended)
Loading