Skip to content

Commit

Permalink
feat!: Upgrade to capellambse v0.6.x
Browse files Browse the repository at this point in the history
  • Loading branch information
Wuestengecko committed Aug 12, 2024
1 parent d1e4a7c commit 0a53a90
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 27 deletions.
18 changes: 11 additions & 7 deletions capella_diff_tools/__main__.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
# Copyright DB Netz AG and contributors
# SPDX-License-Identifier: Apache-2.0
"""Main entry point into capella_diff_tools."""

from __future__ import annotations

import datetime
import logging
import os
import pathlib
import sys
import typing as t

import capellambse
import capellambse.filehandler.git
import capellambse.model as m
import click
import markupsafe
import yaml
from capellambse import filehandler as fh
from capellambse.model import common as c

import capella_diff_tools

from . import compare, report, types

logger = logging.getLogger(__name__)

_T = t.TypeVar("_T", bound=c.GenericElement)
_T = t.TypeVar("_T", bound=m.GenericElement)


@click.command()
Expand All @@ -32,7 +34,7 @@
prog_name="Capella Diff Tools",
message="%(prog)s %(version)s",
)
@click.argument("model", type=capellambse.cli_helpers.ModelInfoCLI())
@click.argument("model", type=capellambse.ModelInfoCLI())
@click.argument("old_version")
@click.argument("new_version")
@click.option(
Expand Down Expand Up @@ -91,7 +93,7 @@ def main(
report_file.write(report.generate_html(result))


def _ensure_git(path: str | pathlib.Path) -> str:
def _ensure_git(path: str | os.PathLike[str]) -> str:
proto, path = fh.split_protocol(path)
if proto == "file":
assert isinstance(path, pathlib.Path)
Expand All @@ -112,17 +114,19 @@ def _get_revision_info(
"""Return the revision info of the given model."""
info = model.info
res = model._loader.resources["\x00"]
resinfo = info.resources["\x00"]
assert isinstance(res, fh.git.GitFileHandler)
assert isinstance(resinfo, fh.git.GitHandlerInfo)
assert t.assert_type(resinfo.rev_hash, str) is not None
author, date_str, description = res._git(
"log",
"-1",
"--format=%aN%x00%aI%x00%B",
info.rev_hash,
resinfo.rev_hash,
encoding="utf-8",
).split("\x00")
assert info.rev_hash is not None
return {
"hash": info.rev_hash,
"hash": resinfo.rev_hash,
"revision": revision,
"author": author,
"date": datetime.datetime.fromisoformat(date_str),
Expand Down
37 changes: 18 additions & 19 deletions capella_diff_tools/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@

import capellambse
import capellambse.model as m
import capellambse.model.common as c

from . import types

logger = logging.getLogger(__name__)

_T = t.TypeVar("_T", bound=c.GenericElement)
_T = t.TypeVar("_T", bound=m.GenericElement)


def compare_all_diagrams(
Expand Down Expand Up @@ -71,7 +70,7 @@ def _compare_diagrams_on_layer(


def _diag2dict(
obj: m.diagram.Diagram | c.GenericElement,
obj: m.diagram.Diagram | m.GenericElement,
) -> types.FullDiagram:
"""Serialize a diagram element into a dict.
Expand Down Expand Up @@ -148,25 +147,25 @@ def compare_all_objects(

def _group_all_objects(
model: capellambse.MelodyModel,
) -> dict[str, dict[str, c.ElementList[c.GenericElement]]]:
) -> dict[str, dict[str, m.ElementList[m.GenericElement]]]:
"""Return a dict of all objects, grouped by layer."""
result: dict[str, dict[str, c.ElementList[c.GenericElement]]]
result: dict[str, dict[str, m.ElementList[m.GenericElement]]]
result = {"oa": {}, "sa": {}, "la": {}, "pa": {}}
for layer, objs in result.items():
ungrouped = sorted(
model.search(below=getattr(model, layer)),
key=lambda i: type(i).__name__,
)
for objtype, group in itertools.groupby(ungrouped, key=type):
objs[objtype.__name__] = c.ElementList(
objs[objtype.__name__] = m.ElementList(
model, [i._element for i in group], objtype
)
return result


def _compare_object_type(
old: c.ElementList[_T],
new: c.ElementList[_T],
old: m.ElementList[_T],
new: m.ElementList[_T],
) -> types.ObjectChange:
changes: types.ObjectChange = {}

Expand All @@ -188,7 +187,7 @@ def _compare_object_type(
return changes


def _obj2dict(obj: c.GenericElement) -> types.FullObject:
def _obj2dict(obj: m.GenericElement) -> types.FullObject:
"""Serialize a model object into a dict.
This function is used for objects that were either created or
Expand All @@ -197,7 +196,7 @@ def _obj2dict(obj: c.GenericElement) -> types.FullObject:
attributes: dict[str, t.Any] = {}
for attr in dir(type(obj)):
acc = getattr(type(obj), attr, None)
if isinstance(acc, c.AttributeProperty):
if isinstance(acc, m.BasePOD):
val = getattr(obj, attr)
if val is None:
continue
Expand All @@ -210,7 +209,7 @@ def _obj2dict(obj: c.GenericElement) -> types.FullObject:


def _obj2diff(
old: c.GenericElement, new: c.GenericElement
old: m.GenericElement, new: m.GenericElement
) -> types.ChangedObject | None:
"""Serialize the differences between the old and new object.
Expand All @@ -224,7 +223,7 @@ def _obj2diff(
for attr in dir(type(old)):
if not isinstance(
getattr(type(old), attr, None),
(c.AttributeProperty, c.AttrProxyAccessor, c.LinkAccessor),
(m.BasePOD, m.AttrProxyAccessor, m.LinkAccessor),
):
continue

Expand Down Expand Up @@ -259,16 +258,16 @@ def _obj2diff(
else:
raise

if isinstance(old_val, c.GenericElement) and isinstance(
new_val, c.GenericElement
if isinstance(old_val, m.GenericElement) and isinstance(
new_val, m.GenericElement
):
if old_val.uuid != new_val.uuid:
attributes[attr] = {
"previous": _serialize_obj(old_val),
"current": _serialize_obj(new_val),
}
elif isinstance(old_val, c.ElementList) and isinstance(
new_val, c.ElementList
elif isinstance(old_val, m.ElementList) and isinstance(
new_val, m.ElementList
):
if [i.uuid for i in old_val] != [i.uuid for i in new_val]:
attributes[attr] = {
Expand All @@ -291,16 +290,16 @@ def _obj2diff(


def _serialize_obj(obj: t.Any) -> t.Any:
if isinstance(obj, c.GenericElement):
if isinstance(obj, m.GenericElement):
return {"uuid": obj.uuid, "display_name": _get_name(obj)}
elif isinstance(obj, c.ElementList):
elif isinstance(obj, m.ElementList):
return [{"uuid": i.uuid, "display_name": _get_name(i)} for i in obj]
elif isinstance(obj, (enum.Enum, enum.Flag)):
return obj.name
return obj


def _get_name(obj: m.diagram.Diagram | c.GenericElement) -> str:
def _get_name(obj: m.diagram.Diagram | m.GenericElement) -> str:
"""Return the object's name.
If the object doesn't own a name, its type is returned instead.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
]
dependencies = [
"capellambse>=0.5.39,<0.6",
"capellambse>=0.6.2,<0.7",
"click",
"diff-match-patch>=20230430",
"jinja2>=3.1.2",
Expand Down

0 comments on commit 0a53a90

Please sign in to comment.