Пример #1
0
class URLObjectModificationTest(unittest.TestCase):

    def setUp(self):
        self.url = URLObject('https://github.com/zacharyvoase/urlobject?spam=eggs#foo')

    def test_with_scheme_replaces_scheme(self):
        assert (self.url.with_scheme('http') ==
                'http://github.com/zacharyvoase/urlobject?spam=eggs#foo')

    def test_with_netloc_replaces_netloc(self):
        assert (self.url.with_netloc('example.com') ==
                'https://example.com/zacharyvoase/urlobject?spam=eggs#foo')

    def test_with_hostname_replaces_hostname(self):
        url = URLObject('https://*****:*****@github.com/')
        assert (url.with_hostname('example.com') ==
                'https://*****:*****@example.com/')

    def test_with_username_adds_username(self):
        url = URLObject('https://github.com/')
        assert url.with_username('zack') == 'https://[email protected]/'

    def test_with_username_replaces_username(self):
        url = URLObject('https://[email protected]/')
        assert url.with_username('alice') == 'https://[email protected]/'

    def test_without_username_removes_username(self):
        url = URLObject('https://[email protected]/')
        assert url.without_username() == 'https://github.com/'

    def test_with_password_adds_password(self):
        url = URLObject('https://[email protected]/')
        assert url.with_password('1234') == 'https://*****:*****@github.com/'

    def test_with_password_raises_ValueError_when_there_is_no_username(self):
        url = URLObject('https://github.com/')
        assert_raises(ValueError, lambda: url.with_password('1234'))

    def test_with_password_replaces_password(self):
        url = URLObject('https://*****:*****@github.com/')
        assert url.with_password('5678') == 'https://*****:*****@github.com/'

    def test_without_password_removes_password(self):
        url = URLObject('https://*****:*****@github.com/')
        assert url.without_password() == 'https://[email protected]/'

    def test_with_auth_with_one_arg_adds_username(self):
        url = URLObject('https://github.com/')
        assert url.with_auth('zack') == 'https://[email protected]/'

    def test_with_auth_with_one_arg_replaces_whole_auth_string_with_username(self):
        url = URLObject('https://*****:*****@github.com/')
        assert url.with_auth('zack') == 'https://[email protected]/'

    def test_with_auth_with_two_args_adds_username_and_password(self):
        url = URLObject('https://github.com/')
        assert url.with_auth('zack', '1234') == 'https://*****:*****@github.com/'

    def test_with_auth_with_two_args_replaces_whole_auth_string_with_username_and_password(self):
        # Replaces username-only auth string
        url = URLObject('https://[email protected]/')
        assert url.with_auth('zack', '1234') == 'https://*****:*****@github.com/'

        # Replaces username and password.
        url = URLObject('https://*****:*****@github.com/')
        assert url.with_auth('zack', '1234') == 'https://*****:*****@github.com/'

    def test_without_auth_removes_entire_auth_string(self):
        # No username or password => no-op.
        url = URLObject('https://github.com/')
        assert url.without_auth() == 'https://github.com/'
        # Username-only.
        url = URLObject('https://[email protected]/')
        assert url.without_auth() == 'https://github.com/'
        # Username and password.
        url = URLObject('https://*****:*****@github.com/')
        assert url.without_auth() == 'https://github.com/'

    def test_with_port_adds_port_number(self):
        assert (self.url.with_port(24) ==
                'https://github.com:24/zacharyvoase/urlobject?spam=eggs#foo')

    def test_with_port_replaces_port_number(self):
        url = URLObject('https://github.com:59/')
        assert url.with_port(67) == 'https://github.com:67/'

    def test_without_port_removes_port_number(self):
        url = URLObject('https://github.com:59/')
        assert url.without_port() == 'https://github.com/'

    def test_with_path_replaces_path(self):
        assert (self.url.with_path('/dvxhouse/intessa') ==
                'https://github.com/dvxhouse/intessa?spam=eggs#foo')

    def test_root_goes_to_root_path(self):
        assert self.url.root == 'https://github.com/?spam=eggs#foo'

    def test_parent_jumps_up_one_level(self):
        url = URLObject('https://github.com/zacharyvoase/urlobject')
        assert url.parent == 'https://github.com/zacharyvoase/'
        assert url.parent.parent == 'https://github.com/'

    def test_add_path_segment_adds_a_path_segment(self):
        url = URLObject('https://github.com/zacharyvoase/urlobject')
        assert (url.add_path_segment('tree') ==
                'https://github.com/zacharyvoase/urlobject/tree')
        assert (url.add_path_segment('tree/master') ==
                'https://github.com/zacharyvoase/urlobject/tree%2Fmaster')

    def test_add_path_adds_a_partial_path(self):
        url = URLObject('https://github.com/zacharyvoase/urlobject')
        assert (url.add_path('tree') ==
                'https://github.com/zacharyvoase/urlobject/tree')
        assert (url.add_path('tree/master') ==
                'https://github.com/zacharyvoase/urlobject/tree/master')

    def test_is_leaf(self):
        assert URLObject('https://github.com/zacharyvoase/urlobject').is_leaf
        assert not URLObject('https://github.com/zacharyvoase/').is_leaf

    def test_with_query_replaces_query(self):
        assert (self.url.with_query('spam-ham-eggs') ==
                'https://github.com/zacharyvoase/urlobject?spam-ham-eggs#foo')

    def test_without_query_removes_query(self):
        assert (self.url.without_query() ==
                'https://github.com/zacharyvoase/urlobject#foo')

    def test_add_query_param_adds_one_query_parameter(self):
        assert (self.url.add_query_param('spam', 'ham') ==
                'https://github.com/zacharyvoase/urlobject?spam=eggs&spam=ham#foo')

    def test_add_query_params_adds_multiple_query_parameters(self):
        assert (self.url.add_query_params([('spam', 'ham'), ('foo', 'bar')]) ==
                'https://github.com/zacharyvoase/urlobject?spam=eggs&spam=ham&foo=bar#foo')

    def test_add_query_params_with_multiple_values_adds_the_same_query_parameter_multiple_times(self):
        assert (self.url.add_query_params({'foo': ['bar', 'baz']}) ==
                'https://github.com/zacharyvoase/urlobject?spam=eggs&foo=bar&foo=baz#foo')

    def test_set_query_param_adds_or_replaces_one_query_parameter(self):
        assert (self.url.set_query_param('spam', 'ham') ==
                'https://github.com/zacharyvoase/urlobject?spam=ham#foo')

    def test_set_query_params_adds_or_replaces_multiple_query_parameters(self):
        assert (self.url.set_query_params({'foo': 'bar'}, spam='ham') ==
                'https://github.com/zacharyvoase/urlobject?foo=bar&spam=ham#foo')

    def test_set_query_params_with_multiple_values_adds_or_replaces_the_same_parameter_multiple_times(self):
        assert (self.url.set_query_params({'spam': ['bar', 'baz']}) ==
                'https://github.com/zacharyvoase/urlobject?spam=bar&spam=baz#foo')
        assert (self.url.set_query_params({'foo': ['bar', 'baz']}) ==
                'https://github.com/zacharyvoase/urlobject?spam=eggs&foo=bar&foo=baz#foo')
        # Ensure it removes all appearances of an existing name before adding
        # the new ones.
        url = URLObject('https://github.com/zacharyvoase/urlobject?foo=bar&foo=baz#foo')
        assert (url.set_query_params({'foo': ['spam', 'ham']}) ==
                'https://github.com/zacharyvoase/urlobject?foo=spam&foo=ham#foo')

    def test_del_query_param_removes_one_query_parameter(self):
        assert (self.url.del_query_param('spam') ==
                'https://github.com/zacharyvoase/urlobject#foo')

    def test_del_query_params_removes_multiple_query_parameters(self):
        url = URLObject('https://github.com/zacharyvoase/urlobject?foo=bar&baz=spam#foo')
        assert (url.del_query_params(['foo', 'baz']) ==
                'https://github.com/zacharyvoase/urlobject#foo')

    def test_with_fragment_replaces_fragment(self):
        assert (self.url.with_fragment('part') ==
                'https://github.com/zacharyvoase/urlobject?spam=eggs#part')

    def test_with_fragment_encodes_fragment_correctly(self):
        assert (self.url.with_fragment('foo bar#baz') ==
                'https://github.com/zacharyvoase/urlobject?spam=eggs#foo%20bar%23baz')

    def test_without_fragment_removes_fragment(self):
        assert (self.url.without_fragment() ==
                'https://github.com/zacharyvoase/urlobject?spam=eggs')
Пример #2
0
class SpurlURLBuilder(object):
    def __init__(self, args, context, tags, filters):
        self.args = args
        self.context = context
        self.tags = tags
        self.filters = filters
        self.autoescape = self.context.autoescape
        self.url = URLObject()

    def build(self):
        for argument, value in self.args:
            self.handle_argument(argument, value)

        self.set_sensible_defaults()

        url = six.text_type(self.url)

        if self.autoescape:
            url = escape(url)

        return url

    def handle_argument(self, argument, value):
        argument = smart_str(argument, 'ascii')
        handler_name = 'handle_%s' % argument
        handler = getattr(self, handler_name, None)

        if handler is not None:
            value = value.resolve(self.context)
            handler(value)

    def handle_base(self, value):
        base = self.prepare_value(value)
        self.url = URLObject(base)

    def handle_auth(self, value):
        auth = self.prepare_value(value)
        self.url = self.url.with_auth(*auth.split(':', 1))

    def handle_secure(self, value):
        is_secure = convert_to_boolean(value)
        scheme = 'https' if is_secure else 'http'
        self.url = self.url.with_scheme(scheme)

    def handle_query(self, value):
        query = self.prepare_value(value)
        if isinstance(query, dict):
            query = QueryString().set_params(**query)
        self.url = self.url.with_query(QueryString(query))

    def handle_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_query(url.query)

    def handle_add_query(self, value):
        query_to_add = self.prepare_value(value)
        if isinstance(query_to_add, six.string_types):
            query_to_add = QueryString(query_to_add).dict
        self.url = self.url.add_query_params(**query_to_add)

    def handle_add_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.add_query_params(**url.query.dict)

    def handle_set_query(self, value):
        query_to_set = self.prepare_value(value)
        if isinstance(query_to_set, six.string_types):
            query_to_set = QueryString(query_to_set).dict
        self.url = self.url.set_query_params(**query_to_set)

    def handle_set_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.set_query_params(**url.query.dict)

    def handle_remove_query_param(self, value):
        query_to_remove = self.prepare_value(value)
        self.url = self.url.del_query_param(query_to_remove)

    def handle_toggle_query(self, value):
        query_to_toggle = self.prepare_value(value)
        if isinstance(query_to_toggle, six.string_types):
            query_to_toggle = QueryString(query_to_toggle).dict
        current_query = self.url.query.dict
        for key, value in list(query_to_toggle.items()):
            if isinstance(value, six.string_types):
                value = value.split(',')
            first, second = value
            if key in current_query and first in current_query[key]:
                self.url = self.url.set_query_param(key, second)
            else:
                self.url = self.url.set_query_param(key, first)

    def handle_scheme(self, value):
        self.url = self.url.with_scheme(value)

    def handle_scheme_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_scheme(url.scheme)

    def handle_host(self, value):
        host = self.prepare_value(value)
        self.url = self.url.with_hostname(host)

    def handle_host_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_hostname(url.hostname)

    def handle_path(self, value):
        path = self.prepare_value(value)
        self.url = self.url.with_path(path)

    def handle_path_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_path(url.path)

    def handle_add_path(self, value):
        path_to_add = self.prepare_value(value)
        self.url = self.url.add_path(path_to_add)

    def handle_add_path_from(self, value):
        url = URLObject(value)
        path_to_add = url.path
        if path_to_add.startswith('/'):
            path_to_add = path_to_add[1:]
        self.url = self.url.add_path(path_to_add)

    def handle_fragment(self, value):
        fragment = self.prepare_value(value)
        self.url = self.url.with_fragment(fragment)

    def handle_fragment_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_fragment(url.fragment)

    def handle_port(self, value):
        self.url = self.url.with_port(int(value))

    def handle_port_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_port(url.port)

    def handle_autoescape(self, value):
        self.autoescape = convert_to_boolean(value)

    def set_sensible_defaults(self):
        if self.url.hostname and not self.url.scheme:
            self.url = self.url.with_scheme('http')

    def prepare_value(self, value):
        """Prepare a value by unescaping embedded template tags
        and rendering through Django's template system"""
        if isinstance(value, six.string_types):
            value = self.render_template(self.unescape_tags(value))
        return value

    def unescape_tags(self, template_string):
        """Spurl allows the use of templatetags inside templatetags, if
        the inner templatetags are escaped - {\% and %\}"""
        return template_string.replace('{\%', '{%').replace('%\}', '%}')

    def compile_string(self, template_string, origin, template_debug=False):
        """Re-implementation of django.template.base.compile_string
        that takes into account the tags and filter of the parser
        that rendered the parent template"""
        if template_debug is True:
            if django.VERSION < (1, 9):
                from django.template.debug import DebugLexer, DebugParser
                lexer_class, parser_class = DebugLexer, DebugParser
            else:
                from django.template.base import DebugLexer
                lexer_class, parser_class = DebugLexer, Parser
        else:
            lexer_class, parser_class = Lexer, Parser
        if django.VERSION < (1, 9):
            lexer = lexer_class(template_string, origin)
        else:
            lexer = lexer_class(template_string)
        parser = parser_class(lexer.tokenize())

        # Attach the tags and filters from the parent parser
        parser.tags = self.tags
        parser.filters = self.filters

        return parser.parse()

    def render_template(self, template_string):
        """Used to render an "inner" template, ie one which
        is passed as an argument to spurl"""
        original_autoescape = self.context.autoescape
        self.context.autoescape = False

        template = Template('')
        template_debug = getattr(
            settings, 'TEMPLATE_DEBUG',
            template.engine.debug if hasattr(template, 'engine') else False)
        if template_debug is True:
            origin = StringOrigin(template_string)
        else:
            origin = None

        template.nodelist = self.compile_string(template_string, origin,
                                                template_debug)

        rendered = template.render(self.context)
        self.context.autoescape = original_autoescape
        return rendered
Пример #3
0
class SpurlURLBuilder(object):

    def __init__(self, args, context, tags, filters):
        self.args = args
        self.context = context
        self.tags = tags
        self.filters = filters
        self.autoescape = self.context.autoescape
        self.url = URLObject()

    def build(self):
        for argument, value in self.args:
            self.handle_argument(argument, value)

        self.set_sensible_defaults()

        url = six.text_type(self.url)

        if self.autoescape:
            url = escape(url)

        return url

    def handle_argument(self, argument, value):
        argument = smart_str(argument, 'ascii')
        handler_name = 'handle_%s' % argument
        handler = getattr(self, handler_name, None)

        if handler is not None:
            value = value.resolve(self.context)
            handler(value)

    def handle_base(self, value):
        base = self.prepare_value(value)
        self.url = URLObject(base)

    def handle_auth(self, value):
        auth = self.prepare_value(value)
        self.url = self.url.with_auth(*auth.split(':', 1))

    def handle_secure(self, value):
        is_secure = convert_to_boolean(value)
        scheme = 'https' if is_secure else 'http'
        self.url = self.url.with_scheme(scheme)

    def handle_query(self, value):
        query = self.prepare_value(value)
        if isinstance(query, dict):
            query = QueryString().set_params(**query)
        self.url = self.url.with_query(QueryString(query))

    def handle_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_query(url.query)

    def handle_add_query(self, value):
        query_to_add = self.prepare_value(value)
        if isinstance(query_to_add, six.string_types):
            query_to_add = QueryString(query_to_add).dict
        self.url = self.url.add_query_params(**query_to_add)

    def handle_add_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.add_query_params(**url.query.dict)

    def handle_set_query(self, value):
        query_to_set = self.prepare_value(value)
        if isinstance(query_to_set, six.string_types):
            query_to_set = QueryString(query_to_set).dict
        self.url = self.url.set_query_params(**query_to_set)

    def handle_set_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.set_query_params(**url.query.dict)

    def handle_remove_query_param(self, value):
        query_to_remove = self.prepare_value(value)
        self.url = self.url.del_query_param(query_to_remove)

    def handle_toggle_query(self, value):
        query_to_toggle = self.prepare_value(value)
        if isinstance(query_to_toggle, six.string_types):
            query_to_toggle = QueryString(query_to_toggle).dict
        current_query = self.url.query.dict
        for key, value in list(query_to_toggle.items()):
            if isinstance(value, six.string_types):
                value = value.split(',')
            first, second = value
            if key in current_query and first in current_query[key]:
                self.url = self.url.set_query_param(key, second)
            else:
                self.url = self.url.set_query_param(key, first)

    def handle_scheme(self, value):
        self.url = self.url.with_scheme(value)

    def handle_scheme_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_scheme(url.scheme)

    def handle_host(self, value):
        host = self.prepare_value(value)
        self.url = self.url.with_hostname(host)

    def handle_host_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_hostname(url.hostname)

    def handle_path(self, value):
        path = self.prepare_value(value)
        self.url = self.url.with_path(path)

    def handle_path_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_path(url.path)

    def handle_add_path(self, value):
        path_to_add = self.prepare_value(value)
        self.url = self.url.add_path(path_to_add)

    def handle_add_path_from(self, value):
        url = URLObject(value)
        path_to_add = url.path
        if path_to_add.startswith('/'):
            path_to_add = path_to_add[1:]
        self.url = self.url.add_path(path_to_add)

    def handle_fragment(self, value):
        fragment = self.prepare_value(value)
        self.url = self.url.with_fragment(fragment)

    def handle_fragment_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_fragment(url.fragment)

    def handle_port(self, value):
        self.url = self.url.with_port(int(value))

    def handle_port_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_port(url.port)

    def handle_autoescape(self, value):
        self.autoescape = convert_to_boolean(value)

    def set_sensible_defaults(self):
        if self.url.hostname and not self.url.scheme:
            self.url = self.url.with_scheme('http')

    def prepare_value(self, value):
        """Prepare a value by unescaping embedded template tags
        and rendering through Django's template system"""
        if isinstance(value, six.string_types):
            value = self.render_template(self.unescape_tags(value))
        return value

    def unescape_tags(self, template_string):
        """Spurl allows the use of templatetags inside templatetags, if
        the inner templatetags are escaped - {\% and %\}"""
        return template_string.replace('{\%', '{%').replace('%\}', '%}')

    def compile_string(self, template_string, origin):
        """Re-implementation of django.template.base.compile_string
        that takes into account the tags and filter of the parser
        that rendered the parent template"""
        if settings.TEMPLATE_DEBUG:
            from django.template.debug import DebugLexer, DebugParser
            lexer_class, parser_class = DebugLexer, DebugParser
        else:
            lexer_class, parser_class = Lexer, Parser
        lexer = lexer_class(template_string, origin)
        parser = parser_class(lexer.tokenize())

        # Attach the tags and filters from the parent parser
        parser.tags = self.tags
        parser.filters = self.filters

        return parser.parse()

    def render_template(self, template_string):
        """Used to render an "inner" template, ie one which
        is passed as an argument to spurl"""
        original_autoescape = self.context.autoescape
        self.context.autoescape = False

        template = Template('')
        if settings.TEMPLATE_DEBUG:
            origin = StringOrigin(template_string)
        else:
            origin = None

        template.nodelist = self.compile_string(template_string, origin)

        rendered = template.render(self.context)
        self.context.autoescape = original_autoescape
        return rendered
Пример #4
0
class URLObjectModificationTest(unittest.TestCase):

    def setUp(self):
        self.url = URLObject(u'https://github.com/zacharyvoase/urlobject?spam=eggs#foo')

    def test_with_scheme_replaces_scheme(self):
        assert (self.url.with_scheme('http') ==
                u'http://github.com/zacharyvoase/urlobject?spam=eggs#foo')

    def test_with_netloc_replaces_netloc(self):
        assert (self.url.with_netloc('example.com') ==
                u'https://example.com/zacharyvoase/urlobject?spam=eggs#foo')

    def test_with_hostname_replaces_hostname(self):
        url = URLObject(u'https://*****:*****@github.com/')
        assert (url.with_hostname('example.com') ==
                u'https://*****:*****@example.com/')

    def test_with_username_adds_username(self):
        url = URLObject(u'https://github.com/')
        assert url.with_username('zack') == u'https://[email protected]/'

    def test_with_username_replaces_username(self):
        url = URLObject(u'https://[email protected]/')
        assert url.with_username('alice') == u'https://[email protected]/'

    def test_without_username_removes_username(self):
        url = URLObject(u'https://[email protected]/')
        assert url.without_username() == u'https://github.com/'

    def test_with_password_adds_password(self):
        url = URLObject(u'https://[email protected]/')
        assert url.with_password('1234') == u'https://*****:*****@github.com/'

    def test_with_password_raises_ValueError_when_there_is_no_username(self):
        url = URLObject(u'https://github.com/')
        assert_raises(ValueError, lambda: url.with_password('1234'))

    def test_with_password_replaces_password(self):
        url = URLObject(u'https://*****:*****@github.com/')
        assert url.with_password('5678') == u'https://*****:*****@github.com/'

    def test_without_password_removes_password(self):
        url = URLObject(u'https://*****:*****@github.com/')
        assert url.without_password() == u'https://[email protected]/'

    def test_with_auth_with_one_arg_adds_username(self):
        url = URLObject(u'https://github.com/')
        assert url.with_auth('zack') == u'https://[email protected]/'

    def test_with_auth_with_one_arg_replaces_whole_auth_string_with_username(self):
        url = URLObject(u'https://*****:*****@github.com/')
        assert url.with_auth('zack') == u'https://[email protected]/'

    def test_with_auth_with_two_args_adds_username_and_password(self):
        url = URLObject(u'https://github.com/')
        assert url.with_auth('zack', '1234') == u'https://*****:*****@github.com/'

    def test_with_auth_with_two_args_replaces_whole_auth_string_with_username_and_password(self):
        # Replaces username-only auth string
        url = URLObject(u'https://[email protected]/')
        assert url.with_auth('zack', '1234') == u'https://*****:*****@github.com/'

        # Replaces username and password.
        url = URLObject(u'https://*****:*****@github.com/')
        assert url.with_auth('zack', '1234') == u'https://*****:*****@github.com/'

    def test_without_auth_removes_entire_auth_string(self):
        # No username or password => no-op.
        url = URLObject(u'https://github.com/')
        assert url.without_auth() == u'https://github.com/'
        # Username-only.
        url = URLObject(u'https://[email protected]/')
        assert url.without_auth() == u'https://github.com/'
        # Username and password.
        url = URLObject(u'https://*****:*****@github.com/')
        assert url.without_auth() == u'https://github.com/'

    def test_with_port_adds_port_number(self):
        assert (self.url.with_port(24) ==
                u'https://github.com:24/zacharyvoase/urlobject?spam=eggs#foo')

    def test_with_port_replaces_port_number(self):
        url = URLObject(u'https://github.com:59/')
        assert url.with_port(67) == u'https://github.com:67/'

    def test_without_port_removes_port_number(self):
        url = URLObject(u'https://github.com:59/')
        assert url.without_port() == u'https://github.com/'

    def test_with_path_replaces_path(self):
        assert (self.url.with_path('/dvxhouse/intessa') ==
                u'https://github.com/dvxhouse/intessa?spam=eggs#foo')

    def test_root_goes_to_root_path(self):
        assert self.url.root == u'https://github.com/?spam=eggs#foo'

    def test_parent_jumps_up_one_level(self):
        url = URLObject(u'https://github.com/zacharyvoase/urlobject')
        assert url.parent == u'https://github.com/zacharyvoase/'
        assert url.parent.parent == u'https://github.com/'

    def test_add_path_segment_adds_a_path_segment(self):
        url = URLObject(u'https://github.com/zacharyvoase/urlobject')
        assert (url.add_path_segment('tree') ==
                u'https://github.com/zacharyvoase/urlobject/tree')
        assert (url.add_path_segment('tree/master') ==
                u'https://github.com/zacharyvoase/urlobject/tree%2Fmaster')

    def test_add_path_adds_a_partial_path(self):
        url = URLObject(u'https://github.com/zacharyvoase/urlobject')
        assert (url.add_path('tree') ==
                u'https://github.com/zacharyvoase/urlobject/tree')
        assert (url.add_path('tree/master') ==
                u'https://github.com/zacharyvoase/urlobject/tree/master')

    def test_is_leaf(self):
        assert URLObject(u'https://github.com/zacharyvoase/urlobject').is_leaf
        assert not URLObject(u'https://github.com/zacharyvoase/').is_leaf

    def test_with_query_replaces_query(self):
        assert (self.url.with_query('spam-ham-eggs') ==
                u'https://github.com/zacharyvoase/urlobject?spam-ham-eggs#foo')

    def test_without_query_removes_query(self):
        assert (self.url.without_query() ==
                u'https://github.com/zacharyvoase/urlobject#foo')

    def test_add_query_param_adds_one_query_parameter(self):
        assert (self.url.add_query_param(u'spam', u'ham') ==
                u'https://github.com/zacharyvoase/urlobject?spam=eggs&spam=ham#foo')

    def test_add_query_params_adds_multiple_query_parameters(self):
        assert (self.url.add_query_params([(u'spam', u'ham'), (u'foo', u'bar')]) ==
                u'https://github.com/zacharyvoase/urlobject?spam=eggs&spam=ham&foo=bar#foo')

    def test_add_query_params_with_multiple_values_adds_the_same_query_parameter_multiple_times(self):
        assert (self.url.add_query_params({u'foo': [u'bar', 'baz']}) ==
                u'https://github.com/zacharyvoase/urlobject?spam=eggs&foo=bar&foo=baz#foo')

    def test_set_query_param_adds_or_replaces_one_query_parameter(self):
        assert (self.url.set_query_param(u'spam', u'ham') ==
                u'https://github.com/zacharyvoase/urlobject?spam=ham#foo')

    def test_set_query_params_adds_or_replaces_multiple_query_parameters(self):
        assert (self.url.set_query_params({u'foo': u'bar'}, spam=u'ham') ==
                u'https://github.com/zacharyvoase/urlobject?foo=bar&spam=ham#foo')

    def test_set_query_params_with_multiple_values_adds_or_replaces_the_same_parameter_multiple_times(self):
        assert (self.url.set_query_params({u'spam': [u'bar', 'baz']}) ==
                u'https://github.com/zacharyvoase/urlobject?spam=bar&spam=baz#foo')
        assert (self.url.set_query_params({u'foo': [u'bar', 'baz']}) ==
                u'https://github.com/zacharyvoase/urlobject?spam=eggs&foo=bar&foo=baz#foo')
        # Ensure it removes all appearances of an existing name before adding
        # the new ones.
        url = URLObject(u'https://github.com/zacharyvoase/urlobject?foo=bar&foo=baz#foo')
        assert (url.set_query_params({u'foo': [u'spam', u'ham']}) ==
                u'https://github.com/zacharyvoase/urlobject?foo=spam&foo=ham#foo')

    def test_del_query_param_removes_one_query_parameter(self):
        assert (self.url.del_query_param(u'spam') ==
                u'https://github.com/zacharyvoase/urlobject#foo')

    def test_del_query_params_removes_multiple_query_parameters(self):
        url = URLObject(u'https://github.com/zacharyvoase/urlobject?foo=bar&baz=spam#foo')
        assert (url.del_query_params(['foo', 'baz']) ==
                u'https://github.com/zacharyvoase/urlobject#foo')

    def test_with_fragment_replaces_fragment(self):
        assert (self.url.with_fragment('part') ==
                u'https://github.com/zacharyvoase/urlobject?spam=eggs#part')

    def test_with_fragment_encodes_fragment_correctly(self):
        assert (self.url.with_fragment('foo bar#baz') ==
                u'https://github.com/zacharyvoase/urlobject?spam=eggs#foo%20bar%23baz')

    def test_without_fragment_removes_fragment(self):
        assert (self.url.without_fragment() ==
                u'https://github.com/zacharyvoase/urlobject?spam=eggs')
Пример #5
0
class SpurlURLBuilder(object):
    def __init__(self, args, context, tags, filters):
        self.args = args
        self.context = context
        self.tags = tags
        self.filters = filters
        self.autoescape = self.context.autoescape
        self.url = URLObject()

    def build(self):
        for argument, value in self.args:
            self.handle_argument(argument, value)

        try:
            self.set_sensible_defaults()

            url = unicode(self.url)

            if self.autoescape:
                url = escape(url)
                url = url.replace('%20', '+')
                url = url.replace('%2C', ',')
                url = url.replace('&amp;', '&')

        except Exception as e:
            url = self.url

        return url

    def handle_argument(self, argument, value):
        argument = smart_str(argument, 'ascii')
        handler_name = 'handle_%s' % argument
        handler = getattr(self, handler_name, None)

        if handler is not None:
            value = value.resolve(self.context)
            handler(value)

    def handle_base(self, value):
        base = self.prepare_value(value)
        self.url = URLObject(base)

    def handle_secure(self, value):
        is_secure = convert_to_boolean(value)
        scheme = 'https' if is_secure else 'http'
        self.url = self.url.with_scheme(scheme)

    def handle_query(self, value):
        query = self.prepare_value(value)
        if isinstance(query, dict):
            query = QueryString().set_params(**query)
        self.url = self.url.with_query(QueryString(query))

    def handle_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_query(url.query)

    def handle_add_query(self, value):
        query_to_add = self.prepare_value(value)
        if isinstance(query_to_add, basestring):
            query_to_add = QueryString(query_to_add).dict
        self.url = self.url.add_query_params(**query_to_add)

    def handle_add_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.add_query_params(**url.query.dict)

    def handle_set_query(self, value):
        query_to_set = self.prepare_value(value)
        if isinstance(query_to_set, basestring):
            query_to_set = QueryString(query_to_set).dict
        self.url = self.url.set_query_params(**query_to_set)

    def handle_active_query(self, value):
        query_to_toggle = self.prepare_value(value)
        if isinstance(query_to_toggle, basestring):
            query_to_toggle = QueryString(query_to_toggle).dict
        current_query = self.url.query.dict
        for key, value in query_to_toggle.items():

            if key in current_query and value in current_query[key]:
                self.url = True
            else:
                self.url = False

    def handle_set_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.set_query_params(**url.query.dict)

    def handle_remove_query_param(self, value):
        self.url = self.url.del_query_param(value)

    def handle_toggle_query(self, value):
        query_to_toggle = self.prepare_value(value)
        if isinstance(query_to_toggle, basestring):
            query_to_toggle = QueryString(query_to_toggle).dict
        current_query = self.url.query.dict
        for key, value in query_to_toggle.items():
            if isinstance(value, basestring):
                value = value.split(',')
            first, second = value
            if key in current_query and first in current_query[key]:
                self.url = self.url.set_query_param(key, second)
            else:
                self.url = self.url.set_query_param(key, first)

    def handle_trigger_query(self, value):
        query_to_trigger = self.prepare_value(value)
        if isinstance(query_to_trigger, basestring):
            query_to_trigger = QueryString(query_to_trigger).dict
        current_query = self.url.query.dict
        for key, value in query_to_trigger.items():

            if isinstance(value, basestring):
                value = value

            if key in current_query and value in current_query[key]:
                # unset
                self.url = self.url.del_query_param(key)
            else:
                # set
                self.url = self.url.set_query_param(key, value)

    def handle_trigger_mquery(self, value):

        query_to_trigger = self.prepare_value(value)
        if isinstance(query_to_trigger, basestring):
            query_to_trigger = QueryString(query_to_trigger).dict
        current_query = self.url.query.dict

        for key, value in query_to_trigger.items():

            # exact match of query -> unset it
            if key in current_query and query_to_trigger[key] == current_query[
                    key]:

                self.url = self.url.del_query_param(key)
                return

            # check if current query has multiple items
            try:
                ext = current_query[key]
                ext = ext.split(',')
            except Exception as e:
                ext = None

            if ext and len(ext) > 1:

                if key in current_query and value in ext:

                    # we have a key-match, so remove it from the string
                    ext = [x for x in ext if x != value]

                else:

                    # no key match, so add it to the string
                    ext.append(value)

                ext.sort()

                self.url = self.url.set_query_param(key, ",".join(ext))

            elif ext and len(ext) == 1:

                # param already here > append
                ext.append(value)
                ext.sort()

                ext = list(set(ext))

                self.url = self.url.set_query_param(key, ",".join(ext))

            else:

                if isinstance(value, basestring):
                    value = value

                if key in current_query and value in current_query[key]:
                    # unset
                    pass
                    #self.url = self.url.del_query_param(key)
                else:
                    # set
                    self.url = self.url.set_query_param(key, value)

    def handle_active_mquery(self, value):

        active = None

        query_to_trigger = self.prepare_value(value)
        if isinstance(query_to_trigger, basestring):
            query_to_trigger = QueryString(query_to_trigger).dict
        current_query = self.url.query.dict

        for key, value in query_to_trigger.items():

            # exact match of query -> unset it
            if key in current_query and query_to_trigger[key] == current_query[
                    key]:
                active = True

            # check if current query has multiple items
            try:
                ext = current_query[key]
                ext = ext.split(',')
            except Exception as e:
                ext = None

            if ext and len(ext) > 1:

                if key in current_query and value in ext:
                    active = True

        self.url = active

    def handle_scheme(self, value):
        self.url = self.url.with_scheme(value)

    def handle_scheme_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_scheme(url.scheme)

    def handle_host(self, value):
        host = self.prepare_value(value)
        self.url = self.url.with_hostname(host)

    def handle_host_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_hostname(url.hostname)

    def handle_path(self, value):
        path = self.prepare_value(value)
        self.url = self.url.with_path(path)

    def handle_path_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_path(url.path)

    def handle_add_path(self, value):
        path_to_add = self.prepare_value(value)
        self.url = self.url.add_path(path_to_add)

    def handle_add_path_from(self, value):
        url = URLObject(value)
        path_to_add = url.path
        if path_to_add.startswith('/'):
            path_to_add = path_to_add[1:]
        self.url = self.url.add_path(path_to_add)

    def handle_fragment(self, value):
        fragment = self.prepare_value(value)
        self.url = self.url.with_fragment(fragment)

    def handle_fragment_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_fragment(url.fragment)

    def handle_port(self, value):
        self.url = self.url.with_port(int(value))

    def handle_port_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_port(url.port)

    def handle_autoescape(self, value):
        self.autoescape = convert_to_boolean(value)

    def set_sensible_defaults(self):
        if self.url.hostname and not self.url.scheme:
            self.url = self.url.with_scheme('http')

    def prepare_value(self, value):
        """Prepare a value by unescaping embedded template tags
        and rendering through Django's template system"""
        if isinstance(value, basestring):
            value = self.unescape_tags(value)
            value = self.render_template(value)
        return value

    def unescape_tags(self, template_string):
        """Spurl allows the use of templatetags inside templatetags, if
        the inner templatetags are escaped - {\% and %\}"""
        return template_string.replace('{\%', '{%').replace('%\}', '%}')

    def compile_string(self, template_string, origin):
        """Re-implementation of django.template.base.compile_string
        that takes into account the tags and filter of the parser
        that rendered the parent template"""

        if TEMPLATE_DEBUG:
            from django.template.debug import DebugLexer, DebugParser
            lexer_class, parser_class = DebugLexer, DebugParser
        else:
            lexer_class, parser_class = Lexer, Parser

        # TODO: investigate. in django 1.9 `Lexer` only takes one argument
        try:
            lexer = lexer_class(template_string, origin)
        except TypeError:
            lexer = lexer_class(template_string)

        parser = parser_class(lexer.tokenize())

        # Attach the tags and filters from the parent parser
        parser.tags = self.tags
        parser.filters = self.filters

        return parser.parse()

    def render_template(self, template_string):
        """Used to render an "inner" template, ie one which
        is passed as an argument to spurl"""
        original_autoescape = self.context.autoescape
        self.context.autoescape = False

        template = Template('')
        if TEMPLATE_DEBUG:
            origin = StringOrigin(template_string)
        else:
            origin = None

        template.nodelist = self.compile_string(template_string, origin)

        rendered = template.render(self.context)
        self.context.autoescape = original_autoescape
        return rendered
Пример #6
0
class SpurlURLBuilder(object):

    def __init__(self, args, context, tags, filters):
        self.args = args
        self.context = context
        self.tags = tags
        self.filters = filters
        self.autoescape = self.context.autoescape
        self.url = URLObject()

    def build(self):
        for argument, value in self.args:
            self.handle_argument(argument, value)

        try:
            self.set_sensible_defaults()

            url = unicode(self.url)

            if self.autoescape:
                url = escape(url)
                url = url.replace('%20', '+')
                url = url.replace('%2C', ',')
                url = url.replace('&amp;', '&')


        except Exception as e:
            url = self.url


        return url

    def handle_argument(self, argument, value):
        argument = smart_str(argument, 'ascii')
        handler_name = 'handle_%s' % argument
        handler = getattr(self, handler_name, None)

        if handler is not None:
            value = value.resolve(self.context)
            handler(value)

    def handle_base(self, value):
        base = self.prepare_value(value)
        self.url = URLObject(base)

    def handle_secure(self, value):
        is_secure = convert_to_boolean(value)
        scheme = 'https' if is_secure else 'http'
        self.url = self.url.with_scheme(scheme)

    def handle_query(self, value):
        query = self.prepare_value(value)
        if isinstance(query, dict):
            query = QueryString().set_params(**query)
        self.url = self.url.with_query(QueryString(query))

    def handle_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_query(url.query)

    def handle_add_query(self, value):
        query_to_add = self.prepare_value(value)
        if isinstance(query_to_add, basestring):
            query_to_add = QueryString(query_to_add).dict
        self.url = self.url.add_query_params(**query_to_add)

    def handle_add_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.add_query_params(**url.query.dict)

    def handle_set_query(self, value):
        query_to_set = self.prepare_value(value)
        if isinstance(query_to_set, basestring):
            query_to_set = QueryString(query_to_set).dict
        self.url = self.url.set_query_params(**query_to_set)




    def handle_active_query(self, value):
        query_to_toggle = self.prepare_value(value)
        if isinstance(query_to_toggle, basestring):
            query_to_toggle = QueryString(query_to_toggle).dict
        current_query = self.url.query.dict
        for key, value in query_to_toggle.items():

            if key in current_query and value in current_query[key]:
                self.url = True
            else:
                self.url = False




    def handle_set_query_from(self, value):
        url = URLObject(value)
        self.url = self.url.set_query_params(**url.query.dict)

    def handle_remove_query_param(self, value):
        self.url = self.url.del_query_param(value)

    def handle_toggle_query(self, value):
        query_to_toggle = self.prepare_value(value)
        if isinstance(query_to_toggle, basestring):
            query_to_toggle = QueryString(query_to_toggle).dict
        current_query = self.url.query.dict
        for key, value in query_to_toggle.items():
            if isinstance(value, basestring):
                value = value.split(',')
            first, second = value
            if key in current_query and first in current_query[key]:
                self.url = self.url.set_query_param(key, second)
            else:
                self.url = self.url.set_query_param(key, first)

    def handle_trigger_query(self, value):
        query_to_trigger = self.prepare_value(value)
        if isinstance(query_to_trigger, basestring):
            query_to_trigger = QueryString(query_to_trigger).dict
        current_query = self.url.query.dict
        for key, value in query_to_trigger.items():

            if isinstance(value, basestring):
                value = value

            if key in current_query and value in current_query[key]:
                # unset
                self.url = self.url.del_query_param(key)
            else:
                # set
                self.url = self.url.set_query_param(key, value)

    def handle_trigger_mquery(self, value):

        query_to_trigger = self.prepare_value(value)
        if isinstance(query_to_trigger, basestring):
            query_to_trigger = QueryString(query_to_trigger).dict
        current_query = self.url.query.dict

        for key, value in query_to_trigger.items():

            # exact match of query -> unset it
            if key in current_query and query_to_trigger[key] == current_query[key]:

                self.url = self.url.del_query_param(key)
                return

            # check if current query has multiple items
            try:
                ext = current_query[key]
                ext = ext.split(',')
            except Exception as e:
                ext = None

            if ext and len(ext) > 1:

                if key in current_query and value in ext:

                    # we have a key-match, so remove it from the string
                    ext = [x for x in ext if x != value]

                else:

                    # no key match, so add it to the string
                    ext.append(value)

                ext.sort()

                self.url = self.url.set_query_param(key, ",".join(ext))


            elif ext and len(ext) == 1:

                # param already here > append
                ext.append(value)
                ext.sort()

                ext = list(set(ext))

                self.url = self.url.set_query_param(key, ",".join(ext))


            else:

                if isinstance(value, basestring):
                    value = value

                if key in current_query and value in current_query[key]:
                    # unset
                    pass
                    #self.url = self.url.del_query_param(key)
                else:
                    # set
                    self.url = self.url.set_query_param(key, value)

    def handle_active_mquery(self, value):



        active = None

        query_to_trigger = self.prepare_value(value)
        if isinstance(query_to_trigger, basestring):
            query_to_trigger = QueryString(query_to_trigger).dict
        current_query = self.url.query.dict

        for key, value in query_to_trigger.items():

            # exact match of query -> unset it
            if key in current_query and query_to_trigger[key] == current_query[key]:
                active = True

            # check if current query has multiple items
            try:
                ext = current_query[key]
                ext = ext.split(',')
            except Exception as e:
                ext = None

            if ext and len(ext) > 1:

                if key in current_query and value in ext:
                    active = True

        self.url = active



    def handle_scheme(self, value):
        self.url = self.url.with_scheme(value)

    def handle_scheme_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_scheme(url.scheme)

    def handle_host(self, value):
        host = self.prepare_value(value)
        self.url = self.url.with_hostname(host)

    def handle_host_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_hostname(url.hostname)

    def handle_path(self, value):
        path = self.prepare_value(value)
        self.url = self.url.with_path(path)

    def handle_path_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_path(url.path)

    def handle_add_path(self, value):
        path_to_add = self.prepare_value(value)
        self.url = self.url.add_path(path_to_add)

    def handle_add_path_from(self, value):
        url = URLObject(value)
        path_to_add = url.path
        if path_to_add.startswith('/'):
            path_to_add = path_to_add[1:]
        self.url = self.url.add_path(path_to_add)

    def handle_fragment(self, value):
        fragment = self.prepare_value(value)
        self.url = self.url.with_fragment(fragment)

    def handle_fragment_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_fragment(url.fragment)

    def handle_port(self, value):
        self.url = self.url.with_port(int(value))

    def handle_port_from(self, value):
        url = URLObject(value)
        self.url = self.url.with_port(url.port)

    def handle_autoescape(self, value):
        self.autoescape = convert_to_boolean(value)

    def set_sensible_defaults(self):
        if self.url.hostname and not self.url.scheme:
            self.url = self.url.with_scheme('http')

    def prepare_value(self, value):
        """Prepare a value by unescaping embedded template tags
        and rendering through Django's template system"""
        if isinstance(value, basestring):
            value = self.unescape_tags(value)
            value = self.render_template(value)
        return value

    def unescape_tags(self, template_string):
        """Spurl allows the use of templatetags inside templatetags, if
        the inner templatetags are escaped - {\% and %\}"""
        return template_string.replace('{\%', '{%').replace('%\}', '%}')

    def compile_string(self, template_string, origin):
        """Re-implementation of django.template.base.compile_string
        that takes into account the tags and filter of the parser
        that rendered the parent template"""

        if settings.TEMPLATE_DEBUG:
            from django.template.debug import DebugLexer, DebugParser
            lexer_class, parser_class = DebugLexer, DebugParser
        else:
            lexer_class, parser_class = Lexer, Parser

        # TODO: investigate. in django 1.9 `Lexer` only takes one argument
        try:
            lexer = lexer_class(template_string, origin)
        except TypeError:
            lexer = lexer_class(template_string)

        parser = parser_class(lexer.tokenize())

        # Attach the tags and filters from the parent parser
        parser.tags = self.tags
        parser.filters = self.filters

        return parser.parse()

    def render_template(self, template_string):
        """Used to render an "inner" template, ie one which
        is passed as an argument to spurl"""
        original_autoescape = self.context.autoescape
        self.context.autoescape = False

        template = Template('')
        if settings.TEMPLATE_DEBUG:
            origin = StringOrigin(template_string)
        else:
            origin = None

        template.nodelist = self.compile_string(template_string, origin)

        rendered = template.render(self.context)
        self.context.autoescape = original_autoescape
        return rendered