From 398428e88322f60100cad3bd51d2ceef7e21608a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Dom=C3=ADnguez?= Date: Wed, 1 Sep 2021 17:40:42 +0200 Subject: [PATCH] =?UTF-8?q?Change=20of=20attributes=20for=20added=20indivi?= =?UTF-8?q?duals=20(#698)=20Authored-by:=20kysrpex=20=20Authored-by:=20Jos=C3=A9=20Manuel=20Dom=C3=ADng?= =?UTF-8?q?uez=20=20(merged=20fro?= =?UTF-8?q?m=202d71d21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- osp/core/cuds.py | 45 ++++++++++++++++++++++++++++++++++--- osp/core/ontology/oclass.py | 7 +++--- osp/core/warnings.py | 8 +++++++ 3 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 osp/core/warnings.py diff --git a/osp/core/cuds.py b/osp/core/cuds.py index fe4eee1e..4349c4f1 100644 --- a/osp/core/cuds.py +++ b/osp/core/cuds.py @@ -5,9 +5,13 @@ """ import logging +from copy import deepcopy from uuid import uuid4, UUID -from typing import Union, List, Iterator, Dict, Any, Optional, Tuple, Iterable +from typing import Any, Dict, Hashable, Iterable, Iterator, List, Optional, \ + Tuple, Union +import rdflib from rdflib import URIRef, BNode, RDF, Graph, Literal +import osp.core.warnings as warning_settings from osp.core.namespaces import cuba, from_iri from osp.core.ontology.relationship import OntologyRelationship from osp.core.ontology.attribute import OntologyAttribute @@ -179,7 +183,9 @@ def get_attributes(self): for s, p, o in self._graph.triples((self.iri, None, None)): obj = from_iri(p, raise_error=False) if isinstance(obj, OntologyAttribute): - result[obj] = o.toPython() + value = self._rdflib_5_inplace_modification_prevention_filter( + o.toPython(), obj) + result[obj] = value return result def is_a(self, oclass): @@ -870,7 +876,9 @@ def __getattr__(self, name): attr = self._get_attribute_by_argname(name) if self.session: self.session._notify_read(self) - return self._graph.value(self.iri, attr.iri).toPython() + value = self._rdflib_5_inplace_modification_prevention_filter( + self._graph.value(self.iri, attr.iri).toPython(), attr) + return value except AttributeError as e: if ( # check if user calls session's methods on wrapper self.is_a(cuba.Wrapper) @@ -893,6 +901,37 @@ def _get_attribute_by_argname(self, name): return attr raise AttributeError(name) + @staticmethod + def _rdflib_5_inplace_modification_prevention_filter( + value: Any, attribute: OntologyAttribute) -> Any: + if rdflib.__version__ < "6.0.0" and not isinstance(value, + Hashable): + value = deepcopy(value) + if warning_settings.attributes_cannot_modify_in_place: + warning_settings.attributes_cannot_modify_in_place = False + logger.warning(f"Attribute {attribute} references the mutable " + f"object {value} of type {type(value)}. Please " + f"note that if you modify this object " + f"in-place, the changes will not be reflected " + f"on the cuds object's attribute. \n" + f"For example, executing " + f"`fr = city.City(name='Freiburg', " + f"coordinates=[1, 2]); fr.coordinates[0]=98; " + f"fr.coordinates` would yield `array([1, 2])` " + f"instead of `array([98, 2])`, as you could " + f"expect. Use `fr.coordinates = [98, 2]` " + f"instead, or save the attribute to a " + f"different variable, i.e. `value = " + f"fr.coordinates; value[0] = 98, " + f"fr.coordinates = value`." + f"\n" + f"You will not see this kind of warning again " + f"during this session. You can turn off the " + f"warning by running `import osp.core.warnings " + f"as warning_settings; warning_settings." + f"attributes_cannot_modify_in_place = False`.") + return value + def __setattr__(self, name, new_value): """Set an attribute. diff --git a/osp/core/ontology/oclass.py b/osp/core/ontology/oclass.py index d810e4bd..3c0f5683 100644 --- a/osp/core/ontology/oclass.py +++ b/osp/core/ontology/oclass.py @@ -1,12 +1,13 @@ """A class defined in the ontology.""" + +import logging import uuid import rdflib +from rdflib import OWL, RDF, RDFS, BNode -from osp.core.ontology.entity import OntologyEntity from osp.core.ontology.cuba import rdflib_cuba -import logging -from rdflib import OWL, RDFS, RDF, BNode +from osp.core.ontology.entity import OntologyEntity logger = logging.getLogger(__name__) diff --git a/osp/core/warnings.py b/osp/core/warnings.py new file mode 100644 index 00000000..534d51e6 --- /dev/null +++ b/osp/core/warnings.py @@ -0,0 +1,8 @@ +"""Configuration of OSP-core warnings.""" + +attributes_cannot_modify_in_place = True +"""Warns when a user fetches a mutable attribute of a CUDS object. + +For example `fr = city.City(name='Freiburg', coordinates=[1, 2]); +fr.coordinates`. +"""