From 8a244f1e31fd3c19c5d4fff427f11829f46bc115 Mon Sep 17 00:00:00 2001 From: mouffok Date: Wed, 24 Apr 2024 16:42:24 +0200 Subject: [PATCH] started implementation for specification of schema id on validation --- kgforge/core/archetypes/model.py | 10 ++++--- kgforge/core/forge.py | 6 ++-- kgforge/specializations/models/rdf/service.py | 29 ++++++++++++------- kgforge/specializations/models/rdf_model.py | 14 +++++---- .../specializations/models/test_demo_model.py | 2 +- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/kgforge/core/archetypes/model.py b/kgforge/core/archetypes/model.py index 8c6a51f7..4f382c03 100644 --- a/kgforge/core/archetypes/model.py +++ b/kgforge/core/archetypes/model.py @@ -171,8 +171,9 @@ def validate( self, data: Union[Resource, List[Resource]], execute_actions_before: bool, - type_: str, - inference: Optional[str] = None, + type_: Optional[str], + inference: Optional[str], + schema_id: Optional[str] ) -> None: # Replace None by self._validate_many to switch to optimized bulk validation. run( @@ -184,18 +185,19 @@ def validate( monitored_status="_validated", type_=type_, inference=inference, + schema_id=schema_id ) @abstractmethod def _validate_many( - self, resources: List[Resource], type_: str, inference: str + self, resources: List[Resource], type_: str, inference: str, schema_id: str ) -> None: # Bulk validation could be optimized by overriding this method in the specialization. # POLICY Should reproduce self._validate_one() and execution._run_one() behaviours. ... @abstractmethod - def _validate_one(self, resource: Resource, type_: str, inference: str) -> None: + def _validate_one(self, resource: Resource, type_: str, inference: str, schema_id: str) -> None: # POLICY Should notify of failures with exception ValidationError including a message. ... diff --git a/kgforge/core/forge.py b/kgforge/core/forge.py index efd85998..6ffe06b8 100644 --- a/kgforge/core/forge.py +++ b/kgforge/core/forge.py @@ -310,8 +310,9 @@ def validate( self, data: Union[Resource, List[Resource]], execute_actions_before: bool = False, - type_: str = None, + type_: Optional[str] = None, inference: Optional[str] = None, + schema_id: Optional[str] = None ) -> None: """ Check if resources conform to their corresponding schemas. This method will try to infer the schema of a resource from its type. @@ -321,13 +322,14 @@ def validate( :param data: a resource or a list of resources to validate :param execute_actions_before: whether to execute a LazyAction value of one of a resource property (True) or not (False) prior to validation + :param schema_id: the schema to validate against it. If None, the validation function will look for the schema tied to the type attribute in the Resource :param type_: the type to validate the data against it. If None, the validation function will look for a type attribute in the Resource :param inference: an inference strategy to use during validation to extend the resource. For example 'rdfs' is an RDF inference strategy (when using RdfModel with pySHACL) able to extend the resource with the transitive closures of type subClassOf and/or property subPropertyOf relations as per the RDFS entailment rules (https://www.w3.org/TR/rdf-mt/). In this example 'owlrl' or 'rdfsowlrl' are also possible values while no inference will be performed with None . :return: None """ - self._model.validate(data, execute_actions_before, type_=type_) + self._model.validate(data, execute_actions_before, type_=type_, inference=inference, schema_id=schema_id) # Resolving User Interface. diff --git a/kgforge/specializations/models/rdf/service.py b/kgforge/specializations/models/rdf/service.py index e7353011..248f5cbe 100644 --- a/kgforge/specializations/models/rdf/service.py +++ b/kgforge/specializations/models/rdf/service.py @@ -193,18 +193,25 @@ def materialize(self, iri: URIRef) -> NodeProperties: """ raise NotImplementedError() - def validate(self, resource: Resource, type_: str, inference: str): + def validate(self, resource: Resource, type_: Optional[str], inference: Optional[str], schema_id: Optional[str]): + if schema_id is not None: + pass # TODO + try: - if not resource.get_type() and not type_: - raise ValueError( - "No type was provided through Resource.type or the type_ parameter" - ) - if isinstance(resource.get_type(), list) and type_ is None: - raise ValueError( - "Resource has list of types as attribute and type_ parameter is not specified. " - "Provide a single value for the type_ parameter or for Resource.type" - ) - type_to_validate = type_ if type_ else resource.get_type() + if type_ is None: + if not resource.get_type(): + raise ValueError( + "No type was provided through Resource.type or the type_ parameter" + ) + if isinstance(resource.get_type(), list): + raise ValueError( + "Resource has list of types as attribute and type_ parameter is not specified. " + "Provide a single value for the type_ parameter or for Resource.type" + ) + type_to_validate = resource.get_type() + else: + type_to_validate = type_ + except ValueError as exc: raise TypeError( f"A single type should be provided for validation: {str(exc)}" diff --git a/kgforge/specializations/models/rdf_model.py b/kgforge/specializations/models/rdf_model.py index 5cd8388a..00181857 100644 --- a/kgforge/specializations/models/rdf_model.py +++ b/kgforge/specializations/models/rdf_model.py @@ -113,8 +113,9 @@ def validate( self, data: Union[Resource, List[Resource]], execute_actions_before: bool, - type_: str, - inference: str = None, + type_: Optional[str], + inference: Optional[str], + schema_id: Optional[str] ) -> None: run( self._validate_one, @@ -125,14 +126,15 @@ def validate( monitored_status="_validated", type_=type_, inference=inference, + schema_id=schema_id ) def _validate_many( - self, resources: List[Resource], type_: str, inference: str + self, resources: List[Resource], type_: str, inference: str, schema_id: str ) -> None: for resource in resources: conforms, graph, _ = self.service.validate( - resource, type_=type_, inference=inference + resource, type_=type_, inference=inference, schema_id=schema_id ) if conforms: resource._validated = True @@ -150,8 +152,8 @@ def _validate_many( resource._last_action = action - def _validate_one(self, resource: Resource, type_: str, inference: str) -> None: - conforms, _, report = self.service.validate(resource, type_, inference) + def _validate_one(self, resource: Resource, type_: str, inference: str, schema_id: str) -> None: + conforms, _, report = self.service.validate(resource, type_, inference, schema_id) if conforms is False: raise ValidationError("\n" + report) diff --git a/tests/specializations/models/test_demo_model.py b/tests/specializations/models/test_demo_model.py index 787c8b9a..17245332 100644 --- a/tests/specializations/models/test_demo_model.py +++ b/tests/specializations/models/test_demo_model.py @@ -53,7 +53,7 @@ def validate(capsys, model, data, rc, err, msg): "I validate the resource. An exception is raised. The printed report mentions an error: 'Exception: exception raised'." ) def validate_exception(monkeypatch, capsys, model, data): - def _validate_one(_, x, type_: str, inference: str): + def _validate_one(_, x, type_: str, inference: str, schema_id: str): raise Exception("exception raised") monkeypatch.setattr(