diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e276aef..5bd2077 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -50,6 +50,7 @@ repos: hooks: - id: mypy additional_dependencies: + - capellambse==0.6.2 - types-pyyaml - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.5.4 diff --git a/capella_diff_tools/__main__.py b/capella_diff_tools/__main__.py index 3fc66b5..8936c9f 100644 --- a/capella_diff_tools/__main__.py +++ b/capella_diff_tools/__main__.py @@ -1,21 +1,23 @@ # 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 @@ -23,7 +25,7 @@ logger = logging.getLogger(__name__) -_T = t.TypeVar("_T", bound=c.GenericElement) +_T = t.TypeVar("_T", bound=m.GenericElement) @click.command() @@ -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( @@ -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) @@ -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), diff --git a/capella_diff_tools/compare.py b/capella_diff_tools/compare.py index 8824268..da6351e 100644 --- a/capella_diff_tools/compare.py +++ b/capella_diff_tools/compare.py @@ -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( @@ -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. @@ -148,9 +147,9 @@ 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( @@ -158,15 +157,15 @@ def _group_all_objects( 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 = {} @@ -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 @@ -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 @@ -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. @@ -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 @@ -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] = { @@ -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. diff --git a/pyproject.toml b/pyproject.toml index 83f7a21..f28e0d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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",