aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-01-07 22:39:11 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-01-07 22:39:11 +0000
commite9b8a40534df1b0de66ee1d6581ce657a6f9eee9 (patch)
tree6072009c262a4bd31720d0c97d20d3a5dbffbb0c
parent7d28f9bfe052309499d1ce27aa16975697bb5904 (diff)
parent8bbe7cd57d5ac0d5d64cfd25c729dc190a407ee9 (diff)
downloaduritemplates-android11-mainline-cellbroadcast-release.tar.gz
Upgrade python/uritemplates to 3.0.1 am: eab8cbc70c am: 5492dc4462 am: 8bbe7cd57dr_aml_301500702android-mainline-12.0.0_r55android-mainline-11.0.0_r9android-mainline-11.0.0_r8android-mainline-11.0.0_r7android-mainline-11.0.0_r6android-mainline-11.0.0_r5android-mainline-11.0.0_r45android-mainline-11.0.0_r44android-mainline-11.0.0_r43android-mainline-11.0.0_r42android-mainline-11.0.0_r41android-mainline-11.0.0_r40android-mainline-11.0.0_r4android-mainline-11.0.0_r39android-mainline-11.0.0_r38android-mainline-11.0.0_r37android-mainline-11.0.0_r36android-mainline-11.0.0_r35android-mainline-11.0.0_r34android-mainline-11.0.0_r33android-mainline-11.0.0_r32android-mainline-11.0.0_r31android-mainline-11.0.0_r30android-mainline-11.0.0_r3android-mainline-11.0.0_r29android-mainline-11.0.0_r28android-mainline-11.0.0_r27android-mainline-11.0.0_r26android-mainline-11.0.0_r25android-mainline-11.0.0_r24android-mainline-11.0.0_r23android-mainline-11.0.0_r22android-mainline-11.0.0_r21android-mainline-11.0.0_r20android-mainline-11.0.0_r2android-mainline-11.0.0_r19android-mainline-11.0.0_r18android-mainline-11.0.0_r17android-mainline-11.0.0_r16android-mainline-11.0.0_r15android-mainline-11.0.0_r14android-mainline-11.0.0_r13android-mainline-11.0.0_r12android-mainline-11.0.0_r10android-mainline-11.0.0_r1android-11.0.0_r9android-11.0.0_r8android-11.0.0_r7android-11.0.0_r48android-11.0.0_r47android-11.0.0_r46android-11.0.0_r45android-11.0.0_r44android-11.0.0_r43android-11.0.0_r42android-11.0.0_r41android-11.0.0_r40android-11.0.0_r39android-11.0.0_r38android-11.0.0_r37android-11.0.0_r36android-11.0.0_r35android-11.0.0_r34android-11.0.0_r33android-11.0.0_r32android-11.0.0_r31android-11.0.0_r30android-11.0.0_r29android-11.0.0_r28android-11.0.0_r27android-11.0.0_r26android-11.0.0_r24android-11.0.0_r23android-11.0.0_r22android-11.0.0_r21android-11.0.0_r20android-11.0.0_r19android-11.0.0_r18android-11.0.0_r16android-11.0.0_r15android-11.0.0_r14android-11.0.0_r13android-11.0.0_r12android-11.0.0_r11android-11.0.0_r10android11-qpr3-s1-releaseandroid11-qpr3-releaseandroid11-qpr2-releaseandroid11-qpr1-s2-releaseandroid11-qpr1-s1-releaseandroid11-qpr1-releaseandroid11-qpr1-d-s1-releaseandroid11-qpr1-d-releaseandroid11-qpr1-c-releaseandroid11-mainline-tethering-releaseandroid11-mainline-sparse-2021-jan-releaseandroid11-mainline-sparse-2020-dec-releaseandroid11-mainline-releaseandroid11-mainline-permission-releaseandroid11-mainline-os-statsd-releaseandroid11-mainline-networkstack-releaseandroid11-mainline-media-swcodec-releaseandroid11-mainline-media-releaseandroid11-mainline-extservices-releaseandroid11-mainline-documentsui-releaseandroid11-mainline-conscrypt-releaseandroid11-mainline-cellbroadcast-releaseandroid11-mainline-captiveportallogin-releaseandroid11-devandroid11-d2-releaseandroid11-d1-s7-releaseandroid11-d1-s6-releaseandroid11-d1-s5-releaseandroid11-d1-s1-releaseandroid11-d1-releaseandroid11-d1-b-release
Change-Id: I96fe751f9f4633adfdf4610a60536a5f2105ab92
-rw-r--r--.mailmap2
-rw-r--r--.travis.yml10
-rw-r--r--AUTHORS.rst13
-rw-r--r--HISTORY.rst15
-rw-r--r--LICENSE2
-rw-r--r--METADATA12
-rw-r--r--README.rst13
-rw-r--r--old/uritemplate.py/uritemplatepy-setup.py5
-rw-r--r--setup.py24
-rw-r--r--tests/fixtures/extended-tests.json6
-rw-r--r--tests/test_from_fixtures.py5
-rw-r--r--tests/test_uritemplate.py68
-rw-r--r--tox.ini8
-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
18 files changed, 255 insertions, 74 deletions
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..6f9a0eb
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,2 @@
+Ian Stapleton Cordasco <graffatcolmingov@gmail.com> Ian Cordasco <graffatcolmingov@gmail.com>
+Ian Stapleton Cordasco <graffatcolmingov@gmail.com> Ian Cordasco <sigmavirus24@users.noreply.github.com>
diff --git a/.travis.yml b/.travis.yml
index b7c9b48..ec4291e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,16 +3,18 @@ sudo: false
matrix:
include:
- - python: 2.6
- env: TOXENV=py26
- python: 2.7
env: TOXENV=py27
- - python: 3.3
- env: TOXENV=py33
- python: 3.4
env: TOXENV=py34
- python: 3.5
env: TOXENV=py35
+ - python: 3.6
+ env: TOXENV=py36
+ - python: 3.7
+ env: TOXENV=py37
+ - python: 3.8
+ env: TOXENV=py38
- env: TOXENV=pep8
install:
diff --git a/AUTHORS.rst b/AUTHORS.rst
index 55848f0..2581f4d 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -1,4 +1,15 @@
Development Lead
----------------
-- Ian Cordasco <graffatcolmingov@gmail.com>
+- Ian Stapleton Cordasco <graffatcolmingov@gmail.com>
+
+Contributors
+------------
+
+- Brett Cannon
+- Daniel Imhoff
+- Eugene Eeo
+- Jeff Potter
+- Philippe Ombredanne
+- Thierry Bastian
+- Thomas Grainger
diff --git a/HISTORY.rst b/HISTORY.rst
index f04a309..3a84017 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,6 +1,19 @@
Changelog - uritemplate
=======================
+3.0.1 - 2019-12-19
+------------------
+
+- Update to Python 3.6, 3.7, and 3.8
+- Drop support for Python 2.6, 3.2, and 3.3
+- Ignore ``None`` in list argument expansion
+- Handle a list with an empty string appropriately
+
+3.0.0 - 2016-08-29
+------------------
+
+- Match major version number of uritemplate.py
+
2.0.0 - 2016-08-29
------------------
@@ -42,7 +55,7 @@ Changelog - uritemplate.py
0.3.0 - 2013-10-22
------------------
-- Add ``#partial`` to partially expand templates and return new instances of
+- Add ``#partial`` to partially expand templates and return new instances of
``URITemplate``.
0.2.0 - 2013-07-26
diff --git a/LICENSE b/LICENSE
index 26e92ad..41c87e7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,3 @@
This software is made available under the terms of *either* of the licenses
-found in LICENSE.APACHE or LICENSE.BSD. Contributions to uritemplate.py are
+found in LICENSE.APACHE or LICENSE.BSD. Contributions to uritemplate are
made under the terms of *both* these licenses.
diff --git a/METADATA b/METADATA
index b2e2d6c..b41e13f 100644
--- a/METADATA
+++ b/METADATA
@@ -1,7 +1,5 @@
name: "uritemplate"
-description:
- "Simple python library to deal with URI Templates."
-
+description: "Simple python library to deal with URI Templates."
third_party {
url {
type: HOMEPAGE
@@ -11,6 +9,10 @@ third_party {
type: GIT
value: "https://github.com/python-hyper/uritemplate"
}
- version: "3.0.0"
- last_upgrade_date { year: 2018 month: 6 day: 4 }
+ version: "3.0.1"
+ last_upgrade_date {
+ year: 2019
+ month: 12
+ day: 23
+ }
}
diff --git a/README.rst b/README.rst
index 2780d7b..2c9d98d 100644
--- a/README.rst
+++ b/README.rst
@@ -1,7 +1,7 @@
uritemplate
===========
-Documentation_ -- GitHub_ -- BitBucket_ -- Travis-CI_
+Documentation_ -- GitHub_ -- Travis-CI_
Simple python library to deal with `URI Templates`_. The API looks like
@@ -48,7 +48,7 @@ Installing
::
- pip install uritemplate.py
+ pip install uritemplate
License
-------
@@ -56,9 +56,8 @@ License
Modified BSD license_
-.. _Documentation: http://uritemplate.rtfd.org/
-.. _GitHub: https://github.com/sigmavirus24/uritemplate
-.. _BitBucket: https://bitbucket.org/icordasc/uritemplate
-.. _Travis-CI: https://travis-ci.org/sigmavirus24/uritemplate
+.. _Documentation: https://uritemplate.readthedocs.io/
+.. _GitHub: https://github.com/python-hyper/uritemplate
+.. _Travis-CI: https://travis-ci.org/python-hyper/uritemplate
.. _URI Templates: http://tools.ietf.org/html/rfc6570
-.. _license: https://github.com/sigmavirus24/uritemplate/blob/master/LICENSE
+.. _license: https://github.com/python-hyper/uritemplate/blob/master/LICENSE
diff --git a/old/uritemplate.py/uritemplatepy-setup.py b/old/uritemplate.py/uritemplatepy-setup.py
index 430d519..ebececb 100644
--- a/old/uritemplate.py/uritemplatepy-setup.py
+++ b/old/uritemplate.py/uritemplatepy-setup.py
@@ -11,6 +11,7 @@ setup(
author_email="graffatcolmingov@gmail.com",
url="https://uritemplate.readthedocs.org",
install_requires=["uritemplate>=2.0"],
+ python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
classifiers=[
'Development Status :: 5 - Production/Stable',
'License :: OSI Approved',
@@ -19,13 +20,11 @@ setup(
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.2',
- 'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
],
)
diff --git a/setup.py b/setup.py
index 59f03ba..7a09f5e 100644
--- a/setup.py
+++ b/setup.py
@@ -1,3 +1,5 @@
+from io import open
+
from setuptools import setup
from uritemplate import __version__
@@ -6,19 +8,27 @@ packages = [
'uritemplate'
]
+with open("README.rst", encoding="utf-8") as file:
+ readme = file.read()
+
+with open("HISTORY.rst", encoding="utf-8") as file:
+ history = file.read()
+
setup(
name="uritemplate",
version=__version__,
description='URI templates',
- long_description="\n\n".join([open("README.rst").read(),
- open("HISTORY.rst").read()]),
+ long_description="\n\n".join([readme, history]),
+ long_description_content_type="text/x-rst",
license="BSD 3-Clause License or Apache License, Version 2.0",
- author="Ian Cordasco",
+ author="Ian Stapleton Cordasco",
author_email="graffatcolmingov@gmail.com",
url="https://uritemplate.readthedocs.org",
packages=packages,
- package_data={'': ['LICENSE', 'AUTHORS.rst']},
+ package_data={'': ['LICENSE', 'LICENSE.APACHE', 'LICENSE.BSD',
+ 'AUTHORS.rst']},
include_package_data=True,
+ python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
classifiers=[
'Development Status :: 5 - Production/Stable',
'License :: OSI Approved',
@@ -27,13 +37,13 @@ setup(
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.2',
- 'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: Implementation :: CPython',
],
)
diff --git a/tests/fixtures/extended-tests.json b/tests/fixtures/extended-tests.json
index fd69744..ad43ad6 100644
--- a/tests/fixtures/extended-tests.json
+++ b/tests/fixtures/extended-tests.json
@@ -11,7 +11,7 @@
"lang" : "en",
"geocode" : ["37.76","-122.427"],
"first_name" : "John",
- "last.name" : "Doe",
+ "last.name" : "Doe",
"Some%20Thing" : "foo",
"number" : 6,
"long" : 37.76,
@@ -28,7 +28,7 @@
"testcases":[
[ "{/id*}" , "/person" ],
- [ "{/id*}{?fields,first_name,last.name,token}" , [
+ [ "{/id*}{?fields,first_name,last.name,token}" , [
"/person?fields=id,name,picture&first_name=John&last.name=Doe&token=12345",
"/person?fields=id,picture,name&first_name=John&last.name=Doe&token=12345",
"/person?fields=picture,name,id&first_name=John&last.name=Doe&token=12345",
@@ -68,7 +68,7 @@
"testcases":[
[ "{/id*}" , ["/person/albums","/albums/person"] ],
- [ "{/id*}{?fields,token}" , [
+ [ "{/id*}{?fields,token}" , [
"/person/albums?fields=id,name,picture&token=12345",
"/person/albums?fields=id,picture,name&token=12345",
"/person/albums?fields=picture,name,id&token=12345",
diff --git a/tests/test_from_fixtures.py b/tests/test_from_fixtures.py
index 70d6553..d6c9810 100644
--- a/tests/test_from_fixtures.py
+++ b/tests/test_from_fixtures.py
@@ -1,3 +1,4 @@
+import io
import json
import os.path
@@ -12,7 +13,7 @@ def fixture_file_path(filename):
def load_examples(filename):
path = fixture_file_path(filename)
- with open(path, 'r') as examples_file:
+ with io.open(path, 'r', encoding="utf-8") as examples_file:
examples = json.load(examples_file)
return examples
@@ -20,7 +21,7 @@ def load_examples(filename):
def expected_set(expected):
if isinstance(expected, list):
return set(expected)
- return set([expected])
+ return {expected}
class FixtureMixin(object):
diff --git a/tests/test_uritemplate.py b/tests/test_uritemplate.py
index b1abc96..f67ad26 100644
--- a/tests/test_uritemplate.py
+++ b/tests/test_uritemplate.py
@@ -464,6 +464,52 @@ class TestURITemplate(RFCTemplateExamples('RFCMeta', (TestCase,), {})):
None
)
+ def test_label_path_expansion_explode_slash(self):
+ t = URITemplate('{/foo*}')
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', [], True, '/'), None
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', [None], True, '/'), None
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', [None, None], True, '/'), None
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', ['one'], True, '/'), 'one'
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', ['one', 'two'], True, '/'), 'one/two'
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', ['one', None, 'two'], True, '/'), 'one/two'
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', [''], True, '/'), ''
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', ['', ''], True, '/'), '/'
+ )
+
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', {}, True, '/'), None
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', {'one': ''}, True, '/'), 'one='
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', {'one': '', 'two': ''}, True, '/'), 'one=/two='
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', {'one': None}, True, '/'), None
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', {'one': None, 'two': 'two'}, True, '/'), 'two=two'
+ )
+ self.assertEqual(t.variables[0]._label_path_expansion(
+ 'foo', {'one': None, 'two': None}, True, '/'), None
+ )
+
def test_semi_path_expansion(self):
t = URITemplate('{foo}')
v = t.variables[0]
@@ -544,24 +590,24 @@ class TestURIVariable(TestCase):
class TestVariableModule(TestCase):
def test_is_list_of_tuples(self):
- l = [(1, 2), (3, 4)]
- self.assertEqual(variable.is_list_of_tuples(l), (True, l))
+ a_list = [(1, 2), (3, 4)]
+ self.assertEqual(variable.is_list_of_tuples(a_list), (True, a_list))
- l = [1, 2, 3, 4]
- self.assertEqual(variable.is_list_of_tuples(l), (False, None))
+ a_list = [1, 2, 3, 4]
+ self.assertEqual(variable.is_list_of_tuples(a_list), (False, None))
def test_list_test(self):
- l = [1, 2, 3, 4]
- self.assertEqual(variable.list_test(l), True)
+ a_list = [1, 2, 3, 4]
+ self.assertEqual(variable.list_test(a_list), True)
- l = str([1, 2, 3, 4])
- self.assertEqual(variable.list_test(l), False)
+ a_list = str([1, 2, 3, 4])
+ self.assertEqual(variable.list_test(a_list), False)
def test_list_of_tuples_test(self):
- l = [(1, 2), (3, 4)]
- self.assertEqual(variable.dict_test(l), False)
+ a_list = [(1, 2), (3, 4)]
+ self.assertEqual(variable.dict_test(a_list), False)
- d = dict(l)
+ d = dict(a_list)
self.assertEqual(variable.dict_test(d), True)
diff --git a/tox.ini b/tox.ini
index 9d86da0..ed27494 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,17 +1,17 @@
[tox]
envlist =
- py26,
py27,
- py32,
- py33,
py34,
py35,
+ py36,
+ py37,
+ py38,
pep8,
[testenv]
deps =
pytest
-commands = py.test {posargs}
+commands = pytest {posargs}
[testenv:pep8]
deps =
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: