Skip to content

Commit

Permalink
feat: Implement modelling rules and validation
Browse files Browse the repository at this point in the history
Note that this feature is distinct from the "Validate Model" option in
the Capella GUI. Validation in capellambse uses its own custom set of
rules.

Also note that this is only an initial version, which still has a lot of
limitations. In future iterations, the applied ruleset may be extended,
modified, or made more configurable from a user's perspective.

Co-authored-by: Ernst Würger <ernst.wuerger@deutschebahn.com>
Co-authored-by: Martin Lehmann <martin.lehmann@deutschebahn.com>
Co-authored-by: Viktor Kravchenko <viktor.kravchenko@deutschebahn.com>
  • Loading branch information
4 people committed Jun 6, 2024
1 parent 610da1b commit add991f
Show file tree
Hide file tree
Showing 10 changed files with 1,469 additions and 1 deletion.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ repos:
- mypy==1.10.0
- click==8.1.7
- diskcache==5.0
- jinja2==3.1.3
- markupsafe==2.0
- platformdirs==4.2.0
- pytest-cov
Expand Down
37 changes: 37 additions & 0 deletions capellambse/extensions/validation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: Copyright DB InfraGO AG
# SPDX-License-Identifier: Apache-2.0
"""The module provides management and evaluation of validation rules.
Validation rules are conditions ensuring that specific modeling
guidelines are followed. These rules apply to particular types of model
elements or to diagrams, and values of metrics. By evaluating each rule,
the module generates validation results, indicating whether the
corresponding guideline has been satisfied or not. This way, the module
helps maintain the quality and consistency of the model.
"""

from ._validate import *

from . import rules # isort: skip


def init() -> None:
# pylint: disable=redefined-outer-name # false-positive
import capellambse
from capellambse.model import common as c

c.set_accessor(
capellambse.MelodyModel,
"validation",
c.AlternateAccessor(ModelValidation),
)
capellambse.MelodyModel.validate = property( # type: ignore[attr-defined]
lambda self: self.validation.validate
)

c.set_accessor(
c.GenericElement, "validation", c.AlternateAccessor(ElementValidation)
)
c.GenericElement.validate = property( # type: ignore[attr-defined]
lambda self: self.validation.validate
)
47 changes: 47 additions & 0 deletions capellambse/extensions/validation/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# SPDX-FileCopyrightText: Copyright DB InfraGO AG
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations

import logging
import typing as t

import click
import jinja2

import capellambse


@click.command()
@click.option("-m", "--model", required=True, type=capellambse.ModelCLI())
@click.option(
"-o",
"--output",
type=click.File("w", atomic=True),
required=True,
help="Output file to render the template into",
)
@click.option("-t", "--template", help="An optional custom template to render")
def _main(
model: capellambse.MelodyModel,
template: str | None,
output: t.IO[str],
) -> None:
logging.basicConfig()

loader: jinja2.BaseLoader
if template is None:
loader = jinja2.PackageLoader("capellambse", "extensions/validation")
template = "report-template.html.jinja"
else:
loader = jinja2.FileSystemLoader(".")
env = jinja2.Environment(loader=loader)

with output:
env.get_template(template).stream(
model=model,
results=model.validation.validate(),
).dump(output)


if __name__ == "__main__":
_main()
Loading

0 comments on commit add991f

Please sign in to comment.