def process_request(self, request): token = request.GET.get(self.param_name) if not token: return redirect_url = URLObject(request.get_full_path()) redirect_url = redirect_url.del_query_param(self.param_name) response = redirect(unicode(redirect_url)) try: token_data = tempus_loads(token, max_age=self.max_age) tempus = getattr(request, 'tempus', None) if tempus: current_tempus = tempus.copy() current_tempus.update(token_data) request.tempus = current_tempus else: request.tempus = token_data except SignatureExpired: value = self.__process_func(request, 'expired_func') if value: return value except BadSignature: value = self.__process_func(request, 'unsuccess_func') if value: return value else: value = self.__process_func(request, 'success_func') if value: return value add_never_cache_headers(response) return response
def remove_tag(context, tagname): # Current url url = URLObject(context.request.get_full_path()) # Dictionary of tags in current url tagdict = url.query.multi_dict tagvalues = tagdict.get("tag", []) # Remove the value of to be removed tagname tagvalues.remove(tagname) # Make clean url url = url.del_query_param("tag") # Add only the remaining tags to the new url for stay_tag in tagvalues: url = url.add_query_param("tag", stay_tag) return url
def modify_url_(url, operation, *args): """ Враппер для функций модуля urlobject https://urlobject.readthedocs.org/en/latest/quickstart.html Назначение: разобрать текщий URL, поменять какую-то его часть и вернуть модифицированный URL в виде строки Например: modify_url(some_url, 'del_query_param', 'page') уберет пейджинг из запроса Возвращает URL без домена """ if not operation: return url url = URLObject(url) if operation.endswith('_np'): url = url.del_query_param('page') operation = operation[0:-3] op = getattr(url, operation, None) if callable(op): return text_type(op(*args)) raise Exception('%s is incorrect function name for urlobject.URLObject' % operation)
def process_request(self, request): token = request.GET.get(self.param_name) if not token: return redirect_url = URLObject(request.get_full_path()) redirect_url = redirect_url.del_query_param(self.param_name) response = redirect(unicode(redirect_url)) try: token_data = tempus_loads(token, max_age=self.max_age) except SignatureExpired: expired_func = getattr(self, 'expired_func') if expired_func: expired_func(request, token_data) except BadSignature: return response else: self.success_func(request, token_data) add_never_cache_headers(response) return response
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')
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
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
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')
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('&', '&') 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
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('&', '&') 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