URL utils¶
Contents
This module contains some utility modules for handling URL building, and the aspect of handling several parts of the URL, each separated by different separators, that may be provided or not (thus, handling separators becomes a bit more complicated).
Decorators¶
- This module defines the pass_tuple() decorator, that makes a function :
- run witout the first part of its original arguments
- return the omitted arguments and its original return value
This allows to use chain of functions in Parsable that work only on a slice of the arguments (for example, to run some operations while passing a boolean flag).
- django_crucrudile.urlutils.pass_tuple(count=1)[source]¶
Returns a decorator that wraps a function to make it run witout the first part of a tuple in its original arguments and return the omitted arguments contatenated with its original return value.
Parameters: count (int) – Number of arguments to omit, default 1. Returns: Decorator Return type: function Warning
This function is not the actual decorator, but a function that returns that decorator (with the given tuple slice index). If it is used as a decorator, it should be written @pass_tuple() instead of @pass_tuple.
>>> pack_with_42 = lambda x: (42, x) >>> pack_with_42(8) (42, 8) >>> add_2 = pass_tuple()(lambda x: x + 2) >>> add_2(pack_with_42(8)) (42, 10) >>> mul_2 = pass_tuple()(lambda x: x*2) >>> mul_2(add_2(pack_with_42(8))) (42, 20) >>> unpack = lambda x: x[0] + x[1] >>> unpack(mul_2(add_2(pack_with_42(8)))) 62
Functions¶
This module defines the compose() function, that compose a list of functions into a single function that returns its arguments, passed in chain to each of the functions. This function is used by Parsable to compose the parsers returned by Parsable.get_parsers(), in Parsable.__call__().
- django_crucrudile.urlutils.compose(functions, *args, **kwargs)[source]¶
Compose functions together
Parameters: functions (list of callables) – Functions to compose Returns: Composed function Return type: function Note
This function will pass all other arguments and keyword arguments to the composed functions.
>>> compose([lambda x: x*2, lambda x: x+2])(5) 12
Classes¶
- Separated allows separator-related options to be passed to Separated.__init__() and provides Separated.get_separator()
- Parsable provides a class which instances can be called (Parsable.__call__()), to return the “parsed” version of the instance. The parsed version is made by passing the instance through the functions returned by Parsable.get_parsers()
- OptionalPartList provides a class that implements Separated and Parsable with a list, and that provides two parsers (that, if needed : transform the original items in tuples ; set the “required” flag to the default value)
- URLBuilder subclasses OptionalPartList and provides parsers , on top of the original ones, to join the URL parts with adequate separators where required
Generic¶
Note
These classes provide bases for the URLBuilder and django_crucrudile.routes.mixins.arguments.parser.ArgumentsParser classes.
- class django_crucrudile.urlutils.Separated(*args, separator=None, opt_separator=None, required_default=None, **kwargs)[source]¶
Bases: builtins.object
Accepts separator options in __init__(), and provide get_separator(), that returns the corresponding separator for required and optional parts, based on the separator passed to __init__() (or set at class-level).
- __init__(*args, separator=None, opt_separator=None, required_default=None, **kwargs)[source]¶
Initialize, set separator options
Parameters: - separator – See separator
- opt_separator – See opt_separator
- required_default – See required_default
- separator = '/'¶
Attribute separator: Separator to use in front of a required item
- opt_separator = '/?'¶
Attribute opt_separator: Separator to use in front of an optional item
- required_default = True¶
Attribute required_default: If True, items required by default (when None)
- get_separator(required=None)[source]¶
Get the argument separator to use according to the required argument
Parameters: required (bool) – If False, will return the optional argument separator instead of the regular one. Default is True. Returns: Separator Return type: str >>> Separated().get_separator() '/' >>> Separated().get_separator(True) '/' >>> Separated().get_separator(False) '/?'
- class django_crucrudile.urlutils.Parsable[source]¶
Bases: builtins.object
Class whose instances may be called, to return a “parsed” version, obtained by passing the original version in the parsers returned by get_parsers().
>>> class TestParsable(Parsable, int): ... def get_parsers(self): ... return [lambda x: x*2, lambda x: x+2] >>> >>> TestParsable(5)() 12
>>> class TestParsable(Parsable, int): ... def get_parsers(self): ... return [] >>> >>> TestParsable(5)() 5
>>> class TestParsable(Parsable, int): ... def get_parsers(self): ... return [lambda x: None] >>> >>> TestParsable(5)()
>>> class TestParsable(Parsable, int): ... def get_parsers(self): ... return [None] >>> >>> TestParsable(5)() Traceback (most recent call last): ... TypeError: the first argument must be callable
>>> class TestParsable(Parsable, int): ... def get_parsers(self): ... return [lambda x, y: None] >>> >>> TestParsable(5)() Traceback (most recent call last): ... TypeError: <lambda>() missing 1 required positional argument: 'y'
>>> class TestParsable(Parsable, int): ... def get_parsers(self): ... return [lambda: None] >>> >>> TestParsable(5)() Traceback (most recent call last): ... TypeError: <lambda>() takes 0 positional arguments but 1 was given
- get_parsers()[source]¶
Return parsers list. Base implementation returns an empty list. To add new parsers, override this function and append/prepend the functions to use as parsers.
Returns: List of parser functions Return type: list
- __call__()[source]¶
Compose the parsers in get_parsers() using compose(), and use the composed function to get the parsed version from the original version.
Returns: output of parsers See also
For doctests that use this member, see Parsable
URL parts classes¶
Optional URL parts list¶
- class django_crucrudile.urlutils.OptionalPartList(iterable=None, separator=None, opt_separator=None, required_default=None)[source]¶
Bases: django_crucrudile.urlutils.Separated, django_crucrudile.urlutils.Parsable, builtins.list
Implement Separated and Parsable into a list, to make a separated, parsable URL part list, that handles optional parts and that uses registered parsers (from get_parsers()) when the instance is called.
Provide two base parsers, that convert, if needed, original items in 2-tuples (transform_to_tuple()), and provide a default value for the first item of the tuple if it’s None (apply_required_default()).
>>> builder = OptionalPartList( ... ["<1>", (None, "<2>"), (False, "<3>")] ... ) >>> >>> list(builder()) [(True, '<1>'), (True, '<2>'), (False, '<3>')]
>>> failing_builder = OptionalPartList( ... ["<1>", (None, "<2>"), (False, "<3>", "fail")] ... ) >>> >>> list(failing_builder()) Traceback (most recent call last): ... ValueError: too many values to unpack (expected 2)
- __add__(other)[source]¶
Concatenate with other iterable, creating a new object..
We override list.__add__() to return a new OptionalPartList instance, instead of a list instance.
Parameters: other (iterable) – Iterable to concatenate with Returns: Concatenated object Return type: type(self) >>> a = OptionalPartList(['foo']) >>> b = OptionalPartList(['bar']) >>> >>> a + b ['foo', 'bar'] >>> >>> type(a + b) <class 'django_crucrudile.urlutils.OptionalPartList'> >>> >>> (a + b) is a False >>> >>> (a + b) is b False
>>> (a + None) is a True
- __init__(iterable=None, separator=None, opt_separator=None, required_default=None)[source]¶
Initialize, use empty list as iterable if None provided.
Parameters: - iterable (iterable) – Raw URL part list
- separator (str) – See Separated.__init__()
- opt_separator (str) – See Separated.__init__()
- required_default (bool) – See Separated.__init__()
- get_parsers()[source]¶
Complement OptionalPartList parsers (from OptionalPartList.get_parsers()) with transform_to_tuple() and apply_required_default().
Returns: List of parser functions Return type: list
- static transform_to_tuple(items)[source]¶
Transform each item to a tuple if it’s not one
Parameters: items (iterable) – List of items and tuples Returns: List of tuples Return type: iterable of tuple >>> list(OptionalPartList.transform_to_tuple([ ... '<1>', ... (None, '<2>') ... ])) [(None, '<1>'), (None, '<2>')]
- static apply_required_default(items, default)[source]¶
Apply default value to first element of item if it’s None.
Parameters: - items (iterable) – List of tuples
- default (boolean) – Value to use if none provided
Returns: List of tuples, with required default value applied
Return type: iterable of tuple
>>> list( ... OptionalPartList.apply_required_default( ... [ ... ('<provided>', '<1>'), ... (None, '<2>') ... ], ... default='<default>' ... ) ... ) [('<provided>', '<1>'), ('<default>', '<2>')]
URL Builder¶
- class django_crucrudile.urlutils.URLBuilder(iterable=None, separator=None, opt_separator=None, required_default=None)[source]¶
Bases: django_crucrudile.urlutils.OptionalPartList
Allows building URLs from a list of URL parts. The parts can be required or optional, this information will be used to determine which separator to use.
We subclass OptionalPartList, and add our parsers in get_parsers(), so that they are used when the instance gets called :
>>> builder = URLBuilder( ... ["<1>", (False, "<2>"), (True, "<3>")] ... ) >>> >>> builder() (True, '<1>/?<2>/<3>')
>>> builder = URLBuilder( ... ["<1>", "<2>", (False, "<3>")] ... ) >>> >>> builder() (True, '<1>/<2>/?<3>')
>>> builder = URLBuilder( ... [(False, "<1>"), "<2>", (False, "<3>")] ... ) >>> >>> builder() (False, '<1>/<2>/?<3>')
>>> builder = URLBuilder( ... [(False, "<1>"), None, (True, None)] ... ) >>> >>> builder() (False, '<1>')
>>> builder = URLBuilder( ... [(False, "<1>"), 1] ... ) >>> >>> builder() Traceback (most recent call last): ... TypeError: sequence item 2: expected str instance, int found
- get_parsers()[source]¶
Complement OptionalPartList parsers (from OptionalPartList.get_parsers()) with filter_empty_items(), add_first_item_required_flag(), flatten() and join().
Returns: List of parser functions Return type: list
- static filter_empty_items(items)[source]¶
Filter out items that give False when casted to boolean.
Parameters: items (iterable) – List of tuples Returns: List of URL part specs (with empty items cleared out) Return type: list of tuple >>> list(URLBuilder.filter_empty_items([ ... (None, ''), ... (None, '<not empty>'), ... (None, []), ... (None, None), ... (None, '<not empty 2>'), ... ])) [(None, '<not empty>'), (None, '<not empty 2>')]
>>> list(URLBuilder.filter_empty_items([ ... (None, '<not empty>'), ... None ... ])) Traceback (most recent call last): ... TypeError: 'NoneType' object is not iterable
- static add_first_item_required_flag(items)[source]¶
Return a boolean indicating whether the first item is required, and the list of items.
Parameters: items (iterable) – List of tuples Returns: Tuple with “first item required” flag, and item list Return type: tuple : (boolean, list) >>> output = URLBuilder.add_first_item_required_flag( ... [(False, '<opt>'), (True, '<req>')] ... ) >>> >>> output[0], list(output[1]) (False, [(False, '<opt>'), (True, '<req>')])
>>> output = URLBuilder.add_first_item_required_flag( ... [] ... ) >>> >>> output[0], list(output[1]) (False, [])
>>> output = URLBuilder.add_first_item_required_flag( ... [(None, )*3] ... ) Traceback (most recent call last): ... ValueError: too many values to unpack (expected 2)
- static flatten(items, get_separator)[source]¶
Flatten items, adding the separator where required.
Parameters: items (iterable) – List of tuples Returns: List of URL parts with separators Return type: iterable of str Warning
This function is decorated using pass_tuple(), the first part of the tuple in its arguments will be omitted, and inserted at the beginning of the return value, automatically. See the documentation of pass_tuple() for more information.
>>> get_separator = lambda x: '/'
>>> output = URLBuilder.flatten( ... (None, [(True, '<1>'), (True, '<2>')]), ... get_separator ... ) >>> >>> output[0], list(output[1]) (None, ['<1>', '/', '<2>'])
>>> from mock import Mock >>> >>> get_separator = Mock() >>> get_separator.side_effect = ['/']
>>> output = URLBuilder.flatten( ... (None, [(True, '<1>'), (True, '<2>')]), ... get_separator ... ) >>> >>> output[0], list(output[1]) (None, ['<1>', '/', '<2>']) >>> get_separator.assert_called_once_with(True)
- static join(items)[source]¶
Concatenate items into a string
Parameters: items (list of str) – List of URL parts, with separators Returns: Joined URL parts Return type: str Warning
This function is decorated using pass_tuple(), the first part of the tuple in its arguments will be passed automatically. See the documentation of pass_tuple() for more information.
>>> URLBuilder.join((None, ['a', 'b'])) (None, 'ab')
>>> URLBuilder.join((None, [['a'], 'b'])) Traceback (most recent call last): ... TypeError: sequence item 0: expected str instance, list found
>>> URLBuilder.join((None, ['a', None])) Traceback (most recent call last): ... TypeError: sequence item 1: expected str instance, NoneType found