Browse Source

Merge pull request #122 from scossu/literals

Literals
Stefano Cossu 4 years ago
parent
commit
0fe1a09e52

+ 1 - 1
docs/contributing.rst

@@ -33,7 +33,7 @@ Modifying Cython Modules
 Cython files must be recompiled into C files and then into binary files every
 time they are changed. To recompile Lakesuperior modules, run::
 
-    python setup.py --build_ext --inplace
+    python setup.py build_ext --inplace
 
 For a faster compilation while testing, the environment variable ``CFLAGS``
 can set to ``-O0`` to turn off compiler optimization. The runtime code may run

+ 6 - 0
lakesuperior/__init__.py

@@ -17,6 +17,12 @@ referenced or copied with a known path relative to the package root.
 """
 
 class Env:
+    """
+    Lakesuperior environment.
+
+    Instances of this class contain the environment necessary to run a
+    self-standing instance of Lakesuperior in a Python environment.
+    """
     pass
 
 env = Env()

+ 0 - 1
lakesuperior/messaging/handlers.py

@@ -24,7 +24,6 @@ class StompHandler(logging.Handler):
             conn_cls = stomp.Connection10
 
         self.conn = conn_cls([(self.conf['host'], self.conf['port'])])
-        self.conn.start()
         try:
             self.conn.connect(
                 username=self.conf['username'],

+ 1 - 1
lakesuperior/model/rdf/graph.pyx

@@ -520,7 +520,7 @@ cdef class Graph:
         This function converts RDFLib terms into the serialized format stored
         in the graph's internal structure and compares them bytewise.
 
-        Any and all of the lookup terms msy be ``None``.
+        Any and all of the lookup terms may be ``None``.
 
         :rtype: Graph
         :return: New Graph instance with matching triples.

+ 28 - 41
lakesuperior/model/rdf/term.pyx

@@ -8,6 +8,7 @@ from libc.stdlib cimport free
 from libc.string cimport memcpy
 
 from lakesuperior.cy_include cimport cytpl as tpl
+from lakesuperior.dictionaries.namespaces import ns_collection as nsc
 from lakesuperior.model.base cimport Buffer, buffer_dump
 
 
@@ -21,6 +22,7 @@ DEF LSUP_TERM_STRUCT_PK_FMT = b'S(' + LSUP_TERM_PK_FMT + b')'
 #    b'^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?'
 #)
 
+
 __doc__ = """
 Term model.
 
@@ -76,9 +78,9 @@ cdef int deserialize(const Buffer *data, Term *term) except -1:
     """
     #print(f'Deserializing: {buffer_dump(data)}')
     _pk = tpl.tpl_peek(
-            tpl.TPL_MEM | tpl.TPL_DATAPEEK, data[0].addr, data[0].sz,
-            LSUP_TERM_PK_FMT, &(term[0].type), &(term[0].data),
-            &(term[0].datatype), &(term[0].lang))
+            tpl.TPL_MEM | tpl.TPL_DATAPEEK, data.addr, data.sz,
+            LSUP_TERM_PK_FMT, &(term.type), &(term.data),
+            &(term.datatype), &(term.lang))
 
     if _pk is NULL:
         raise MemoryError('Error deserializing term.')
@@ -91,21 +93,25 @@ cdef int from_rdflib(term_obj, Term *term) except -1:
     Return a Term struct obtained from a Python/RDFLib term.
     """
     _data = str(term_obj).encode()
-    term[0].data = _data
+    term.data = _data
+    term.datatype = NULL
+    term.lang = NULL
 
     if isinstance(term_obj, Literal):
-        _datatype = (getattr(term_obj, 'datatype') or '').encode()
-        _lang = (getattr(term_obj, 'language') or '').encode()
-        term[0].type = LSUP_TERM_TYPE_LITERAL
-        term[0].datatype = _datatype
-        term[0].lang = _lang
+        _datatype = getattr(term_obj, 'datatype', None)
+        _lang = getattr(term_obj, 'language', None)
+        term.type = LSUP_TERM_TYPE_LITERAL
+        if _datatype:
+            _datatype = _datatype.encode()
+            term.datatype = _datatype
+        if _lang:
+            _lang = _lang.encode()
+            term.lang = _lang
     else:
-        term[0].datatype = NULL
-        term[0].lang = NULL
         if isinstance(term_obj, URIRef):
-            term[0].type = LSUP_TERM_TYPE_URIREF
+            term.type = LSUP_TERM_TYPE_URIREF
         elif isinstance(term_obj, BNode):
-            term[0].type = LSUP_TERM_TYPE_BNODE
+            term.type = LSUP_TERM_TYPE_BNODE
         else:
             raise ValueError(f'Unsupported term type: {type(term_obj)}')
 
@@ -120,28 +126,7 @@ cdef int serialize_from_rdflib(term_obj, Buffer *data) except -1:
         void *addr
         size_t sz
 
-    # From RDFlib
-    _data = str(term_obj).encode()
-    _term.data = _data
-
-    if isinstance(term_obj, Literal):
-        _datatype = (getattr(term_obj, 'datatype') or '').encode()
-        _lang = (getattr(term_obj, 'language') or '').encode()
-        _term.type = LSUP_TERM_TYPE_LITERAL
-        _term.datatype = _datatype
-        _term.lang = _lang
-    else:
-        _term.datatype = NULL
-        _term.lang = NULL
-        if isinstance(term_obj, URIRef):
-            _term.type = LSUP_TERM_TYPE_URIREF
-        elif isinstance(term_obj, BNode):
-            _term.type = LSUP_TERM_TYPE_BNODE
-        else:
-            raise ValueError(
-                f'Unsupported term type: {term_obj} {type(term_obj)}'
-            )
-
+    from_rdflib(term_obj, &_term)
     serialize(&_term, data)
 
 
@@ -150,12 +135,14 @@ cdef object to_rdflib(const Term *term):
     Return an RDFLib term.
     """
     cdef str data = (<bytes>term.data).decode()
-    if term[0].type == LSUP_TERM_TYPE_LITERAL:
-        return Literal(
-            data,
-            datatype=term.datatype if not term.lang else None,
-            lang=term.lang or None
-        )
+    if term.type == LSUP_TERM_TYPE_LITERAL:
+        if term.lang:
+            params = {'lang': (<bytes>term.lang).decode()}
+        elif term.datatype:
+            params = {'datatype': (<bytes>term.datatype).decode()}
+        else:
+            params = {}
+        return Literal(data, **params)
     else:
         if term.type == LSUP_TERM_TYPE_URIREF:
             return URIRef(data)

+ 2 - 2
lakesuperior/store/base_lmdb_store.pyx

@@ -295,9 +295,9 @@ cdef class BaseLmdbStore:
 
 
     cpdef void close_env(self, bint commit_pending_transaction=False) except *:
-        logger.debug('Cleaning up store env.')
+        #logger.debug('Cleaning up store env.')
         if self.is_open:
-            logger.debug('Closing store env.')
+            #logger.debug('Closing store env.')
             if self.is_txn_open is True:
                 if commit_pending_transaction:
                     self._txn_commit()

+ 2 - 1
requirements_dev.txt

@@ -15,8 +15,9 @@ numpy>=1.15.1
 pytest-flask
 pytest>=3.2.2
 rdflib==4.2.2
+rdflib_jsonld==0.4.0
 requests-toolbelt>=0.8.0
 requests>=2.18.4
 sphinx-rtd-theme>=0.2.4
-stomp.py>=4.1.20
+stomp.py>=5.0
 wheel>=0.30.0a0

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

@@ -122,6 +122,44 @@ class TestResourceCRUD:
                     rsrc.uri : nsc['rdf'].type : nsc['ldp'].RDFSource]
 
 
+    def test_create_ldp_rs_literals(self):
+        """
+        Create an RDF resource (LDP-RS) containing different literal types.
+        """
+        uid = f'/{uuid4()}'
+        uri = nsc['fcres'][uid]
+        with env.app_globals.rdf_store.txn_ctx():
+            gr = from_rdf(
+                data = '''
+                <>
+                  <urn:p:1> 1 ;
+                  <urn:p:2> "Untyped Literal" ;
+                  <urn:p:3> "Typed Literal"^^<http://www.w3.org/2001/XMLSchema#string> ;
+                  <urn:p:4> "2019-09-26"^^<http://www.w3.org/2001/XMLSchema#date> ;
+                  <urn:p:5> "Lang-tagged Literal"@en-US ;
+                  .
+                ''', format='turtle',
+                publicID=uri)
+        evt, _ = rsrc_api.create_or_replace(uid, graph=gr)
+
+        rsrc = rsrc_api.get(uid)
+        with env.app_globals.rdf_store.txn_ctx():
+            assert rsrc.imr[
+                    rsrc.uri : URIRef('urn:p:1') :
+                    Literal('1', datatype=nsc['xsd'].integer)]
+            assert rsrc.imr[
+                    rsrc.uri : URIRef('urn:p:2') : Literal('Untyped Literal')]
+            assert rsrc.imr[
+                    rsrc.uri : URIRef('urn:p:3') :
+                    Literal('Typed Literal', datatype=nsc['xsd'].string)]
+            assert rsrc.imr[
+                    rsrc.uri : URIRef('urn:p:4') :
+                    Literal('2019-09-26', datatype=nsc['xsd'].date)]
+            assert rsrc.imr[
+                    rsrc.uri : URIRef('urn:p:5') :
+                    Literal('Lang-tagged Literal', lang='en-US')]
+
+
     def test_create_ldp_nr(self):
         """
         Create a non-RDF resource (LDP-NR).