summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Merickel <michael@merickel.org>2018-09-27 22:18:56 -0500
committerMichael Merickel <michael@merickel.org>2018-09-27 22:18:56 -0500
commitf2294fb6969a7bc04642f2f987dec5ee131ad98c (patch)
treebdd0a74c67c9d8b0610ca47f2bf465a6ac00dcc0
parent58d2a5f14bb787defefe7a2b1b36665c4991c0da (diff)
downloadpyramid-f2294fb6969a7bc04642f2f987dec5ee131ad98c.tar.gz
pyramid-f2294fb6969a7bc04642f2f987dec5ee131ad98c.tar.bz2
pyramid-f2294fb6969a7bc04642f2f987dec5ee131ad98c.zip
move sort_accept_offers to pyramid.config.util
keeping this code isolated for now as it's kind of crazy
-rw-r--r--pyramid/config/util.py76
-rw-r--r--pyramid/config/views.py2
-rw-r--r--pyramid/tests/test_config/test_util.py59
-rw-r--r--pyramid/tests/test_util.py60
-rw-r--r--pyramid/util.py77
5 files changed, 136 insertions, 138 deletions
diff --git a/pyramid/config/util.py b/pyramid/config/util.py
index aedebd9e2..7024fa862 100644
--- a/pyramid/config/util.py
+++ b/pyramid/config/util.py
@@ -1,6 +1,7 @@
import functools
from hashlib import md5
import traceback
+from webob.acceptparse import Accept
from zope.interface import implementer
from pyramid.compat import (
@@ -218,3 +219,78 @@ class PredicateList(object):
score = score | bit
order = (MAX_ORDER - score) / (len(preds) + 1)
return order, preds, phash.hexdigest()
+
+
+def sort_accept_offers(offers, order=None):
+ """
+ Sort a list of offers by specificity and preference.
+
+ Supported offers are of the following forms, ordered by specificity
+ (higher to lower):
+
+ - ``type/subtype;params`` and ``type/subtype``
+ - ``type/*``
+ - ``*/*``
+
+ :param offers: A list of offers to be sorted.
+ :param order: A weighted list of offers where items closer to the start of
+ the list will be a preferred over items closer to the end.
+ :return: A list of offers sorted first by specificity (higher to lower)
+ then by ``order``.
+
+ """
+ if order is None:
+ order = []
+
+ max_weight = len(offers)
+
+ def find_order_index(value, default=None):
+ return next((i for i, x in enumerate(order) if x == value), default)
+
+ def offer_sort_key(value):
+ """
+ (category, type_weight, params_weight)
+
+ category:
+ 1 - foo/bar and foo/bar;params
+ 2 - foo/*
+ 3 - */*
+
+ type_weight:
+ if category 1 & 2:
+ - index of type/* in order list
+ - ``max_weight`` if no match is found
+
+ - index of type/subtype in order list
+ - index of type/* in order list + ``max_weight``
+ - ``max_weight * 2`` if no match is found
+
+ params_weight:
+ - index of specific ``type/subtype;params`` in order list
+ - ``max_weight`` if not found
+ - ``max_weight + 1`` if no params at all
+
+ """
+ parsed = Accept.parse_offer(value)
+
+ if value == '*/*':
+ return (3, 0, 0)
+
+ elif parsed.subtype == '*':
+ type_w = find_order_index(value, max_weight)
+ return (2, type_w, 0)
+
+ type_w = find_order_index(parsed.type + '/' + parsed.subtype, None)
+ if type_w is None:
+ type_w = max_weight + find_order_index(
+ parsed.type + '/*', max_weight)
+
+ if parsed.params:
+ param_w = find_order_index(value, max_weight)
+
+ else:
+ param_w = max_weight + 1
+
+ return (1, type_w, param_w)
+
+ return sorted(offers, key=offer_sort_key)
diff --git a/pyramid/config/views.py b/pyramid/config/views.py
index e40a851ff..26e86d7d3 100644
--- a/pyramid/config/views.py
+++ b/pyramid/config/views.py
@@ -68,7 +68,6 @@ from pyramid.view import AppendSlashNotFoundViewFactory
from pyramid.util import (
as_sorted_tuple,
- sort_accept_offers,
TopologicalSorter,
)
@@ -90,6 +89,7 @@ from pyramid.config.util import (
DEFAULT_PHASH,
MAX_ORDER,
predvalseq,
+ sort_accept_offers,
)
urljoin = urlparse.urljoin
diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py
index 99c67e8c6..bbda615c9 100644
--- a/pyramid/tests/test_config/test_util.py
+++ b/pyramid/tests/test_config/test_util.py
@@ -431,6 +431,65 @@ class TestDeprecatedPredicates(unittest.TestCase):
from pyramid.config.predicates import XHRPredicate
self.assertEqual(len(w), 1)
+class Test_sort_accept_offers(unittest.TestCase):
+ def _callFUT(self, offers, order=None):
+ from pyramid.config.util import sort_accept_offers
+ return sort_accept_offers(offers, order)
+
+ def test_default_specificities(self):
+ result = self._callFUT(['*/*', 'text/*', 'text/html', 'text/html;charset=utf8'])
+ self.assertEqual(result, [
+ 'text/html;charset=utf8', 'text/html', 'text/*', '*/*',
+ ])
+
+ def test_wildcard_type_order(self):
+ result = self._callFUT(
+ ['*/*', 'text/*', 'image/*'],
+ ['image/*', 'text/*'],
+ )
+ self.assertEqual(result, ['image/*', 'text/*', '*/*'])
+
+ def test_specific_type_order(self):
+ result = self._callFUT(
+ ['text/html', 'application/json', 'text/html;charset=utf8', 'text/plain'],
+ ['application/json', 'text/html'],
+ )
+ self.assertEqual(result, [
+ 'application/json', 'text/html;charset=utf8', 'text/html', 'text/plain',
+ ])
+
+ def test_params_order(self):
+ result = self._callFUT(
+ ['text/html;charset=utf8', 'text/html;charset=latin1', 'text/html;foo=bar'],
+ ['text/html;charset=latin1', 'text/html;charset=utf8'],
+ )
+ self.assertEqual(result, [
+ 'text/html;charset=latin1', 'text/html;charset=utf8', 'text/html;foo=bar',
+ ])
+
+ def test_params_inherit_type_prefs(self):
+ result = self._callFUT(
+ ['text/html;charset=utf8', 'text/plain;charset=latin1'],
+ ['text/plain', 'text/html'],
+ )
+ self.assertEqual(result, ['text/plain;charset=latin1', 'text/html;charset=utf8'])
+
+ def test_params_inherit_wildcard_prefs(self):
+ result = self._callFUT(
+ ['image/png;progressive=1', 'text/html;charset=utf8'],
+ ['text/*', 'image/*'],
+ )
+ self.assertEqual(result, ['text/html;charset=utf8', 'image/png;progressive=1'])
+
+ def test_type_overrides_wildcard_prefs(self):
+ result = self._callFUT(
+ ['text/html;charset=utf8', 'image/png', 'foo/bar', 'text/bar'],
+ ['foo/*', 'text/*', 'image/*', 'image/png', 'text/html'],
+ )
+ self.assertEqual(result, [
+ 'image/png', 'text/html;charset=utf8', 'foo/bar', 'text/bar',
+ ])
+
class DummyCustomPredicate(object):
def __init__(self):
self.__text__ = 'custom predicate'
diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py
index 907ca7351..a76cd2017 100644
--- a/pyramid/tests/test_util.py
+++ b/pyramid/tests/test_util.py
@@ -1109,63 +1109,3 @@ class TestSimpleSerializer(unittest.TestCase):
def test_dumps(self):
inst = self._makeOne()
self.assertEqual(inst.dumps('abc'), bytes_('abc'))
-
-
-class Test_sort_accept_offers(unittest.TestCase):
- def _callFUT(self, offers, order=None):
- from pyramid.util import sort_accept_offers
- return sort_accept_offers(offers, order)
-
- def test_default_specificities(self):
- result = self._callFUT(['*/*', 'text/*', 'text/html', 'text/html;charset=utf8'])
- self.assertEqual(result, [
- 'text/html;charset=utf8', 'text/html', 'text/*', '*/*',
- ])
-
- def test_wildcard_type_order(self):
- result = self._callFUT(
- ['*/*', 'text/*', 'image/*'],
- ['image/*', 'text/*'],
- )
- self.assertEqual(result, ['image/*', 'text/*', '*/*'])
-
- def test_specific_type_order(self):
- result = self._callFUT(
- ['text/html', 'application/json', 'text/html;charset=utf8', 'text/plain'],
- ['application/json', 'text/html'],
- )
- self.assertEqual(result, [
- 'application/json', 'text/html;charset=utf8', 'text/html', 'text/plain',
- ])
-
- def test_params_order(self):
- result = self._callFUT(
- ['text/html;charset=utf8', 'text/html;charset=latin1', 'text/html;foo=bar'],
- ['text/html;charset=latin1', 'text/html;charset=utf8'],
- )
- self.assertEqual(result, [
- 'text/html;charset=latin1', 'text/html;charset=utf8', 'text/html;foo=bar',
- ])
-
- def test_params_inherit_type_prefs(self):
- result = self._callFUT(
- ['text/html;charset=utf8', 'text/plain;charset=latin1'],
- ['text/plain', 'text/html'],
- )
- self.assertEqual(result, ['text/plain;charset=latin1', 'text/html;charset=utf8'])
-
- def test_params_inherit_wildcard_prefs(self):
- result = self._callFUT(
- ['image/png;progressive=1', 'text/html;charset=utf8'],
- ['text/*', 'image/*'],
- )
- self.assertEqual(result, ['text/html;charset=utf8', 'image/png;progressive=1'])
-
- def test_type_overrides_wildcard_prefs(self):
- result = self._callFUT(
- ['text/html;charset=utf8', 'image/png', 'foo/bar', 'text/bar'],
- ['foo/*', 'text/*', 'image/*', 'image/png', 'text/html'],
- )
- self.assertEqual(result, [
- 'image/png', 'text/html;charset=utf8', 'foo/bar', 'text/bar',
- ])
diff --git a/pyramid/util.py b/pyramid/util.py
index 708931eea..6655455bf 100644
--- a/pyramid/util.py
+++ b/pyramid/util.py
@@ -1,5 +1,3 @@
-from collections import defaultdict
-from collections import namedtuple
from contextlib import contextmanager
import functools
try:
@@ -9,7 +7,6 @@ except ImportError: # pragma: no cover
compare_digest = None
import inspect
import weakref
-from webob.acceptparse import Accept
from pyramid.exceptions import (
ConfigurationError,
@@ -652,77 +649,3 @@ class SimpleSerializer(object):
def dumps(self, appstruct):
return bytes_(appstruct)
-
-def sort_accept_offers(offers, order=None):
- """
- Sort a list of offers by specificity and preference.
-
- Supported offers are of the following forms, ordered by specificity
- (higher to lower):
-
- - ``type/subtype;params`` and ``type/subtype``
- - ``type/*``
- - ``*/*``
-
- :param offers: A list of offers to be sorted.
- :param order: A weighted list of offers where items closer to the start of
- the list will be a preferred over items closer to the end.
- :return: A list of offers sorted first by specificity (higher to lower)
- then by ``order``.
-
- """
- if order is None:
- order = []
-
- max_weight = len(offers)
-
- def find_order_index(value, default=None):
- return next((i for i, x in enumerate(order) if x == value), default)
-
- def offer_sort_key(value):
- """
- (category, type_weight, params_weight)
-
- category:
- 1 - foo/bar and foo/bar;params
- 2 - foo/*
- 3 - */*
-
- type_weight:
- if category 1 & 2:
- - index of type/* in order list
- - ``max_weight`` if no match is found
-
- - index of type/subtype in order list
- - index of type/* in order list + ``max_weight``
- - ``max_weight * 2`` if no match is found
-
- params_weight:
- - index of specific ``type/subtype;params`` in order list
- - ``max_weight`` if not found
- - ``max_weight + 1`` if no params at all
-
- """
- parsed = Accept.parse_offer(value)
-
- if value == '*/*':
- return (3, 0, 0)
-
- elif parsed.subtype == '*':
- type_w = find_order_index(value, max_weight)
- return (2, type_w, 0)
-
- type_w = find_order_index(parsed.type + '/' + parsed.subtype, None)
- if type_w is None:
- type_w = max_weight + find_order_index(
- parsed.type + '/*', max_weight)
-
- if parsed.params:
- param_w = find_order_index(value, max_weight)
-
- else:
- param_w = max_weight + 1
-
- return (1, type_w, param_w)
-
- return sorted(offers, key=offer_sort_key)