Przeglądaj źródła

Merge pull request #124 from scossu/user_types

User types
Stefano Cossu 4 lat temu
rodzic
commit
4427a7b51c

+ 12 - 0
lakesuperior/endpoints/ldp.py

@@ -661,6 +661,18 @@ def parse_repr_options(retr_opts, out_headers):
     Ideally, IMR retrieval is done once per request, so all the options
     Ideally, IMR retrieval is done once per request, so all the options
     are set once in the `imr()` property.
     are set once in the `imr()` property.
 
 
+    Representation options include:
+
+    - ``embed_children``: include full resource representation of all resource
+        children in the resource graph.
+    - ``incl_children``: TODO
+    - ``incl_inbound``: include inbound triples (triples whose object is
+      this resource).
+    - ``incl_srv_mgd``: include server-managed triples.
+
+    All options above are ``False`` by default except for ``incl_srv_mgd``
+    which is only ``False`` if the ``return`` representation is ``minimal``.
+
     :param dict retr_opts:: Options parsed from `Prefer` header.
     :param dict retr_opts:: Options parsed from `Prefer` header.
     :param dict out_headers:: Response headers.
     :param dict out_headers:: Response headers.
     """
     """

+ 29 - 4
lakesuperior/model/ldp/ldpr.py

@@ -158,10 +158,11 @@ class Ldpr(metaclass=ABCMeta):
             set) it refers to the root node. It can also be the full URI or
             set) it refers to the root node. It can also be the full URI or
             URN, in which case it will be converted.
             URN, in which case it will be converted.
         :param dict repr_opts: Options used to retrieve the IMR. See
         :param dict repr_opts: Options used to retrieve the IMR. See
-            `parse_rfc7240` for format details.
+            :py:meth:`~lakesuperior.endpoints.ldp.parse_repr_options` for
+            format details.
         :param str provided_imr: RDF data provided by the client in
         :param str provided_imr: RDF data provided by the client in
             operations such as `PUT` or `POST`, serialized as a string. This
             operations such as `PUT` or `POST`, serialized as a string. This
-            sets the `provided_imr` property.
+            sets the :py:data:`~Ldpr.provided_imr` property.
         """
         """
         self.uid = (
         self.uid = (
             rdfly.uri_to_uid(uid) if isinstance(uid, URIRef) else uid)
             rdfly.uri_to_uid(uid) if isinstance(uid, URIRef) else uid)
@@ -264,6 +265,17 @@ class Ldpr(metaclass=ABCMeta):
         return self._metadata
         return self._metadata
 
 
 
 
+    @property
+    def user_data(self):
+        """
+        User-defined triples.
+        """
+        if not hasattr(self, '_user_data'):
+            self._user_data = rdfly.get_user_data(self.uid)
+
+        return self._user_data
+
+
     @metadata.setter
     @metadata.setter
     def metadata(self, rsrc):
     def metadata(self, rsrc):
         """
         """
@@ -339,7 +351,8 @@ class Ldpr(metaclass=ABCMeta):
 
 
     @property
     @property
     def types(self):
     def types(self):
-        """All RDF types.
+        """
+        All RDF types, both server-managed and user-defined.
 
 
         :rtype: set(rdflib.term.URIRef)
         :rtype: set(rdflib.term.URIRef)
         """
         """
@@ -352,7 +365,7 @@ class Ldpr(metaclass=ABCMeta):
             else:
             else:
                 return set()
                 return set()
 
 
-            self._types = set(metadata[self.uri: RDF.type])
+            self._types = set(metadata[self.uri: RDF.type]) | self.user_types
 
 
         return self._types
         return self._types
 
 
@@ -369,6 +382,18 @@ class Ldpr(metaclass=ABCMeta):
         return self._ldp_types
         return self._ldp_types
 
 
 
 
+    @property
+    def user_types(self):
+        """User-defined types.
+
+        :rtype: set(rdflib.term.URIRef)
+        """
+        if not hasattr(self, '_ud_types'):
+            self._ud_types = self.user_data[self.uri: RDF.type]
+
+        return self._ud_types
+
+
     ## LDP METHODS ##
     ## LDP METHODS ##
 
 
     def head(self):
     def head(self):

+ 54 - 0
tests/2_api/test_2_0_resource_api.py

@@ -568,6 +568,60 @@ class TestResourceCRUD:
     #                top_cont_rsrc.uri: nsc['dcterms'].relation:
     #                top_cont_rsrc.uri: nsc['dcterms'].relation:
     #                nsc['fcres'][target_uid]]
     #                nsc['fcres'][target_uid]]
 
 
+    def test_user_data(self):
+        '''
+        Verify that only user-defined data are in user_data.
+        '''
+        data = b'''
+        <> a <urn:t:1> ;
+            <urn:p:1> "Property 1" ;
+            <urn:p:2> <urn:o:2> .
+        '''
+        uid = f'/{uuid4()}'
+        uri = nsc['fcres'][uid]
+
+        rsrc_api.create_or_replace(uid, rdf_data=data, rdf_fmt='ttl')
+        rsrc = rsrc_api.get(uid)
+
+        with env.app_globals.rdf_store.txn_ctx():
+            ud_data = rsrc.user_data
+
+            assert ud_data[uri: nsc['rdf'].type: URIRef('urn:t:1')]
+            assert ud_data[uri: URIRef('urn:p:1'): Literal('Property 1')]
+            assert ud_data[uri: URIRef('urn:p:2'): URIRef('urn:o:2')]
+            assert not ud_data[uri: nsc['rdf'].type: nsc['ldp'].Resource]
+
+
+    def test_types(self):
+        '''
+        Test server-managed and user-defined RDF types.
+        '''
+        data = b'''
+        <> a <urn:t:1> , <urn:t:2> .
+        '''
+        uid = f'/{uuid4()}'
+        uri = nsc['fcres'][uid]
+
+        rsrc_api.create_or_replace(uid, rdf_data=data, rdf_fmt='ttl')
+        rsrc = rsrc_api.get(uid)
+
+        with env.app_globals.rdf_store.txn_ctx():
+            assert URIRef('urn:t:1') in rsrc.types
+            assert URIRef('urn:t:1') in rsrc.user_types
+            assert URIRef('urn:t:1') not in rsrc.ldp_types
+
+            assert URIRef('urn:t:2') in rsrc.types
+            assert URIRef('urn:t:2') in rsrc.user_types
+            assert URIRef('urn:t:2') not in rsrc.ldp_types
+
+            assert nsc['ldp'].Resource in rsrc.types
+            assert nsc['ldp'].Resource not in rsrc.user_types
+            assert nsc['ldp'].Resource in rsrc.ldp_types
+
+            assert nsc['ldp'].Container in rsrc.types
+            assert nsc['ldp'].Container not in rsrc.user_types
+            assert nsc['ldp'].Container in rsrc.ldp_types
+
 
 
 
 
 @pytest.mark.usefixtures('db')
 @pytest.mark.usefixtures('db')