aboutsummaryrefslogtreecommitdiff
path: root/uritemplate
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-01-07 14:06:28 -0800
committerandroid-build-merger <android-build-merger@google.com>2020-01-07 14:06:28 -0800
commit5492dc4462f38ec23ff1cd58f66f8d19cd23f04b (patch)
tree6072009c262a4bd31720d0c97d20d3a5dbffbb0c /uritemplate
parentb7137cc2f5b626d8d644ccd8866c4dab837bbd99 (diff)
parenteab8cbc70cc7907afb0105d11ebf812aa99c11d0 (diff)
downloaduritemplates-5492dc4462f38ec23ff1cd58f66f8d19cd23f04b.tar.gz
Upgrade python/uritemplates to 3.0.1
am: eab8cbc70c Change-Id: Ib1cf1d8c27befad71731abd470cb3eb7e73044ed
Diffstat (limited to 'uritemplate')
-rw-r--r--uritemplate/__init__.py2
-rw-r--r--uritemplate/api.py4
-rw-r--r--uritemplate/orderedset.py90
-rw-r--r--uritemplate/template.py8
-rw-r--r--uritemplate/variable.py42
5 files changed, 121 insertions, 25 deletions
diff --git a/uritemplate/__init__.py b/uritemplate/__init__.py
index 40c0320..5352520 100644
--- a/uritemplate/__init__.py
+++ b/uritemplate/__init__.py
@@ -16,7 +16,7 @@ __title__ = 'uritemplate'
__author__ = 'Ian Cordasco'
__license__ = 'Modified BSD or Apache License, Version 2.0'
__copyright__ = 'Copyright 2013 Ian Cordasco'
-__version__ = '3.0.0'
+__version__ = '3.0.1'
__version_info__ = tuple(int(i) for i in __version__.split('.') if i.isdigit())
from uritemplate.api import (
diff --git a/uritemplate/api.py b/uritemplate/api.py
index 37c7c45..5ad2815 100644
--- a/uritemplate/api.py
+++ b/uritemplate/api.py
@@ -6,6 +6,8 @@ uritemplate.api
This module contains the very simple API provided by uritemplate.
"""
+
+from uritemplate.orderedset import OrderedSet
from uritemplate.template import URITemplate
@@ -68,4 +70,4 @@ def variables(uri):
# => {'username', 'repository'}
"""
- return set(URITemplate(uri).variable_names)
+ return OrderedSet(URITemplate(uri).variable_names)
diff --git a/uritemplate/orderedset.py b/uritemplate/orderedset.py
new file mode 100644
index 0000000..f21c9cb
--- /dev/null
+++ b/uritemplate/orderedset.py
@@ -0,0 +1,90 @@
+# From: https://github.com/ActiveState/code/blob/master/recipes/Python/576696_OrderedSet_with_Weakrefs/ # noqa
+
+from weakref import proxy
+
+try:
+ import collections.abc as collections_abc
+except ImportError:
+ import collections as collections_abc
+
+
+class Link(object):
+ __slots__ = 'prev', 'next', 'key', '__weakref__'
+
+
+class OrderedSet(collections_abc.MutableSet):
+ 'Set the remembers the order elements were added'
+ # Big-O running times for all methods are the same as for regular sets.
+ # The internal self.__map dictionary maps keys to links in a doubly linked
+ # list. The circular doubly linked list starts and ends with a sentinel
+ # element. The sentinel element never gets deleted (this simplifies the
+ # algorithm). The prev/next links are weakref proxies (to prevent circular
+ # references). Individual links are kept alive by the hard reference in
+ # self.__map. Those hard references disappear when a key is deleted from
+ # an OrderedSet.
+
+ def __init__(self, iterable=None):
+ self.__root = root = Link() # sentinel node for doubly linked list
+ root.prev = root.next = root
+ self.__map = {} # key --> link
+ if iterable is not None:
+ self |= iterable
+
+ def __len__(self):
+ return len(self.__map)
+
+ def __contains__(self, key):
+ return key in self.__map
+
+ def add(self, key):
+ # Store new key in a new link at the end of the linked list
+ if key not in self.__map:
+ self.__map[key] = link = Link()
+ root = self.__root
+ last = root.prev
+ link.prev, link.next, link.key = last, root, key
+ last.next = root.prev = proxy(link)
+
+ def discard(self, key):
+ # Remove an existing item using self.__map to find the link which is
+ # then removed by updating the links in the predecessor and successors.
+ if key in self.__map:
+ link = self.__map.pop(key)
+ link.prev.next = link.next
+ link.next.prev = link.prev
+
+ def __iter__(self):
+ # Traverse the linked list in order.
+ root = self.__root
+ curr = root.next
+ while curr is not root:
+ yield curr.key
+ curr = curr.next
+
+ def __reversed__(self):
+ # Traverse the linked list in reverse order.
+ root = self.__root
+ curr = root.prev
+ while curr is not root:
+ yield curr.key
+ curr = curr.prev
+
+ def pop(self, last=True):
+ if not self:
+ raise KeyError('set is empty')
+ key = next(reversed(self)) if last else next(iter(self))
+ self.discard(key)
+ return key
+
+ def __repr__(self):
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, list(self))
+
+ def __str__(self):
+ return self.__repr__()
+
+ def __eq__(self, other):
+ if isinstance(other, OrderedSet):
+ return len(self) == len(other) and list(self) == list(other)
+ return not self.isdisjoint(other)
diff --git a/uritemplate/template.py b/uritemplate/template.py
index c9d7c7e..0df0da6 100644
--- a/uritemplate/template.py
+++ b/uritemplate/template.py
@@ -16,9 +16,10 @@ What do you do?
"""
import re
+from uritemplate.orderedset import OrderedSet
from uritemplate.variable import URIVariable
-template_re = re.compile('{([^\}]+)}')
+template_re = re.compile('{([^}]+)}')
def _merge(var_dict, overrides):
@@ -71,9 +72,10 @@ class URITemplate(object):
URIVariable(m.groups()[0]) for m in template_re.finditer(self.uri)
]
#: A set of variable names in the URI.
- self.variable_names = set()
+ self.variable_names = OrderedSet()
for variable in self.variables:
- self.variable_names.update(variable.variable_names)
+ for name in variable.variable_names:
+ self.variable_names.add(name)
def __repr__(self):
return 'URITemplate("%s")' % self
diff --git a/uritemplate/variable.py b/uritemplate/variable.py
index 1842830..ce3f652 100644
--- a/uritemplate/variable.py
+++ b/uritemplate/variable.py
@@ -15,12 +15,16 @@ What do you do?
"""
-import collections
import sys
-if (2, 6) <= sys.version_info < (2, 8):
+try:
+ import collections.abc as collections_abc
+except ImportError:
+ import collections as collections_abc
+
+if sys.version_info.major == 2:
import urllib
-elif (3, 3) <= sys.version_info < (4, 0):
+elif sys.version_info.major == 3:
import urllib.parse as urllib
@@ -149,11 +153,11 @@ class URIVariable(object):
return None
if explode:
return self.join_str.join(
- '%s=%s' % (name, quote(v, safe)) for v in value
+ '{}={}'.format(name, quote(v, safe)) for v in value
)
else:
value = ','.join(quote(v, safe) for v in value)
- return '%s=%s' % (name, value)
+ return '{}={}'.format(name, value)
if dict_test(value) or tuples:
if not value:
@@ -161,21 +165,21 @@ class URIVariable(object):
items = items or sorted(value.items())
if explode:
return self.join_str.join(
- '%s=%s' % (
+ '{}={}'.format(
quote(k, safe), quote(v, safe)
) for k, v in items
)
else:
value = ','.join(
- '%s,%s' % (
+ '{},{}'.format(
quote(k, safe), quote(v, safe)
) for k, v in items
)
- return '%s=%s' % (name, value)
+ return '{}={}'.format(name, value)
if value:
value = value[:prefix] if prefix else value
- return '%s=%s' % (name, quote(value, safe))
+ return '{}={}'.format(name, quote(value, safe))
return name + '='
def _label_path_expansion(self, name, value, explode, prefix):
@@ -196,10 +200,8 @@ class URIVariable(object):
if not explode:
join_str = ','
- expanded = join_str.join(
- quote(v, safe) for v in value if value is not None
- )
- return expanded if expanded else None
+ fragments = [quote(v, safe) for v in value if v is not None]
+ return join_str.join(fragments) if fragments else None
if dict_test(value) or tuples:
items = items or sorted(value.items())
@@ -234,35 +236,35 @@ class URIVariable(object):
if list_test(value) and not tuples:
if explode:
expanded = join_str.join(
- '%s=%s' % (
+ '{}={}'.format(
name, quote(v, safe)
) for v in value if v is not None
)
return expanded if expanded else None
else:
value = ','.join(quote(v, safe) for v in value)
- return '%s=%s' % (name, value)
+ return '{}={}'.format(name, value)
if dict_test(value) or tuples:
items = items or sorted(value.items())
if explode:
return join_str.join(
- '%s=%s' % (
+ '{}={}'.format(
quote(k, safe), quote(v, safe)
) for k, v in items if v is not None
)
else:
expanded = ','.join(
- '%s,%s' % (
+ '{},{}'.format(
quote(k, safe), quote(v, safe)
) for k, v in items if v is not None
)
- return '%s=%s' % (name, expanded)
+ return '{}={}'.format(name, expanded)
value = value[:prefix] if prefix else value
if value:
- return '%s=%s' % (name, quote(value, safe))
+ return '{}={}'.format(name, quote(value, safe))
return name
@@ -360,7 +362,7 @@ def list_test(value):
def dict_test(value):
- return isinstance(value, (dict, collections.MutableMapping))
+ return isinstance(value, (dict, collections_abc.MutableMapping))
try: