Browse Source

LDPR instantiation improvements:

* Reduce variables passed and inherited
* Change all `repr_opts` and `retr_options` variable names to `repr_options`
* Load inbound triples in LDP-NR
Stefano Cossu 4 years ago
parent
commit
6b71d46b73

+ 1 - 1
lakesuperior/__init__.py

@@ -49,7 +49,7 @@ class Env:
             manually before passing it to the setup.
         """
         if hasattr(self, 'app_globals'):
-            logger.warn('The environment is already set up.')
+            logger.warning('The environment is already set up.')
             return
 
         if not config:

+ 3 - 3
lakesuperior/api/resource.py

@@ -166,7 +166,7 @@ def get(uid, repr_options={}):
     - incl_children: include children URIs. Default: True.
     - embed_children: Embed full graph of all child resources. Default: False
     """
-    rsrc = LdpFactory.from_stored(uid, repr_opts=repr_options)
+    rsrc = LdpFactory.from_stored(uid, repr_options=repr_options)
     # Load graph before leaving the transaction.
     rsrc.imr
 
@@ -327,8 +327,8 @@ def delete(uid, soft=True, inbound=True):
     inbound = True if refint else inbound
 
     if soft:
-        repr_opts = {'incl_inbound' : True} if inbound else {}
-        rsrc = LdpFactory.from_stored(uid, repr_opts)
+        repr_options = {'incl_inbound' : True} if inbound else {}
+        rsrc = LdpFactory.from_stored(uid, repr_options)
         return rsrc.bury(inbound)
     else:
         Ldpr.forget(uid, inbound)

+ 16 - 14
lakesuperior/endpoints/ldp.py

@@ -574,8 +574,10 @@ def _create_args_from_req(uid):
     #logger.debug('stream: {}'.format(request.stream))
     #pdb.set_trace()
 
-    kwargs = {}
-    kwargs['handling'], kwargs['disposition'] = _set_post_put_params()
+    handling, disposition = _set_post_put_params()
+    kwargs = {'handling': handling}
+    if disposition:
+        kwargs['disposition'] = disposition
 
     link_hdr = request.headers.get('Link')
     if link_hdr:
@@ -653,7 +655,7 @@ def _set_post_put_params():
     return handling, disposition
 
 
-def parse_repr_options(retr_opts, out_headers):
+def parse_repr_options(repr_options, out_headers):
     """
     Set options to retrieve IMR.
 
@@ -672,12 +674,12 @@ def parse_repr_options(retr_opts, out_headers):
     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 repr_options:: Options parsed from `Prefer` header.
     :param dict out_headers:: Response headers.
     """
-    logger.debug('Parsing retrieval options: {}'.format(retr_opts))
+    logger.debug('Parsing retrieval options: {}'.format(repr_options))
 
-    if retr_opts.get('value') == 'minimal':
+    if repr_options.get('value') == 'minimal':
         imr_options = {
             'embed_children' : False,
             'incl_children' : False,
@@ -695,9 +697,9 @@ def parse_repr_options(retr_opts, out_headers):
         }
 
         # Override defaults.
-        if 'parameters' in retr_opts:
+        if 'parameters' in repr_options:
             try:
-                pref_imr_options = _valid_preferences(retr_opts)
+                pref_imr_options = _valid_preferences(repr_options)
                 include = list()
                 omit = list()
                 for k, v in pref_imr_options.items():
@@ -745,20 +747,20 @@ def _preference_decision(include, omit, header):
     return None
 
 
-def _valid_preferences(retr_opts):
+def _valid_preferences(repr_options):
     """
     Parse the Preference header to determine which we are applying.
 
     Re-used for response Preference-Applied header.
 
-    :param retr_opts: The incoming Preference header.
+    :param repr_options: The incoming Preference header.
     :return: list of options being applied.
     """
     imr_options = dict()
-    include = retr_opts['parameters']['include'].split(' ') \
-        if 'include' in retr_opts['parameters'] else []
-    omit = retr_opts['parameters']['omit'].split(' ') \
-        if 'omit' in retr_opts['parameters'] else []
+    include = repr_options['parameters']['include'].split(' ') \
+        if 'include' in repr_options['parameters'] else []
+    omit = repr_options['parameters']['omit'].split(' ') \
+        if 'omit' in repr_options['parameters'] else []
 
     logger.debug('Include: {}'.format(include))
     logger.debug('Omit: {}'.format(omit))

+ 2 - 2
lakesuperior/model/ldp/ldp_factory.py

@@ -40,7 +40,7 @@ class LdpFactory:
 
 
     @staticmethod
-    def from_stored(uid, ver_label=None, repr_opts={}, strict=True, **kwargs):
+    def from_stored(uid, ver_label=None, repr_options={}, strict=True, **kwargs):
         """
         Create an instance for retrieval purposes.
 
@@ -65,7 +65,7 @@ class LdpFactory:
         else:
             raise exc.ResourceNotExistsError(uid)
 
-        rsrc = cls(uid, repr_opts, **kwargs)
+        rsrc = cls(uid, repr_options, **kwargs)
         # Sneak in the already extracted metadata to save a query.
         rsrc._metadata = rsrc_meta
 

+ 11 - 19
lakesuperior/model/ldp/ldp_nr.py

@@ -22,28 +22,20 @@ class LdpNr(Ldpr):
     Definition: https://www.w3.org/TR/ldp/#ldpnr
     """
 
-    base_types = {
-        nsc['fcrepo'].Binary,
-        nsc['fcrepo'].Resource,
-        nsc['ldp'].Resource,
-        nsc['ldp'].NonRDFSource,
-    }
-
-    def __init__(self, uuid, stream=None, mimetype=None,
-            disposition=None, prov_cksum_algo=None, prov_cksum=None,
-            **kwargs):
+    def __init__(self, *args, stream=None, mimetype=None, disposition=None,
+            prov_cksum_algo=None, prov_cksum=None, **kwargs):
         """
-        Extends Ldpr.__init__ by adding LDP-NR specific parameters.
+        Extends :meth:`lakesuperior.model.Ldpr.__init__` by adding LDP-NR
+        specific parameters.
         """
-        super().__init__(uuid, **kwargs)
+        super().__init__(*args, **kwargs)
 
-        self._imr_options = {}
-        if stream:
-            self.workflow = self.WRKF_INBOUND
-            self.stream = stream
-        else:
-            self.workflow = self.WRKF_OUTBOUND
+        self.base_types = super().base_types | {
+            nsc['fcrepo'].Binary,
+            nsc['ldp'].NonRDFSource,
+        }
 
+        self.stream = stream
         if mimetype:
             self.mimetype = mimetype
         else:
@@ -52,9 +44,9 @@ class LdpNr(Ldpr):
                     if self.is_stored
                     else 'application/octet-stream')
 
+        self.disposition = disposition
         self.prov_cksum_algo = prov_cksum_algo
         self.prov_cksum = prov_cksum
-        self.disposition = disposition
 
 
     @property

+ 15 - 28
lakesuperior/model/ldp/ldp_rs.py

@@ -16,37 +16,24 @@ class LdpRs(Ldpr):
 
     https://www.w3.org/TR/ldp/#ldprs
     """
-    def __init__(self, uuid, repr_opts={}, handling='lenient', **kwargs):
-        """
-        Extends :meth:`Ldpr.__init__`by adding LDP-RS specific parameters.
 
-        :param str handling: One of ``strict``, ``lenient`` (the default) or
-        ``none``. ``strict`` raises an error if a server-managed term is in the
-        graph. ``lenient`` removes all sever-managed triples encountered.
-        ``none`` skips all server-managed checks. It is used for internal
-        modifications.
+    def __init__(self, *args, **kwargs):
+        """
+        Extends :meth:`lakesuperior.model.Ldpr.__init__` by adding LDP-RS
+        specific parameters.
         """
-        super().__init__(uuid, **kwargs)
+        super().__init__(*args, **kwargs)
+
         self.base_types = super().base_types | {
-            nsc['fcrepo'].Container,
-            nsc['ldp'].Container,
+            nsc['ldp'].RDFSource,
         }
 
-        # provided_imr can be empty. If None, it is an outbound resource.
-        if self.provided_imr is not None:
-            self.workflow = self.WRKF_INBOUND
-        else:
-            self.workflow = self.WRKF_OUTBOUND
-            self._imr_options = repr_opts
-
-        self.handling = handling
-
 
 
 class Ldpc(LdpRs):
     """LDPC (LDP Container)."""
-    def __init__(self, uuid, *args, **kwargs):
-        super().__init__(uuid, *args, **kwargs)
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
         self.base_types |= {
             nsc['fcrepo'].Container,
             nsc['ldp'].Container,
@@ -56,8 +43,8 @@ class Ldpc(LdpRs):
 
 class LdpBc(Ldpc):
     """LDP-BC (LDP Basic Container)."""
-    def __init__(self, uuid, *args, **kwargs):
-        super().__init__(uuid, *args, **kwargs)
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
         self.base_types |= {
             nsc['ldp'].BasicContainer,
         }
@@ -66,8 +53,8 @@ class LdpBc(Ldpc):
 
 class LdpDc(Ldpc):
     """LDP-DC (LDP Direct Container)."""
-    def __init__(self, uuid, *args, **kwargs):
-        super().__init__(uuid, *args, **kwargs)
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
         self.base_types |= {
             nsc['ldp'].DirectContainer,
         }
@@ -76,8 +63,8 @@ class LdpDc(Ldpc):
 
 class LdpIc(Ldpc):
     """LDP-IC (LDP Indirect Container)."""
-    def __init__(self, uuid, *args, **kwargs):
-        super().__init__(uuid, *args, **kwargs)
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
         self.base_types |= {
             nsc['ldp'].IndirectContainer,
         }

+ 18 - 15
lakesuperior/model/ldp/ldpr.py

@@ -88,7 +88,6 @@ class Ldpr(metaclass=ABCMeta):
     base_types = {
         nsc['fcrepo'].Resource,
         nsc['ldp'].Resource,
-        nsc['ldp'].RDFSource,
     }
     """RDF Types that populate a new resource."""
 
@@ -155,21 +154,30 @@ class Ldpr(metaclass=ABCMeta):
     These are used by setters and can be cleared with :py:meth:`_clear_cache`.
     """
 
+    # This gets overridden by LDP-NR.
+    mimetype = None
+
     ## MAGIC METHODS ##
 
-    def __init__(self, uid, repr_opts={}, provided_imr=None, **kwargs):
+    def __init__(
+            self, uid, repr_options={}, provided_imr=None, handling='lenient'):
         """
         Instantiate an in-memory LDP resource.
 
         :param str uid: uid of the resource. If None (must be explicitly
             set) it refers to the root node. It can also be the full URI or
             URN, in which case it will be converted.
-        :param dict repr_opts: Options used to retrieve the IMR. See
+        :param dict repr_options: Options used to retrieve the IMR. See
             :py:meth:`~lakesuperior.endpoints.ldp.parse_repr_options` for
             format details.
         :param str provided_imr: RDF data provided by the client in
             operations such as `PUT` or `POST`, serialized as a string. This
             sets the :py:data:`~Ldpr.provided_imr` property.
+        :param str handling: One of ``strict``, ``lenient`` (the default) or
+            ``none``. ``strict`` raises an error if a server-managed term is in
+            the graph. ``lenient`` removes all sever-managed triples
+            encountered.  ``none`` skips all server-managed checks. It is used
+            for internal modifications.
         """
         self.uid = (
             rdfly.uri_to_uid(uid) if isinstance(uid, URIRef) else uid)
@@ -179,10 +187,8 @@ class Ldpr(metaclass=ABCMeta):
 
         self.provided_imr = provided_imr
 
-        # This gets overridden by LDP-NR.
-        self.mimetype = None
-
-        # Disable all internal checks e.g. for raw I/O.
+        self._imr_options = repr_options
+        self.handling = handling
 
 
     #@property
@@ -224,12 +230,9 @@ class Ldpr(metaclass=ABCMeta):
             is not stored (yet).
         """
         if not hasattr(self, '_imr'):
-            if hasattr(self, '_imr_options'):
-                logger.debug(
-                    'Getting RDF triples for resource {}'.format(self.uid))
-                imr_options = self._imr_options
-            else:
-                imr_options = {}
+            logger.debug(
+                'Getting RDF triples for resource {}'.format(self.uid))
+            imr_options = getattr(self, '_imr_options', {})
             options = dict(imr_options, strict=True)
             self._imr = rdfly.get_imr(self.uid, **options)
 
@@ -501,7 +504,7 @@ class Ldpr(metaclass=ABCMeta):
             try:
                 desc_rsrc = LdpFactory.from_stored(
                     env.app_globals.rdfly.uri_to_uid(desc_uri),
-                    repr_opts={'incl_children' : False})
+                    repr_options={'incl_children' : False})
             except (TombstoneError, ResourceNotExistsError):
                 continue
             desc_rsrc.bury(inbound, tstone_pointer=self.uri)
@@ -924,7 +927,7 @@ class Ldpr(metaclass=ABCMeta):
             parent_uid = ROOT_UID
 
         parent_rsrc = LdpFactory.from_stored(
-            parent_uid, repr_opts={'incl_children': False}, handling='none')
+            parent_uid, repr_options={'incl_children': False}, handling='none')
 
         # Only update parent if the resource is new.
         if create:

+ 91 - 46
tests/2_api/test_2_0_resource_api.py

@@ -15,6 +15,8 @@ from lakesuperior.exceptions import (
 from lakesuperior.model.ldp.ldpr import Ldpr, RES_CREATED, RES_UPDATED
 from lakesuperior.model.rdf.graph import Graph, from_rdf
 
+txn_ctx = env.app_globals.rdf_store.txn_ctx
+
 
 @pytest.fixture(scope='module')
 def random_uuid():
@@ -70,7 +72,7 @@ class TestResourceCRUD:
         gr = rsrc_api.get_metadata('/')
         assert isinstance(gr, Graph)
         assert len(gr) == 9
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert gr[gr.uri : nsc['rdf'].type : nsc['ldp'].Resource ]
             assert not gr[
                 gr.uri : nsc['dcterms'].title : Literal("Repository Root")
@@ -87,7 +89,7 @@ class TestResourceCRUD:
         assert isinstance(rsrc, Ldpr)
         gr = rsrc.imr
         assert len(gr) == 10
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert gr[gr.uri : nsc['rdf'].type : nsc['ldp'].Resource ]
             assert gr[
                 gr.uri : nsc['dcterms'].title : Literal('Repository Root')]
@@ -107,14 +109,14 @@ class TestResourceCRUD:
         """
         uid = '/rsrc_from_graph'
         uri = nsc['fcres'][uid]
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr = from_rdf(
                 data='<> a <http://ex.org/type#A> .', 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():
+        with txn_ctx():
             assert rsrc.imr[
                     rsrc.uri : nsc['rdf'].type : URIRef('http://ex.org/type#A')]
             assert rsrc.imr[
@@ -127,7 +129,7 @@ class TestResourceCRUD:
         """
         uid = f'/{uuid4()}'
         uri = nsc['fcres'][uid]
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr = from_rdf(
                 data = '''
                 <>
@@ -142,7 +144,7 @@ class TestResourceCRUD:
         evt, _ = rsrc_api.create_or_replace(uid, graph=gr)
 
         rsrc = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert rsrc.imr[
                     rsrc.uri : URIRef('urn:p:1') :
                     Literal('1', datatype=nsc['xsd'].integer)]
@@ -176,7 +178,7 @@ class TestResourceCRUD:
     def test_replace_rsrc(self):
         uid = '/test_replace'
         uri = nsc['fcres'][uid]
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr1 = from_rdf(
                 data='<> a <http://ex.org/type#A> .', format='turtle',
                 publicID=uri
@@ -185,13 +187,13 @@ class TestResourceCRUD:
         assert evt == RES_CREATED
 
         rsrc = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert rsrc.imr[
                     rsrc.uri : nsc['rdf'].type : URIRef('http://ex.org/type#A')]
             assert rsrc.imr[
                     rsrc.uri : nsc['rdf'].type : nsc['ldp'].RDFSource]
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr2 = from_rdf(
                 data='<> a <http://ex.org/type#B> .', format='turtle',
                 publicID=uri
@@ -201,7 +203,7 @@ class TestResourceCRUD:
         assert evt == RES_UPDATED
 
         rsrc = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert not rsrc.imr[
                     rsrc.uri : nsc['rdf'].type : URIRef('http://ex.org/type#A')]
             assert rsrc.imr[
@@ -219,7 +221,7 @@ class TestResourceCRUD:
         uid_rs = '/test_incomp_rs'
         uid_nr = '/test_incomp_nr'
         data = b'mock binary content'
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr = from_rdf(
                 data='<> a <http://ex.org/type#A> .', format='turtle',
                 publicID=nsc['fcres'][uid_rs]
@@ -257,13 +259,13 @@ class TestResourceCRUD:
             (URIRef(uri), nsc['rdf'].type, nsc['foaf'].Organization),
         }
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr = Graph(data=init_trp)
         rsrc_api.create_or_replace(uid, graph=gr)
         rsrc_api.update_delta(uid, remove_trp, add_trp)
         rsrc = rsrc_api.get(uid)
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert rsrc.imr[
                     rsrc.uri : nsc['rdf'].type : nsc['foaf'].Organization]
             assert rsrc.imr[rsrc.uri : nsc['foaf'].name : Literal('Joe Bob')]
@@ -290,13 +292,13 @@ class TestResourceCRUD:
             (URIRef(uri), nsc['foaf'].name, Literal('Joan Knob')),
         }
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr = Graph(data=init_trp)
         rsrc_api.create_or_replace(uid, graph=gr)
         rsrc_api.update_delta(uid, remove_trp, add_trp)
         rsrc = rsrc_api.get(uid)
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert rsrc.imr[
                     rsrc.uri : nsc['rdf'].type : nsc['foaf'].Person]
             assert rsrc.imr[rsrc.uri : nsc['foaf'].name : Literal('Joan Knob')]
@@ -328,7 +330,7 @@ class TestResourceCRUD:
         ver_uid = rsrc_api.create_version(uid, 'v1').split('fcr:versions/')[-1]
 
         rsrc = rsrc_api.update(uid, update_str)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert (
                 (rsrc.uri, nsc['dcterms'].title, Literal('Original title.'))
                 not in set(rsrc.imr))
@@ -354,7 +356,7 @@ class TestResourceCRUD:
 
         member_rsrc = rsrc_api.get('/member')
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert nsc['ldp'].Container in dc_rsrc.ldp_types
             assert nsc['ldp'].DirectContainer in dc_rsrc.ldp_types
 
@@ -369,7 +371,7 @@ class TestResourceCRUD:
 
         member_rsrc = rsrc_api.get('/member')
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert nsc['ldp'].Container in dc_rsrc.ldp_types
             assert nsc['ldp'].DirectContainer in dc_rsrc.ldp_types
 
@@ -385,7 +387,7 @@ class TestResourceCRUD:
         child_uid = rsrc_api.create(dc_uid).uid
         member_rsrc = rsrc_api.get('/member')
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert member_rsrc.imr[
                 member_rsrc.uri: nsc['dcterms'].relation: nsc['fcres'][child_uid]]
 
@@ -408,7 +410,7 @@ class TestResourceCRUD:
         child_uid = rsrc_api.create(dc_uid).uid
         member_rsrc = rsrc_api.get('/member')
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert member_rsrc.imr[
                 member_rsrc.uri: nsc['ldp'].member: nsc['fcres'][child_uid]
             ]
@@ -432,7 +434,7 @@ class TestResourceCRUD:
         child_uid = rsrc_api.create(dc_uid).uid
         member_rsrc = rsrc_api.get(dc_uid)
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             #import pdb; pdb.set_trace()
             assert member_rsrc.imr[
                 member_rsrc.uri: nsc['dcterms'].relation:
@@ -456,7 +458,7 @@ class TestResourceCRUD:
         child_uid = rsrc_api.create(dc_uid, None).uid
         member_rsrc = rsrc_api.get(dc_uid)
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert member_rsrc.imr[
                 member_rsrc.uri: nsc['ldp'].member: nsc['fcres'][child_uid]]
 
@@ -480,14 +482,14 @@ class TestResourceCRUD:
                 member_uid, rdf_data=ic_member_rdf, rdf_fmt='turtle')
 
         ic_rsrc = rsrc_api.get(ic_uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert nsc['ldp'].Container in ic_rsrc.ldp_types
             assert nsc['ldp'].IndirectContainer in ic_rsrc.ldp_types
             assert nsc['ldp'].DirectContainer not in ic_rsrc.ldp_types
 
         member_rsrc = rsrc_api.get(member_uid)
         top_cont_rsrc = rsrc_api.get(cont_uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert top_cont_rsrc.imr[
                 top_cont_rsrc.uri: nsc['dcterms'].relation:
                 nsc['fcres'][target_uid]]
@@ -554,7 +556,7 @@ class TestResourceCRUD:
     #                member_uid, rdf_data=ic_member_rdf, rdf_fmt='turtle')
 
     #        ic_rsrc = rsrc_api.get(ic_uid)
-    #        with env.app_globals.rdf_store.txn_ctx():
+    #        with txn_ctx():
     #            assert nsc['ldp'].Container in ic_rsrc.ldp_types
     #            assert nsc['ldp'].IndirectContainer in ic_rsrc.ldp_types
 
@@ -562,7 +564,7 @@ class TestResourceCRUD:
 
     #    for i, ic_rdf in enumerate(ic_def_rdf):
     #        member_rsrc = rsrc_api.get(member_uid)
-    #        with env.app_globals.rdf_store.txn_ctx():
+    #        with txn_ctx():
     #            assert top_cont_rsrc.imr[
     #                top_cont_rsrc.uri: nsc['dcterms'].relation:
     #                nsc['fcres'][target_uid]]
@@ -582,7 +584,7 @@ class TestResourceCRUD:
         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():
+        with txn_ctx():
             ud_data = rsrc.user_data
 
             assert ud_data[uri: nsc['rdf'].type: URIRef('urn:t:1')]
@@ -604,7 +606,7 @@ class TestResourceCRUD:
         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():
+        with 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
@@ -622,6 +624,49 @@ class TestResourceCRUD:
             assert nsc['ldp'].Container in rsrc.ldp_types
 
 
+    def test_inbound_triples_ldprs(self):
+        """ Test displaying of inbound triples for a LDP_RS. """
+        src_uid = f'/{uuid4()}'
+        src_uri = nsc['fcres'][src_uid]
+        trg_uid = f'/{uuid4()}'
+        trg_uri = nsc['fcres'][trg_uid]
+
+        src_data = f'<> <urn:p:1> <{trg_uri}> .'.encode()
+        trg_data = b'<> <urn:p:2> <urn:o:1> .'
+
+        with txn_ctx(True):
+            rsrc_api.create_or_replace(
+                    trg_uid, rdf_data=trg_data, rdf_fmt='ttl')
+            rsrc_api.create_or_replace(
+                    src_uid, rdf_data=src_data, rdf_fmt='ttl')
+
+        rsrc = rsrc_api.get(trg_uid, repr_options={'incl_inbound': True})
+
+        with txn_ctx():
+            assert (src_uri, URIRef('urn:p:1'), trg_uri) in rsrc.imr
+
+
+    def test_inbound_triples_ldpnr(self):
+        """ Test displaying of inbound triples for a LDP_NR. """
+        src_uid = f'/{uuid4()}'
+        src_uri = nsc['fcres'][src_uid]
+        trg_uid = f'/{uuid4()}'
+        trg_uri = nsc['fcres'][trg_uid]
+
+        src_data = f'<> <urn:p:1> <{trg_uri}> .'.encode()
+        trg_data = b'Some ASCII content.'
+
+        with txn_ctx(True):
+            rsrc_api.create_or_replace(
+                    trg_uid, stream=BytesIO(trg_data), mimetype='text/plain')
+            rsrc_api.create_or_replace(
+                    src_uid, rdf_data=src_data, rdf_fmt='ttl')
+
+        rsrc = rsrc_api.get(trg_uid, repr_options={'incl_inbound': True})
+
+        with txn_ctx():
+            assert (src_uri, URIRef('urn:p:1'), trg_uri) in rsrc.imr
+
 
 @pytest.mark.usefixtures('db')
 class TestRelativeUris:
@@ -641,7 +686,7 @@ class TestRelativeUris:
         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():
+        with txn_ctx():
             assert rsrc.imr[uri: nsc['rdf']['type']: URIRef('urn:type:A')]
             assert rsrc.imr[
                 URIRef('http://ex.org/external'): URIRef('urn:pred:x'): uri]
@@ -654,7 +699,7 @@ class TestRelativeUris:
         uid = '/reluri02'
         uri = nsc['fcres'][uid]
         gr = Graph()
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr.add({
                 (URIRef(''), nsc['rdf']['type'], URIRef('urn:type:A')),
                 (
@@ -665,7 +710,7 @@ class TestRelativeUris:
         rsrc_api.create_or_replace(uid, graph=gr)
         rsrc = rsrc_api.get(uid)
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert rsrc.imr[uri: nsc['rdf']['type']: URIRef('urn:type:A')]
             assert rsrc.imr[
                 URIRef('http://ex.org/external'): URIRef('urn:pred:x'): uri]
@@ -684,7 +729,7 @@ class TestRelativeUris:
         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():
+        with txn_ctx():
             assert rsrc.imr[
                 URIRef(str(uri) + '#hash1'): nsc['rdf'].type:
                 URIRef('urn:type:A')]
@@ -701,7 +746,7 @@ class TestRelativeUris:
         uid = '/reluri04'
         uri = nsc['fcres'][uid]
         gr = Graph()
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr.add({
                 (URIRef('#hash1'), nsc['rdf']['type'], URIRef('urn:type:A')),
                 (
@@ -712,7 +757,7 @@ class TestRelativeUris:
         rsrc_api.create_or_replace(uid, graph=gr)
         rsrc = rsrc_api.get(uid)
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert rsrc.imr[
                 URIRef(str(uri) + '#hash1'): nsc['rdf']['type']:
                 URIRef('urn:type:A')]
@@ -735,7 +780,7 @@ class TestRelativeUris:
         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():
+        with txn_ctx():
             assert rsrc.imr[
                 URIRef(str(uri) + '/child1'): nsc['rdf'].type:
                 URIRef('urn:type:A')]
@@ -752,7 +797,7 @@ class TestRelativeUris:
         uid = '/reluri06'
         uri = nsc['fcres'][uid]
         gr = Graph()
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             gr.add({
                 (URIRef('child1'), nsc['rdf']['type'], URIRef('urn:type:A')),
                 (
@@ -763,7 +808,7 @@ class TestRelativeUris:
         rsrc_api.create_or_replace(uid, graph=gr)
         rsrc = rsrc_api.get(uid)
 
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert rsrc.imr[
                 URIRef(str(uri) + '/child1'): nsc['rdf'].type:
                 URIRef('urn:type:A')]
@@ -799,7 +844,7 @@ class TestAdvancedDelete:
         rsrc_api.resurrect(uid)
 
         rsrc = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert nsc['ldp'].Resource in rsrc.ldp_types
 
 
@@ -844,11 +889,11 @@ class TestAdvancedDelete:
         uid = '/test_soft_delete_children01'
         rsrc_api.resurrect(uid)
         parent_rsrc = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert nsc['ldp'].Resource in parent_rsrc.ldp_types
         for i in range(3):
             child_rsrc = rsrc_api.get('{}/child{}'.format(uid, i))
-            with env.app_globals.rdf_store.txn_ctx():
+            with txn_ctx():
                 assert nsc['ldp'].Resource in child_rsrc.ldp_types
 
 
@@ -932,7 +977,7 @@ class TestResourceVersioning:
 
         rsrc_api.update(uid, update_str)
         current = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert (
                 (current.uri, nsc['dcterms'].title, Literal('Title #2.'))
                 in current.imr)
@@ -941,7 +986,7 @@ class TestResourceVersioning:
                 not in current.imr)
 
         v1 = rsrc_api.get_version(uid, ver_uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert (
                 (v1.uri, nsc['dcterms'].title, Literal('Original title.'))
                 in set(v1))
@@ -960,7 +1005,7 @@ class TestResourceVersioning:
         ver_uid = 'v1'
         rsrc_api.revert_to_version(uid, ver_uid)
         rev = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert (
                 (rev.uri, nsc['dcterms'].title, Literal('Original title.'))
                 in rev.imr)
@@ -985,19 +1030,19 @@ class TestResourceVersioning:
         rsrc_api.create_or_replace(ch1_uid)
         ver_uid = rsrc_api.create_version(uid, ver_uid).split('fcr:versions/')[-1]
         rsrc = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert nsc['fcres'][ch1_uid] in rsrc.imr[
                     rsrc.uri : nsc['ldp'].contains]
 
         rsrc_api.create_or_replace(ch2_uid)
         rsrc = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert nsc['fcres'][ch2_uid] in rsrc.imr[
                     rsrc.uri : nsc['ldp'].contains]
 
         rsrc_api.revert_to_version(uid, ver_uid)
         rsrc = rsrc_api.get(uid)
-        with env.app_globals.rdf_store.txn_ctx():
+        with txn_ctx():
             assert nsc['fcres'][ch1_uid] in rsrc.imr[
                     rsrc.uri : nsc['ldp'].contains]
             assert nsc['fcres'][ch2_uid] in rsrc.imr[