Files
cleveragents-core/features/steps/uko_layer3_vocabularies_steps.py
T
hamza.khyari 89eaee008d
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 19s
CI / build (pull_request) Successful in 27s
CI / quality (pull_request) Successful in 29s
CI / security (pull_request) Successful in 41s
CI / typecheck (pull_request) Successful in 45s
CI / e2e_tests (pull_request) Successful in 1m29s
CI / unit_tests (pull_request) Successful in 3m19s
CI / integration_tests (pull_request) Successful in 3m30s
CI / docker (pull_request) Successful in 54s
CI / coverage (pull_request) Successful in 6m8s
CI / benchmark-regression (pull_request) Successful in 38m9s
feat(acms): implement UKO Layer 3 Technology Vocabularies (uko-py, uko-ts, uko-rs, uko-java)
Implement Layer 3 technology-specific UKO vocabulary extensions for Python,
TypeScript, Rust, and Java with language-specific classes, properties, and
DetailLevelMap insertions.

- 4 OWL/Turtle ontology files with language-specific semantic classes
- DetailLevelMap insertion logic with correct integer reassignment
- Provenance contract (5 required fields per spec)
- Full 4-layer chain resolution (Layer 3 -> Layer 2 -> Layer 1 -> Layer 0)
- Comprehensive Behave test suite (63 scenarios)

ISSUES CLOSED: #576
2026-03-16 12:11:08 +00:00

529 lines
18 KiB
Python

"""Step definitions for UKO Layer 3 Technology Vocabularies -- base models and vocabs.
All steps use the suffix "for uko_l3" to avoid AmbiguousStep errors.
"""
from __future__ import annotations
from datetime import UTC, datetime
from typing import Any
from behave import given, then
from pydantic import ValidationError
from cleveragents.acms.uko.layer3_java import JAVA_VOCABULARY, JavaClass
from cleveragents.acms.uko.layer3_py import (
PYTHON_VOCABULARY,
PythonClass,
)
from cleveragents.acms.uko.layer3_rs import RUST_VOCABULARY, RustStruct
from cleveragents.acms.uko.layer3_ts import TYPESCRIPT_VOCABULARY, TypeScriptClass
from cleveragents.acms.uko.vocabulary import (
Layer2Dependency,
ProvenanceInfo,
UKOClass,
UKOProperty,
UKOVocabulary,
)
__all__: list[str] = []
# -- ProvenanceInfo steps --
@given('a provenance info with resource "{resource}" and path "{path}" for uko_l3')
def step_given_provenance_info(context: Any, resource: str, path: str) -> None:
context.provenance = ProvenanceInfo(
source_resource=resource,
source_path=path,
)
@given(
'a ranged provenance info with resource "{resource}" and path '
'"{path}" and range "{source_range}" for uko_l3'
)
def step_given_provenance_info_with_range(
context: Any, resource: str, path: str, source_range: str
) -> None:
context.provenance = ProvenanceInfo(
source_resource=resource,
source_path=path,
source_range=source_range,
)
@then('the provenance source_resource should be "{expected}" for uko_l3')
def step_then_provenance_resource(context: Any, expected: str) -> None:
assert context.provenance.source_resource == expected
@then('the provenance source_path should be "{expected}" for uko_l3')
def step_then_provenance_path(context: Any, expected: str) -> None:
assert context.provenance.source_path == expected
@then("the provenance is_current should be true for uko_l3")
def step_then_provenance_is_current(context: Any) -> None:
assert context.provenance.is_current is True
@then("the provenance valid_from should be a UTC datetime for uko_l3")
def step_then_provenance_valid_from_utc(context: Any) -> None:
vf = context.provenance.valid_from
assert isinstance(vf, datetime)
assert vf.tzinfo is not None
assert vf.tzinfo == UTC
@then('the provenance source_range should be "{expected}" for uko_l3')
def step_then_provenance_source_range(context: Any, expected: str) -> None:
assert context.provenance.source_range == expected
@then(
"creating a provenance info with empty source_resource "
"should raise ValueError for uko_l3"
)
def step_then_provenance_empty_resource(context: Any) -> None:
try:
ProvenanceInfo(source_resource="", source_path="some.py")
msg = "Expected ValueError"
raise AssertionError(msg)
except ValueError:
pass
@then(
"creating a provenance info with whitespace source_resource "
"should raise ValueError for uko_l3"
)
def step_then_provenance_whitespace_resource(context: Any) -> None:
try:
ProvenanceInfo(source_resource=" ", source_path="some.py")
msg = "Expected ValueError"
raise AssertionError(msg)
except ValueError:
pass
@then(
"creating a provenance info with empty source_path "
"should raise ValueError for uko_l3"
)
def step_then_provenance_empty_path(context: Any) -> None:
try:
ProvenanceInfo(source_resource="res-01", source_path="")
msg = "Expected ValueError"
raise AssertionError(msg)
except ValueError:
pass
@then(
"creating a provenance info with whitespace source_path "
"should raise ValueError for uko_l3"
)
def step_then_provenance_whitespace_path(context: Any) -> None:
try:
ProvenanceInfo(source_resource="res-01", source_path=" ")
msg = "Expected ValueError"
raise AssertionError(msg)
except ValueError:
pass
@then("modifying provenance is_current should raise an error for uko_l3")
def step_then_provenance_immutable(context: Any) -> None:
try:
context.provenance.is_current = False
msg = "Expected immutability error"
raise AssertionError(msg)
except (TypeError, AttributeError, ValidationError):
pass
# -- UKOClass steps --
@given('a UKO class with uri "{uri}" and label "{label}" for uko_l3')
def step_given_uko_class(context: Any, uri: str, label: str) -> None:
context.uko_class = UKOClass(uri=uri, label=label)
@then('the UKO class uri should be "{expected}" for uko_l3')
def step_then_uko_class_uri(context: Any, expected: str) -> None:
assert context.uko_class.uri == expected
@then('the UKO class label should be "{expected}" for uko_l3')
def step_then_uko_class_label(context: Any, expected: str) -> None:
assert context.uko_class.label == expected
@then("the UKO class subclass_of should be empty for uko_l3")
def step_then_uko_class_subclass_empty(context: Any) -> None:
assert context.uko_class.subclass_of == ()
@then("creating a UKO class with empty uri should raise ValueError for uko_l3")
def step_then_uko_class_empty_uri(context: Any) -> None:
try:
UKOClass(uri="", label="X")
msg = "Expected ValueError"
raise AssertionError(msg)
except ValueError:
pass
@then("creating a UKO class with whitespace label should raise ValueError for uko_l3")
def step_then_uko_class_whitespace_label(context: Any) -> None:
try:
UKOClass(uri="https://example.com/X", label=" ")
msg = "Expected ValueError"
raise AssertionError(msg)
except ValueError:
pass
@then("modifying UKO class label should raise an error for uko_l3")
def step_then_uko_class_immutable(context: Any) -> None:
try:
context.uko_class.label = "mutated"
msg = "Expected immutability error"
raise AssertionError(msg)
except (TypeError, AttributeError, ValidationError):
pass
# -- UKOClass provenance steps --
@given('a UKO class with provenance resource "{resource}" and path "{path}" for uko_l3')
def step_given_uko_class_with_provenance(
context: Any, resource: str, path: str
) -> None:
context.uko_class = UKOClass(
uri="https://example.com/WithProv",
label="WithProv",
provenance=ProvenanceInfo(
source_resource=resource,
source_path=path,
),
)
@then('the UKO class provenance source_resource should be "{expected}" for uko_l3')
def step_then_uko_class_prov_resource(context: Any, expected: str) -> None:
assert context.uko_class.provenance is not None
assert context.uko_class.provenance.source_resource == expected
@then('the UKO class provenance source_path should be "{expected}" for uko_l3')
def step_then_uko_class_prov_path(context: Any, expected: str) -> None:
assert context.uko_class.provenance is not None
assert context.uko_class.provenance.source_path == expected
@then("the UKO class provenance should be None for uko_l3")
def step_then_uko_class_prov_none(context: Any) -> None:
assert context.uko_class.provenance is None
# -- UKOProperty steps --
@given('a UKO property with uri "{uri}" and label "{label}" for uko_l3')
def step_given_uko_property(context: Any, uri: str, label: str) -> None:
context.uko_property = UKOProperty(uri=uri, label=label)
@then('the UKO property uri should be "{expected}" for uko_l3')
def step_then_uko_property_uri(context: Any, expected: str) -> None:
assert context.uko_property.uri == expected
@then("the UKO property is_object_property should be true for uko_l3")
def step_then_uko_property_is_object(context: Any) -> None:
assert context.uko_property.is_object_property is True
@then("creating a UKO property with empty uri should raise ValueError for uko_l3")
def step_then_uko_property_empty_uri(context: Any) -> None:
try:
UKOProperty(uri="", label="X")
msg = "Expected ValueError"
raise AssertionError(msg)
except ValueError:
pass
# -- Layer2Dependency steps --
@given('a layer2 dependency with uri "{uri}" and prefix "{prefix}" for uko_l3')
def step_given_layer2_dep(context: Any, uri: str, prefix: str) -> None:
context.layer2_dep = Layer2Dependency(uri=uri, prefix=prefix)
@then("the layer2 dependency layer should be {expected:d} for uko_l3")
def step_then_layer2_dep_layer(context: Any, expected: int) -> None:
assert context.layer2_dep.layer == expected
@then('the layer2 dependency prefix should be "{expected}" for uko_l3')
def step_then_layer2_dep_prefix(context: Any, expected: str) -> None:
assert context.layer2_dep.prefix == expected
# -- UKOVocabulary steps --
@given(
'a UKO vocabulary with namespace "{ns}" and prefix "{prefix}" '
'and label "{label}" for uko_l3'
)
def step_given_uko_vocab(context: Any, ns: str, prefix: str, label: str) -> None:
context.uko_vocab = UKOVocabulary(namespace=ns, prefix=prefix, label=label)
@then("the vocabulary layer should be {expected:d} for uko_l3")
def step_then_vocab_layer(context: Any, expected: int) -> None:
assert context.uko_vocab.layer == expected
@then('the vocabulary prefix should be "{expected}" for uko_l3')
def step_then_vocab_prefix(context: Any, expected: str) -> None:
assert context.uko_vocab.prefix == expected
# -- Python vocabulary steps --
@then('the Python vocabulary namespace should be "{expected}" for uko_l3')
def step_then_py_namespace(context: Any, expected: str) -> None:
assert PYTHON_VOCABULARY.namespace == expected
@then('the Python vocabulary prefix should be "{expected}" for uko_l3')
def step_then_py_prefix(context: Any, expected: str) -> None:
assert PYTHON_VOCABULARY.prefix == expected
@then("the Python vocabulary layer should be {expected:d} for uko_l3")
def step_then_py_layer(context: Any, expected: int) -> None:
assert PYTHON_VOCABULARY.layer == expected
@then("the Python vocabulary should have {count:d} classes for uko_l3")
def step_then_py_class_count(context: Any, count: int) -> None:
assert len(PYTHON_VOCABULARY.classes) == count
@then('the Python vocabulary should contain class "{name}" for uko_l3')
def step_then_py_has_class(context: Any, name: str) -> None:
labels = tuple(c.label for c in PYTHON_VOCABULARY.classes)
assert name in labels, f"{name!r} not in {labels}"
@then("the Python vocabulary should have {count:d} properties for uko_l3")
def step_then_py_property_count(context: Any, count: int) -> None:
assert len(PYTHON_VOCABULARY.properties) == count
@then('the Python vocabulary should contain property "{name}" for uko_l3')
def step_then_py_has_property(context: Any, name: str) -> None:
labels = tuple(p.label for p in PYTHON_VOCABULARY.properties)
assert name in labels, f"{name!r} not in {labels}"
@then('the Python vocabulary parent_prefixes should contain "{prefix}" for uko_l3')
def step_then_py_parent_prefix(context: Any, prefix: str) -> None:
assert prefix in PYTHON_VOCABULARY.parent_prefixes
@then('the PythonClass subclass_of should contain "{uri}" for uko_l3')
def step_then_python_class_subclass(context: Any, uri: str) -> None:
assert uri in PythonClass.subclass_of, f"{uri!r} not in {PythonClass.subclass_of}"
@then("the Python vocabulary should have {count:d} inserted levels for uko_l3")
def step_then_py_inserted_count(context: Any, count: int) -> None:
assert len(PYTHON_VOCABULARY.inserted_levels) == count
@then('the Python vocabulary inserted levels should include "{name}" for uko_l3')
def step_then_py_inserted_name(context: Any, name: str) -> None:
names = tuple(n for n, _ in PYTHON_VOCABULARY.inserted_levels)
assert name in names, f"{name!r} not in {names}"
# -- TypeScript vocabulary steps --
@then('the TypeScript vocabulary namespace should be "{expected}" for uko_l3')
def step_then_ts_namespace(context: Any, expected: str) -> None:
assert TYPESCRIPT_VOCABULARY.namespace == expected
@then('the TypeScript vocabulary prefix should be "{expected}" for uko_l3')
def step_then_ts_prefix(context: Any, expected: str) -> None:
assert TYPESCRIPT_VOCABULARY.prefix == expected
@then("the TypeScript vocabulary layer should be {expected:d} for uko_l3")
def step_then_ts_layer(context: Any, expected: int) -> None:
assert TYPESCRIPT_VOCABULARY.layer == expected
@then("the TypeScript vocabulary should have {count:d} classes for uko_l3")
def step_then_ts_class_count(context: Any, count: int) -> None:
assert len(TYPESCRIPT_VOCABULARY.classes) == count
@then('the TypeScript vocabulary should contain class "{name}" for uko_l3')
def step_then_ts_has_class(context: Any, name: str) -> None:
labels = tuple(c.label for c in TYPESCRIPT_VOCABULARY.classes)
assert name in labels, f"{name!r} not in {labels}"
@then("the TypeScript vocabulary should have {count:d} properties for uko_l3")
def step_then_ts_property_count(context: Any, count: int) -> None:
assert len(TYPESCRIPT_VOCABULARY.properties) == count
@then('the TypeScript vocabulary should contain property "{name}" for uko_l3')
def step_then_ts_has_property(context: Any, name: str) -> None:
labels = tuple(p.label for p in TYPESCRIPT_VOCABULARY.properties)
assert name in labels, f"{name!r} not in {labels}"
@then('the TypeScript vocabulary parent_prefixes should contain "{prefix}" for uko_l3')
def step_then_ts_parent_prefix(context: Any, prefix: str) -> None:
assert prefix in TYPESCRIPT_VOCABULARY.parent_prefixes
@then("the TypeScript vocabulary should have {count:d} inserted levels for uko_l3")
def step_then_ts_inserted_count(context: Any, count: int) -> None:
assert len(TYPESCRIPT_VOCABULARY.inserted_levels) == count
# -- Rust vocabulary steps --
@then('the Rust vocabulary namespace should be "{expected}" for uko_l3')
def step_then_rs_namespace(context: Any, expected: str) -> None:
assert RUST_VOCABULARY.namespace == expected
@then('the Rust vocabulary prefix should be "{expected}" for uko_l3')
def step_then_rs_prefix(context: Any, expected: str) -> None:
assert RUST_VOCABULARY.prefix == expected
@then("the Rust vocabulary layer should be {expected:d} for uko_l3")
def step_then_rs_layer(context: Any, expected: int) -> None:
assert RUST_VOCABULARY.layer == expected
@then("the Rust vocabulary should have {count:d} classes for uko_l3")
def step_then_rs_class_count(context: Any, count: int) -> None:
assert len(RUST_VOCABULARY.classes) == count
@then('the Rust vocabulary should contain class "{name}" for uko_l3')
def step_then_rs_has_class(context: Any, name: str) -> None:
labels = tuple(c.label for c in RUST_VOCABULARY.classes)
assert name in labels, f"{name!r} not in {labels}"
@then("the Rust vocabulary should have {count:d} properties for uko_l3")
def step_then_rs_property_count(context: Any, count: int) -> None:
assert len(RUST_VOCABULARY.properties) == count
@then('the Rust vocabulary should contain property "{name}" for uko_l3')
def step_then_rs_has_property(context: Any, name: str) -> None:
labels = tuple(p.label for p in RUST_VOCABULARY.properties)
assert name in labels, f"{name!r} not in {labels}"
@then('the Rust vocabulary parent_prefixes should contain "{prefix}" for uko_l3')
def step_then_rs_parent_prefix(context: Any, prefix: str) -> None:
assert prefix in RUST_VOCABULARY.parent_prefixes
@then("the Rust vocabulary should have {count:d} inserted levels for uko_l3")
def step_then_rs_inserted_count(context: Any, count: int) -> None:
assert len(RUST_VOCABULARY.inserted_levels) == count
@then('the RustStruct subclass_of should contain "{uri}" for uko_l3')
def step_then_rs_struct_subclass(context: Any, uri: str) -> None:
assert uri in RustStruct.subclass_of, f"{uri!r} not in {RustStruct.subclass_of}"
# -- Java vocabulary steps --
@then('the Java vocabulary namespace should be "{expected}" for uko_l3')
def step_then_java_namespace(context: Any, expected: str) -> None:
assert JAVA_VOCABULARY.namespace == expected
@then('the Java vocabulary prefix should be "{expected}" for uko_l3')
def step_then_java_prefix(context: Any, expected: str) -> None:
assert JAVA_VOCABULARY.prefix == expected
@then("the Java vocabulary layer should be {expected:d} for uko_l3")
def step_then_java_layer(context: Any, expected: int) -> None:
assert JAVA_VOCABULARY.layer == expected
@then("the Java vocabulary should have {count:d} classes for uko_l3")
def step_then_java_class_count(context: Any, count: int) -> None:
assert len(JAVA_VOCABULARY.classes) == count
@then('the Java vocabulary should contain class "{name}" for uko_l3')
def step_then_java_has_class(context: Any, name: str) -> None:
labels = tuple(c.label for c in JAVA_VOCABULARY.classes)
assert name in labels, f"{name!r} not in {labels}"
@then("the Java vocabulary should have {count:d} properties for uko_l3")
def step_then_java_property_count(context: Any, count: int) -> None:
assert len(JAVA_VOCABULARY.properties) == count
@then('the Java vocabulary should contain property "{name}" for uko_l3')
def step_then_java_has_property(context: Any, name: str) -> None:
labels = tuple(p.label for p in JAVA_VOCABULARY.properties)
assert name in labels, f"{name!r} not in {labels}"
@then('the Java vocabulary parent_prefixes should contain "{prefix}" for uko_l3')
def step_then_java_parent_prefix(context: Any, prefix: str) -> None:
assert prefix in JAVA_VOCABULARY.parent_prefixes
@then("the Java vocabulary should have {count:d} inserted levels for uko_l3")
def step_then_java_inserted_count(context: Any, count: int) -> None:
assert len(JAVA_VOCABULARY.inserted_levels) == count
@then('the JavaClass subclass_of should contain "{uri}" for uko_l3')
def step_then_java_class_subclass(context: Any, uri: str) -> None:
assert uri in JavaClass.subclass_of, f"{uri!r} not in {JavaClass.subclass_of}"
# -- TypeScript subclass_of step --
@then('the TypeScriptClass subclass_of should contain "{uri}" for uko_l3')
def step_then_ts_class_subclass(context: Any, uri: str) -> None:
assert uri in TypeScriptClass.subclass_of, (
f"{uri!r} not in {TypeScriptClass.subclass_of}"
)