from __future__ import annotations
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional, Generic, TypeVar, Union
from enum import Enum
from uuid import uuid4
from datetime import date, datetime
Cls = TypeVar("Cls")
class FilterWrapper(Generic[Cls]):
def __init__(self, collection: list[Cls], **kwargs):
self.collection = collection
self.kwargs = kwargs
def filter(self) -> list[Cls]:
for key, value in self.kwargs.items():
self.collection = [
item for item in self.collection if self._fetch_attr(key, item) == value
]
return self.collection
def _fetch_attr(self, name: str, item: Cls):
try:
return getattr(item, name)
except AttributeError:
raise AttributeError(f"{item} does not have attribute {name}")
def add_namespace(obj, prefix: str | None, iri: str | None):
if prefix is None and iri is None:
return
elif prefix and iri is None:
raise ValueError("If prefix is provided, iri must also be provided")
elif iri and prefix is None:
raise ValueError("If iri is provided, prefix must also be provided")
obj.ld_context[prefix] = iri
def validate_prefix(term: str | dict, prefix: str):
if isinstance(term, dict) and not term["@id"].startswith(prefix + ":"):
raise ValueError(f"Term {term} is not prefixed with {prefix}")
elif isinstance(term, str) and not term.startswith(prefix + ":"):
raise ValueError(f"Term {term} is not prefixed with {prefix}")
class Test(BaseModel):
model_config: ConfigDict = ConfigDict( validate_assignment = True,
)
name: str = Field(
default= "2",
description="""The name of the test. This is a unique identifier
that helps track individual test
cases across the system. It should be
descriptive and follow the standard naming
conventions.""",
)
number: Union[None,float,str] = Field(
default= 1,
description="""""",
)
test2: list[Test2] = Field(
default_factory=list,
description="""""",
)
ontology: Optional[Ontology] = Field(
default=None,
description="""""",
)
ld_id: str = Field(
serialization_alias="@id",
default_factory=lambda: "tst:Test/" + str(uuid4())
)
ld_type: list[str] = Field(
serialization_alias="@type",
default_factory = lambda: [
"tst:Test",
],
)
ld_context: dict[str, str | dict] = Field(
serialization_alias="@context",
default_factory = lambda: {
"tst": "https://www.github.com/my/repo/",
"schema": "http://schema.org/",
"Test2": "https://www.github.com/my/repo/Test2/",
"Ontology": "https://www.github.com/my/repo/Ontology/",
"name": {
"@id": "schema:hello",
"@type": "@id",
},
"number": "schema:one",
"test2": "schema:something",
}
)
def filter_test2(self, **kwargs) -> list[Test2]:
return FilterWrapper[Test2](self.test2, **kwargs).filter()
def set_attr_term(
self,
attr: str,
term: str | dict,
prefix: str | None = None,
iri: str | None = None
):
assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}"
if prefix:
validate_prefix(term, prefix)
add_namespace(self, prefix, iri)
self.ld_context[attr] = term
def add_type_term(
self,
term: str,
prefix: str | None = None,
iri: str | None = None
):
if prefix:
validate_prefix(term, prefix)
add_namespace(self, prefix, iri)
self.ld_type.append(term)
def add_to_test2(
self,
names: list[str]= [],
number: Optional[float]= None,
**kwargs,
):
params = {
"names": names,
"number": number
}
if "id" in kwargs:
params["id"] = kwargs["id"]
self.test2.append(
Test2(**params)
)
return self.test2[-1]
class Test2(BaseModel):
model_config: ConfigDict = ConfigDict( validate_assignment = True,
)
names: list[str] = Field(
default_factory=list,
description="""""",
)
number: Optional[float] = Field(
default=None,
description="""""",
)
ld_id: str = Field(
serialization_alias="@id",
default_factory=lambda: "tst:Test2/" + str(uuid4())
)
ld_type: list[str] = Field(
serialization_alias="@type",
default_factory = lambda: [
"tst:Test2",
],
)
ld_context: dict[str, str | dict] = Field(
serialization_alias="@context",
default_factory = lambda: {
"tst": "https://www.github.com/my/repo/",
"schema": "http://schema.org/",
"names": "schema:hello",
"number": "schema:one",
}
)
def set_attr_term(
self,
attr: str,
term: str | dict,
prefix: str | None = None,
iri: str | None = None
):
assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}"
if prefix:
validate_prefix(term, prefix)
add_namespace(self, prefix, iri)
self.ld_context[attr] = term
def add_type_term(
self,
term: str,
prefix: str | None = None,
iri: str | None = None
):
if prefix:
validate_prefix(term, prefix)
add_namespace(self, prefix, iri)
self.ld_type.append(term)
class Ontology(Enum):
ECO = "https://www.evidenceontology.org/term/"
GO = "https://amigo.geneontology.org/amigo/term/"
SIO = "http://semanticscience.org/resource/"