From 52fa015d9ea3b88c25db0f615f728a6d4d766186 Mon Sep 17 00:00:00 2001 From: Ian Stapleton Cordasco Date: Fri, 21 Jul 2017 19:41:29 -0500 Subject: [PATCH 1/2] Add basic Validation for URITemplates Closes #33 --- tests/test_validator.py | 43 +++++++++++++++++++++++++++++ uritemplate/__init__.py | 5 ++-- uritemplate/exceptions.py | 31 +++++++++++++++++++++ uritemplate/validator.py | 58 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 tests/test_validator.py create mode 100644 uritemplate/exceptions.py create mode 100644 uritemplate/validator.py diff --git a/tests/test_validator.py b/tests/test_validator.py new file mode 100644 index 0000000..cf89fc1 --- /dev/null +++ b/tests/test_validator.py @@ -0,0 +1,43 @@ +"""Tests for the uritemplate.Validator class.""" +import uritemplate +from uritemplate import exceptions + +import pytest + + +@pytest.mark.parametrize('template', [ + 'https://github.com{/user}', + 'https://github.com/sigmavirus24{/repository}', + '{foo}', + '?{bar}', + 'https://example.com', +]) +def test_valid_uris(template): + """Verify we don't raise an exception.""" + urit = uritemplate.URITemplate(template) + uritemplate.Validator().validate(urit) + + +@pytest.mark.parametrize('template', [ + 'https://github.com{/user', + 'https://github.com/sigmavirus24/repository}', + '{foo}}', + '?{{bar}', +]) +def test_invalid_uris(template): + """Verify we catch invalid URITemplates.""" + urit = uritemplate.URITemplate(template) + with pytest.raises(exceptions.InvalidTemplate): + uritemplate.Validator().validate(urit) + + +@pytest.mark.parametrize('template', [ + 'https://github.com{/user', + 'https://github.com/sigmavirus24/repository}', + '{foo}}', + '?{{bar}', +]) +def test_allow_invalid_uris(template): + """Verify we allow invalid URITemplates.""" + urit = uritemplate.URITemplate(template) + uritemplate.Validator().allow_unbalanced_braces().validate(urit) diff --git a/uritemplate/__init__.py b/uritemplate/__init__.py index 40c0320..4427a08 100644 --- a/uritemplate/__init__.py +++ b/uritemplate/__init__.py @@ -16,11 +16,12 @@ __author__ = 'Ian Cordasco' __license__ = 'Modified BSD or Apache License, Version 2.0' __copyright__ = 'Copyright 2013 Ian Cordasco' -__version__ = '3.0.0' +__version__ = '3.1.0' __version_info__ = tuple(int(i) for i in __version__.split('.') if i.isdigit()) from uritemplate.api import ( URITemplate, expand, partial, variables # noqa: E402 ) +from uritemplate.validator import Validator # noqa: E402 -__all__ = ('URITemplate', 'expand', 'partial', 'variables') +__all__ = ('URITemplate', 'Validator', 'expand', 'partial', 'variables') diff --git a/uritemplate/exceptions.py b/uritemplate/exceptions.py new file mode 100644 index 0000000..caf6f97 --- /dev/null +++ b/uritemplate/exceptions.py @@ -0,0 +1,31 @@ +"""Module containing all exceptions for the uritemplate module.""" + + +class TemplateException(Exception): + """Base Exception class for all uritemplate exceptions.""" + + pass + + +class InvalidTemplate(TemplateException): + """Base class for template validation.""" + + message = "The URI template ({}) is invalid." + + def __init__(self, uri, *args): + """Initialize our exception.""" + super(InvalidTemplate, self).__init__(self.message.format(uri, *args)) + self.uri = uri + + +class UnbalancedBraces(InvalidTemplate): + """The template has unbalanced braces.""" + + message = "The URI template ({}) has more {} braces than {} braces." + + def __init__(self, uri, left_braces_count, right_braces_count): + """Initialize our exception.""" + more, less = 'left', 'right' + if left_braces_count < right_braces_count: + more, less = less, more + super(UnbalancedBraces, self).__init__(uri, more, less) diff --git a/uritemplate/validator.py b/uritemplate/validator.py new file mode 100644 index 0000000..07552b9 --- /dev/null +++ b/uritemplate/validator.py @@ -0,0 +1,58 @@ +"""Module containing all the validation logic for uritemplate.""" +from uritemplate import exceptions as exc + + +class Validator(object): + """Provide configurable validation of URITemplate objects. + + .. versionadded:: 3.1.0 + + .. code-block:: + + from uritemplate import URITemplate, Validator + + + """ + + def __init__(self): + """Initialize our validator.""" + self.enforcing_unbalanced_braces = True + + def allow_unbalanced_braces(self): + """Allow a template to have unbalanced braces. + + .. versionadded:: 3.1.0 + + Returns the validator instance. + """ + self.enforcing_unbalanced_braces = False + return self + + def force_balanced_braces(self): + """Force a template to have balanced braces. + + .. versionadded:: 3.1.0 + + Returns the validator instance. + """ + self.enforcing_unbalanced_braces = True + return self + + def validate(self, template): + """Validate that a template meets the parameters. + + .. versionadded:: 3.1.0 + + :raises: uritemplate.exceptions.InvalidTemplate + :raises: uritemplate.exceptions.UnbalancedBraces + """ + if self.enforcing_unbalanced_braces: + _enforce_balanced_braces(template) + + +def _enforce_balanced_braces(template): + uri = template.uri + left_braces = uri.count('{') + right_braces = uri.count('}') + if left_braces != right_braces: + raise exc.UnbalancedBraces(uri, left_braces, right_braces) From a3dd055c6ceadccbd9a7691259e941be217f7bb4 Mon Sep 17 00:00:00 2001 From: Ian Stapleton Cordasco Date: Fri, 21 Jul 2017 20:01:18 -0500 Subject: [PATCH 2/2] Use numbered substitions for python 2.6 --- uritemplate/exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uritemplate/exceptions.py b/uritemplate/exceptions.py index caf6f97..8edac8f 100644 --- a/uritemplate/exceptions.py +++ b/uritemplate/exceptions.py @@ -10,7 +10,7 @@ class TemplateException(Exception): class InvalidTemplate(TemplateException): """Base class for template validation.""" - message = "The URI template ({}) is invalid." + message = "The URI template ({0}) is invalid." def __init__(self, uri, *args): """Initialize our exception.""" @@ -21,7 +21,7 @@ def __init__(self, uri, *args): class UnbalancedBraces(InvalidTemplate): """The template has unbalanced braces.""" - message = "The URI template ({}) has more {} braces than {} braces." + message = "The URI template ({0}) has more {1} braces than {2} braces." def __init__(self, uri, left_braces_count, right_braces_count): """Initialize our exception."""