[PATCH oaipmh] Make size of list requests' results configurable

Denis Laxalde denis.laxalde at logilab.fr
Wed Apr 11 09:29:58 CEST 2018


# HG changeset patch
# User Denis Laxalde <denis.laxalde at logilab.fr>
# Date 1523430794 -7200
#      Wed Apr 11 09:13:14 2018 +0200
# Node ID b486fb621d385776a1ee68d6ffa407b0eb4afead
# Parent  c20e2c8abdd3bf426f9ad7f14894de2c0b2468f9
# EXP-Topic list-results-size-configurable
Make size of list requests' results configurable

We register a new "list-max-size" option that replace the
"max_result_size" class attribute of OAIComponent.

This way, the size of result of list requests (e.g. ListRecords or
ListIdentifiers) is configurable by application manager.

Closes #17142484.

diff --git a/entities.py b/entities.py
--- a/entities.py
+++ b/entities.py
@@ -56,8 +56,6 @@ class OAIComponent(Component):
     # the manner in which the repository supports the notion of deleted
     # records (legitimate values are no ; transient ; persistent)
     deleted_handling = 'no'
-    # maximum number of items for request returning a list of discrete items
-    max_result_size = 20
 
     # Internals.
     __setspecs__ = {}
@@ -124,8 +122,8 @@ class OAIComponent(Component):
         Finally, if `setspec` is None, a result set corresponding to all
         registered setspecs is returned.
 
-        This result set has a size lower that class `max_result_size`
-        attribute.
+        This result set has a size lower the value specified in
+        "list-max-size" configuration option.
 
         The eid of the next entity to yield is returned (in case a result set
         is returned, None otherwise) if there are more results to fetch from
@@ -142,7 +140,9 @@ class OAIComponent(Component):
                 args['until_date'] = until_date
             return query
 
-        qs = 'Any X ORDERBY X LIMIT {0}'.format(self.max_result_size + 1)
+        max_result_size = self._cw.vreg.config['list-max-size']
+
+        qs = 'Any X ORDERBY X LIMIT {0}'.format(max_result_size + 1)
         where, args = [], {}
         # Add restriction from resumptionToken (from_eid).
         if from_eid is not None:
@@ -201,15 +201,15 @@ class OAIComponent(Component):
         if subquery:
             qs += ' WITH XX BEING ({0})'.format(subquery)
         rset = self._cw.execute(qs, args)
-        return self.limit_rset(rset)
+        return self.limit_rset(rset, max_result_size)
 
-    def limit_rset(self, rset):
+    def limit_rset(self, rset, max_result_size):
         """Return a result set limited to `max_result_size` along with the eid
         of next entity to be returned.
         """
-        if len(rset) > self.max_result_size:
+        if len(rset) > max_result_size:
             next_eid = str(rset[-1][0])
-            rset = rset.limit(self.max_result_size, inplace=True)
+            rset = rset.limit(max_result_size, inplace=True)
         else:
             next_eid = None
         return rset, next_eid
diff --git a/site_cubicweb.py b/site_cubicweb.py
--- a/site_cubicweb.py
+++ b/site_cubicweb.py
@@ -24,4 +24,10 @@ options = (
       'help': 'the e-mail address of an administrator of the OAI-PMH repository',
       'group': 'oaipmh',
       'level': 0}),
+    ('list-max-size',
+     {'type': 'int',
+      'default': 20,
+      'help': 'maximum number of items for request returning a list of discrete entities',
+      'group': 'oaipmh',
+      'level': 0}),
 )
diff --git a/test/test_oaipmh.py b/test/test_oaipmh.py
--- a/test/test_oaipmh.py
+++ b/test/test_oaipmh.py
@@ -16,6 +16,7 @@
 """cubicweb-oaipmh tests"""
 from __future__ import print_function
 
+from contextlib import contextmanager
 from datetime import date, timedelta
 from functools import wraps
 import time
@@ -27,13 +28,11 @@ from lxml import etree
 import pytz
 from six import text_type
 
-from logilab.common import tempattr
-
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.pyramid.test import PyramidCWTest
 
 from cubes.oaipmh import utcnow, MetadataFormat, ResumptionToken
-from cubes.oaipmh.entities import OAIComponent, NoRecordsMatch
+from cubes.oaipmh.entities import NoRecordsMatch
 from cubes.oaipmh.views import OAIError, OAIRequest
 
 
@@ -50,6 +49,17 @@ def xmlview_snippet(cnx, eid):
                                          entity.cwuri)
 
 
+ at contextmanager
+def temporary_list_max_size(config, value):
+    optname = 'list-max-size'
+    old_value = config['list-max-size']
+    config.global_set_option(optname, value)
+    try:
+        yield
+    finally:
+        config.global_set_option(optname, old_value)
+
+
 class ResumptionTokenTC(unittest2.TestCase):
 
     def test_none(self):
@@ -186,7 +196,7 @@ class OAIRequestTC(CubicWebTC):
             return OAIRequest('http://testing.fr', setspec='agent', **kwargs)
 
         with self.admin_access.web_request() as req:
-            with tempattr(OAIComponent, 'max_result_size', 1):
+            with temporary_list_max_size(self.config, 1):
                 rset, next_eid = oairq().rset(req)
                 self.assertEqual(len(rset), 1)
                 self.assertEqual(next_eid, str(simpsons.eid))
@@ -465,7 +475,7 @@ class OAIPMHViewsTC(PyramidCWTest, OAITe
         # All results returned, no resumptionToken is request -> no
         # resumptionToken in response.
         self.assertNotIn('resumptionToken', result)
-        with tempattr(OAIComponent, 'max_result_size', 1):
+        with temporary_list_max_size(self.config, 1):
             result = check_request([alice.eid])
             root = etree.fromstring(result)
             token = root.find('.//{%s}resumptionToken' % root.nsmap[None])
@@ -590,7 +600,7 @@ class OAIPMHViewsTC(PyramidCWTest, OAITe
             cnx.commit()
         expected_token = ResumptionToken(newyork.eid, metadata_prefix='oai_dc')
         with self.admin_access.web_request() as req:
-            with tempattr(OAIComponent, 'max_result_size', 1):
+            with temporary_list_max_size(self.config, 1):
                 result = self.oai_request(req, verb='ListRecords',
                                           metadataPrefix='oai_dc')
                 self.assertIn(xmlview_snippet(req, alice.eid), result)
@@ -621,7 +631,7 @@ class OAIPMHViewsTC(PyramidCWTest, OAITe
         # The expected ResumptionToken built from request parameters.
         token = ResumptionToken(newyork.eid, metadata_prefix='oai_dc')
         with self.admin_access.web_request() as req:
-            with tempattr(OAIComponent, 'max_result_size', 1):
+            with temporary_list_max_size(self.config, 1):
                 # First request includes metadataPrefix.
                 result = self.oai_request(req, verb='ListRecords',
                                           metadataPrefix='oai_dc')
@@ -664,7 +674,7 @@ class OAIPMHViewsTC(PyramidCWTest, OAITe
         with self.admin_access.cnx() as cnx:
             bob = agent(cnx, u'bob')
             cnx.commit()
-        with tempattr(OAIComponent, 'max_result_size', 2):
+        with temporary_list_max_size(self.config, 2):
             with self.admin_access.web_request() as req:
                 result = self.oai_request(req, verb='ListRecords',
                                           metadataPrefix='eac_cpf')



More information about the saem-devel mailing list