shared: implementazione package identity
Continuous Integration / Quality Assurance (push) Canceled after 0s
Continuous Integration / Quality Assurance (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# Normalize all text files to LF
|
||||
* text=auto eol=lf
|
||||
|
||||
# Python
|
||||
*.py text eol=lf
|
||||
|
||||
# Markdown
|
||||
*.md text eol=lf
|
||||
|
||||
# YAML
|
||||
*.yml text eol=lf
|
||||
*.yaml text eol=lf
|
||||
|
||||
# TOML
|
||||
*.toml text eol=lf
|
||||
|
||||
# JSON
|
||||
*.json text eol=lf
|
||||
|
||||
# Shell
|
||||
*.sh text eol=lf
|
||||
|
||||
# Windows scripts
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
|
||||
# Binary files
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.pdf binary
|
||||
@@ -56,6 +56,10 @@ dev = [
|
||||
[tool.setuptools]
|
||||
include-package-data = true
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
include = ["shared*", "core*", "api*", "modules*", "artifacts*"]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
line-length = 88
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
"""
|
||||
SMAVS Shared Kernel.
|
||||
|
||||
Provides shared components used across the framework.
|
||||
"""
|
||||
|
||||
__all__: list[str] = []
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
SMAVS Shared Kernel - Identity.
|
||||
|
||||
Provides the public interface for the identity package.
|
||||
"""
|
||||
|
||||
from shared.identity.artifact_id import ArtifactId
|
||||
from shared.identity.blueprint_id import BlueprintId
|
||||
from shared.identity.execution_id import ExecutionId
|
||||
from shared.identity.identifier import Identifier
|
||||
from shared.identity.module_id import ModuleId
|
||||
from shared.identity.request_id import RequestId
|
||||
from shared.identity.session_id import SessionId
|
||||
|
||||
__all__ = [
|
||||
"ArtifactId",
|
||||
"BlueprintId",
|
||||
"ExecutionId",
|
||||
"Identifier",
|
||||
"ModuleId",
|
||||
"RequestId",
|
||||
"SessionId",
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
SMAVS Shared Kernel - Artifact Identifier.
|
||||
|
||||
Defines the unique identifier for an Artifact.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from shared.identity.identifier import Identifier
|
||||
|
||||
__all__ = ["ArtifactId"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class ArtifactId(Identifier):
|
||||
"""
|
||||
Unique identifier of an Artifact.
|
||||
|
||||
This identifier is used to uniquely identify an Artifact
|
||||
within the SMAVS framework.
|
||||
"""
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
SMAVS Shared Kernel - Blueprint Identifier.
|
||||
|
||||
Defines the unique identifier for a Blueprint.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from shared.identity.identifier import Identifier
|
||||
|
||||
__all__ = ["BlueprintId"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class BlueprintId(Identifier):
|
||||
"""
|
||||
Unique identifier of a Blueprint.
|
||||
|
||||
This identifier is used to uniquely identify a Blueprint
|
||||
within the SMAVS framework.
|
||||
"""
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
SMAVS Shared Kernel - Execution Identifier.
|
||||
|
||||
Defines the unique identifier for an Execution.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from shared.identity.identifier import Identifier
|
||||
|
||||
__all__ = ["ExecutionId"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class ExecutionId(Identifier):
|
||||
"""
|
||||
Unique identifier of an Execution.
|
||||
|
||||
This identifier is used to uniquely identify an Execution
|
||||
within the SMAVS framework.
|
||||
"""
|
||||
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
SMAVS Shared Kernel - Identifier
|
||||
|
||||
Defines the base Value Object used to uniquely identify every
|
||||
domain element inside the framework.
|
||||
|
||||
All domain-specific identifiers inherit from this class.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
__all__ = ["Identifier"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Identifier:
|
||||
"""
|
||||
Base immutable identifier.
|
||||
|
||||
An Identifier represents the identity of a domain object.
|
||||
|
||||
Internally it stores a UUID while exposing a strongly typed
|
||||
Value Object to the rest of the domain.
|
||||
"""
|
||||
|
||||
value: UUID
|
||||
|
||||
@classmethod
|
||||
def new(cls) -> Identifier:
|
||||
"""
|
||||
Create a new identifier.
|
||||
|
||||
Returns:
|
||||
A newly generated identifier.
|
||||
"""
|
||||
return cls(uuid4())
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, value: str) -> Identifier:
|
||||
"""
|
||||
Create an identifier from its string representation.
|
||||
|
||||
Args:
|
||||
value:
|
||||
UUID string.
|
||||
|
||||
Returns:
|
||||
The corresponding identifier.
|
||||
|
||||
Raises:
|
||||
ValueError:
|
||||
If the provided string is not a valid UUID.
|
||||
"""
|
||||
return cls(UUID(value))
|
||||
|
||||
@classmethod
|
||||
def from_uuid(cls, value: UUID) -> Identifier:
|
||||
"""
|
||||
Create an identifier from an existing UUID.
|
||||
|
||||
Args:
|
||||
value:
|
||||
UUID instance.
|
||||
|
||||
Returns:
|
||||
The corresponding identifier.
|
||||
"""
|
||||
return cls(value)
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
Return the canonical string representation.
|
||||
"""
|
||||
return str(self.value)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Return the developer representation.
|
||||
"""
|
||||
return f"{self.__class__.__name__}('{self.value}')"
|
||||
|
||||
@property
|
||||
def hex(self) -> str:
|
||||
"""
|
||||
Return the hexadecimal representation.
|
||||
"""
|
||||
return self.value.hex
|
||||
|
||||
@property
|
||||
def urn(self) -> str:
|
||||
"""
|
||||
Return the UUID URN representation.
|
||||
"""
|
||||
return self.value.urn
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
SMAVS Shared Kernel - Module Identifier.
|
||||
|
||||
Defines the unique identifier for a Module.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from shared.identity.identifier import Identifier
|
||||
|
||||
__all__ = ["ModuleId"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class ModuleId(Identifier):
|
||||
"""
|
||||
Unique identifier of a Module.
|
||||
|
||||
This identifier is used to uniquely identify a Module
|
||||
within the SMAVS framework.
|
||||
"""
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
SMAVS Shared Kernel - Request Identifier.
|
||||
|
||||
Defines the unique identifier for a Request.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from shared.identity.identifier import Identifier
|
||||
|
||||
__all__ = ["RequestId"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class RequestId(Identifier):
|
||||
"""
|
||||
Unique identifier of a Request.
|
||||
|
||||
This identifier is used to uniquely identify a Request
|
||||
within the SMAVS framework.
|
||||
"""
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
SMAVS Shared Kernel - Session Identifier.
|
||||
|
||||
Defines the unique identifier for a Session.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from shared.identity.identifier import Identifier
|
||||
|
||||
__all__ = ["SessionId"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class SessionId(Identifier):
|
||||
"""
|
||||
Unique identifier of a Session.
|
||||
|
||||
This identifier is used to uniquely identify a Session
|
||||
within the SMAVS framework.
|
||||
"""
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Tests for the ArtifactId Value Object.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from shared.identity import ArtifactId, Identifier
|
||||
|
||||
|
||||
def test_new_creates_module_id() -> None:
|
||||
"""A new ArtifactId should be created."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ArtifactId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, ArtifactId)
|
||||
|
||||
|
||||
def test_module_id_is_identifier() -> None:
|
||||
"""ArtifactId should inherit from Identifier."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ArtifactId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, Identifier)
|
||||
|
||||
|
||||
def test_module_id_preserves_type() -> None:
|
||||
"""Factory methods should preserve the concrete type."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ArtifactId.new()
|
||||
|
||||
# Assert
|
||||
assert type(module_id) is ArtifactId
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Tests for the BlueprintId Value Object.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from shared.identity import BlueprintId, Identifier
|
||||
|
||||
|
||||
def test_new_creates_module_id() -> None:
|
||||
"""A new BlueprintId should be created."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = BlueprintId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, BlueprintId)
|
||||
|
||||
|
||||
def test_module_id_is_identifier() -> None:
|
||||
"""BlueprintId should inherit from Identifier."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = BlueprintId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, Identifier)
|
||||
|
||||
|
||||
def test_module_id_preserves_type() -> None:
|
||||
"""Factory methods should preserve the concrete type."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = BlueprintId.new()
|
||||
|
||||
# Assert
|
||||
assert type(module_id) is BlueprintId
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Tests for the ExecutionId Value Object.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from shared.identity import ExecutionId, Identifier
|
||||
|
||||
|
||||
def test_new_creates_module_id() -> None:
|
||||
"""A new ExecutionId should be created."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ExecutionId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, ExecutionId)
|
||||
|
||||
|
||||
def test_module_id_is_identifier() -> None:
|
||||
"""ExecutionId should inherit from Identifier."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ExecutionId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, Identifier)
|
||||
|
||||
|
||||
def test_module_id_preserves_type() -> None:
|
||||
"""Factory methods should preserve the concrete type."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ExecutionId.new()
|
||||
|
||||
# Assert
|
||||
assert type(module_id) is ExecutionId
|
||||
@@ -0,0 +1,158 @@
|
||||
"""
|
||||
Tests for the Identifier Value Object.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import FrozenInstanceError
|
||||
from uuid import UUID
|
||||
|
||||
import pytest
|
||||
|
||||
from shared.identity import Identifier
|
||||
|
||||
|
||||
def test_new_creates_identifier() -> None:
|
||||
"""A new identifier should contain a valid UUID."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
identifier = Identifier.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(identifier.value, UUID)
|
||||
|
||||
|
||||
def test_from_string_creates_identifier() -> None:
|
||||
"""An identifier can be created from a UUID string."""
|
||||
|
||||
# Arrange
|
||||
value = "550e8400-e29b-41d4-a716-446655440000"
|
||||
|
||||
# Act
|
||||
identifier = Identifier.from_string(value)
|
||||
|
||||
# Assert
|
||||
assert identifier.value == UUID(value)
|
||||
|
||||
|
||||
def test_from_uuid_creates_identifier() -> None:
|
||||
"""An identifier can be created from an existing UUID."""
|
||||
|
||||
# Arrange
|
||||
value = UUID("550e8400-e29b-41d4-a716-446655440000")
|
||||
|
||||
# Act
|
||||
identifier = Identifier.from_uuid(value)
|
||||
|
||||
# Assert
|
||||
assert identifier.value == value
|
||||
|
||||
|
||||
def test_from_string_raises_for_invalid_uuid() -> None:
|
||||
"""Creating an identifier from an invalid UUID should fail."""
|
||||
|
||||
# Arrange
|
||||
value = "invalid-uuid"
|
||||
|
||||
# Act / Assert
|
||||
with pytest.raises(ValueError):
|
||||
Identifier.from_string(value)
|
||||
|
||||
|
||||
def test_identifiers_with_same_value_are_equal() -> None:
|
||||
"""Identifiers with the same UUID should be equal."""
|
||||
|
||||
# Arrange
|
||||
value = UUID("550e8400-e29b-41d4-a716-446655440000")
|
||||
|
||||
# Act
|
||||
first = Identifier.from_uuid(value)
|
||||
second = Identifier.from_uuid(value)
|
||||
|
||||
# Assert
|
||||
assert first == second
|
||||
|
||||
|
||||
def test_identifiers_with_different_values_are_not_equal() -> None:
|
||||
"""Identifiers with different UUIDs should not be equal."""
|
||||
|
||||
# Arrange / Act
|
||||
first = Identifier.new()
|
||||
second = Identifier.new()
|
||||
|
||||
# Assert
|
||||
assert first != second
|
||||
|
||||
|
||||
def test_identifier_is_hashable() -> None:
|
||||
"""Identifiers should be hashable."""
|
||||
|
||||
# Arrange
|
||||
identifier = Identifier.new()
|
||||
|
||||
# Act
|
||||
values = {identifier}
|
||||
|
||||
# Assert
|
||||
assert identifier in values
|
||||
|
||||
|
||||
def test_str_returns_uuid_string() -> None:
|
||||
"""The string representation should match the UUID."""
|
||||
|
||||
# Arrange
|
||||
identifier = Identifier.from_string(
|
||||
"550e8400-e29b-41d4-a716-446655440000",
|
||||
)
|
||||
|
||||
# Act / Assert
|
||||
assert str(identifier) == "550e8400-e29b-41d4-a716-446655440000"
|
||||
|
||||
|
||||
def test_repr_returns_developer_representation() -> None:
|
||||
"""The repr should contain the class name and UUID."""
|
||||
|
||||
# Arrange
|
||||
identifier = Identifier.from_string(
|
||||
"550e8400-e29b-41d4-a716-446655440000",
|
||||
)
|
||||
|
||||
# Act / Assert
|
||||
assert repr(identifier) == "Identifier('550e8400-e29b-41d4-a716-446655440000')"
|
||||
|
||||
|
||||
def test_hex_returns_uuid_hexadecimal() -> None:
|
||||
"""The hexadecimal representation should match the UUID."""
|
||||
|
||||
# Arrange
|
||||
identifier = Identifier.from_string(
|
||||
"550e8400-e29b-41d4-a716-446655440000",
|
||||
)
|
||||
|
||||
# Act / Assert
|
||||
assert identifier.hex == "550e8400e29b41d4a716446655440000"
|
||||
|
||||
|
||||
def test_urn_returns_uuid_urn() -> None:
|
||||
"""The URN representation should match the UUID."""
|
||||
|
||||
# Arrange
|
||||
identifier = Identifier.from_string(
|
||||
"550e8400-e29b-41d4-a716-446655440000",
|
||||
)
|
||||
|
||||
# Act / Assert
|
||||
assert identifier.urn == "urn:uuid:550e8400-e29b-41d4-a716-446655440000"
|
||||
|
||||
|
||||
def test_identifier_is_immutable() -> None:
|
||||
"""Identifiers must be immutable."""
|
||||
|
||||
# Arrange
|
||||
identifier = Identifier.new()
|
||||
|
||||
# Act / Assert
|
||||
with pytest.raises(FrozenInstanceError):
|
||||
object.__setattr__(identifier, "value", UUID(int=0))
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Tests for the ModuleId Value Object.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from shared.identity import Identifier, ModuleId
|
||||
|
||||
|
||||
def test_new_creates_module_id() -> None:
|
||||
"""A new ModuleId should be created."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ModuleId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, ModuleId)
|
||||
|
||||
|
||||
def test_module_id_is_identifier() -> None:
|
||||
"""ModuleId should inherit from Identifier."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ModuleId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, Identifier)
|
||||
|
||||
|
||||
def test_module_id_preserves_type() -> None:
|
||||
"""Factory methods should preserve the concrete type."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = ModuleId.new()
|
||||
|
||||
# Assert
|
||||
assert type(module_id) is ModuleId
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Tests for the RequestId Value Object.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from shared.identity import Identifier, RequestId
|
||||
|
||||
|
||||
def test_new_creates_module_id() -> None:
|
||||
"""A new RequestId should be created."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = RequestId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, RequestId)
|
||||
|
||||
|
||||
def test_module_id_is_identifier() -> None:
|
||||
"""RequestId should inherit from Identifier."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = RequestId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, Identifier)
|
||||
|
||||
|
||||
def test_module_id_preserves_type() -> None:
|
||||
"""Factory methods should preserve the concrete type."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = RequestId.new()
|
||||
|
||||
# Assert
|
||||
assert type(module_id) is RequestId
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Tests for the SessionId Value Object.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from shared.identity import Identifier, SessionId
|
||||
|
||||
|
||||
def test_new_creates_module_id() -> None:
|
||||
"""A new SessionId should be created."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = SessionId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, SessionId)
|
||||
|
||||
|
||||
def test_module_id_is_identifier() -> None:
|
||||
"""SessionId should inherit from Identifier."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = SessionId.new()
|
||||
|
||||
# Assert
|
||||
assert isinstance(module_id, Identifier)
|
||||
|
||||
|
||||
def test_module_id_preserves_type() -> None:
|
||||
"""Factory methods should preserve the concrete type."""
|
||||
|
||||
# Arrange
|
||||
|
||||
# Act
|
||||
module_id = SessionId.new()
|
||||
|
||||
# Assert
|
||||
assert type(module_id) is SessionId
|
||||
Reference in New Issue
Block a user