def do_round(value, precision=0, method='common'): """Round the number to a given precision. The first parameter specifies the precision (default is ``0``), the second the rounding method: - ``'common'`` rounds either up or down - ``'ceil'`` always rounds up - ``'floor'`` always rounds down If you don't specify a method ``'common'`` is used. .. sourcecode:: jinja {{ 42.55|round }} -> 43 {{ 42.55|round(1, 'floor') }} -> 42.5 """ if not method in ('common', 'ceil', 'floor'): raise FilterArgumentError('method must be common, ceil or floor') if precision < 0: raise FilterArgumentError('precision must be a postive integer ' 'or zero.') if method == 'common': return round(value, precision) func = getattr(math, method) if precision: return func(value * 10 * precision) / (10 * precision) else: return func(value)
def map_dict(*args, **kwargs): """ Apply a filter on a dictionary. The equivalent of the map() filter, but for dictionaries. """ context = args[0] seq = args[1] if len(args) == 2 and 'attribute' in kwargs: attribute = kwargs.pop('attribute') if kwargs: raise FilterArgumentError('Unexpected keyword argument %r' % next(iter(kwargs))) func = make_attrgetter(context.environment, attribute) else: try: name = args[2] args = args[3:] except LookupError: raise FilterArgumentError('map requires a filter argument') func = lambda item: context.environment.call_filter( name, item, args, kwargs, context=context) if seq and isinstance(seq, dict): values = list(seq.values()) keys = list(seq.keys()) for i in range(len(keys)): seq[keys[i]] = func(values[i]) return seq
def do_round(value, precision=0, method='common'): if method not in ('common', 'ceil', 'floor'): raise FilterArgumentError('method must be common, ceil or floor') if method == 'common': return round(value, precision) func = getattr(math, method) return func(value * 10**precision) / 10**precision
def _select_or_reject(args, kwargs, modfunc, lookup_attr): context = args[0] seq = args[1] if lookup_attr: try: attr = args[2] except LookupError: raise FilterArgumentError('Missing parameter for attribute name') transfunc = make_attrgetter(context.environment, attr) off = 1 else: off = 0 transfunc = lambda x: x try: name = args[2 + off] args = args[3 + off:] func = lambda item: context.environment.call_test( name, item, args, kwargs) except LookupError: func = bool if seq: for item in seq: if modfunc(func(transfunc(item))): yield item
def do_round(value, precision=0, method='common'): """Round the number to a given precision. The first parameter specifies the precision (default is ``0``), the second the rounding method: - ``'common'`` rounds either up or down - ``'ceil'`` always rounds up - ``'floor'`` always rounds down If you don't specify a method ``'common'`` is used. .. sourcecode:: jinja {{ 42.55|round }} -> 43.0 {{ 42.55|round(1, 'floor') }} -> 42.5 Note that even if rounded to 0 precision, a float is returned. If you need a real integer, pipe it through `int`: .. sourcecode:: jinja {{ 42.55|round|int }} -> 43 """ if not method in ('common', 'ceil', 'floor'): raise FilterArgumentError('method must be common, ceil or floor') if method == 'common': return round(value, precision) func = getattr(math, method) return func(value * (10 ** precision)) / (10 ** precision)
def do_dictsort(value, case_sensitive=False, by='key'): """Sort a dict and yield (key, value) pairs. Because python dicts are unsorted you may want to use this function to order them by either key or value: .. sourcecode:: jinja {% for item in mydict|dictsort %} sort the dict by key, case insensitive {% for item in mydict|dictsort(true) %} sort the dict by key, case sensitive {% for item in mydict|dictsort(false, 'value') %} sort the dict by value, case insensitive """ if by == 'key': pos = 0 elif by == 'value': pos = 1 else: raise FilterArgumentError('You can only sort by either ' '"key" or "value"') def sort_func(item): value = item[pos] if isinstance(value, string_types) and not case_sensitive: value = value.lower() return value return sorted(value.items(), key=sort_func)
def do_dictsort(value, case_sensitive=False, by="key", reverse=False): """Sort a dict and yield (key, value) pairs. Because python dicts are unsorted you may want to use this function to order them by either key or value: .. sourcecode:: jinja {% for item in mydict|dictsort %} sort the dict by key, case insensitive {% for item in mydict|dictsort(reverse=true) %} sort the dict by key, case insensitive, reverse order {% for item in mydict|dictsort(true) %} sort the dict by key, case sensitive {% for item in mydict|dictsort(false, 'value') %} sort the dict by value, case insensitive """ if by == "key": pos = 0 elif by == "value": pos = 1 else: raise FilterArgumentError('You can only sort by either "key" or "value"') def sort_func(item): value = item[pos] if not case_sensitive: value = ignore_case(value) return value return sorted(value.items(), key=sort_func, reverse=reverse)
def sort_dict(value, case_sensitive=False, by='key', reverse=False, index=0): """ 字典排序 :param value: 字典对象 :param case_sensitive: 是否大小写敏感 :param by: 排序对象 :param reverse: 排序方式(正序:True、倒序:False) :param index: 索引号(此处针对 value 为 list 情况下可根据 list 的某一 index 排序) :return: """ if by == 'key': pos = 0 elif by == 'value': pos = 1 else: raise FilterArgumentError( 'You can only sort by either "key" or "value"') def sort_func(item): value = item[pos] if index: try: value = value[index] except: pass if isinstance(value, string_types) and not case_sensitive: value = value.lower() return value return sorted(value.items(), key=sort_func, reverse=reverse)
def do_map(*args, **kwargs): """Applies a filter on a sequence of objects or looks up an attribute. This is useful when dealing with lists of objects but you are really only interested in a certain value of it. The basic usage is mapping on an attribute. Imagine you have a list of users but you are only interested in a list of usernames: .. sourcecode:: jinja Users on this page: {{ users|map(attribute='username')|join(', ') }} Alternatively you can let it invoke a filter by passing the name of the filter and the arguments afterwards. A good example would be applying a text conversion filter on a sequence: .. sourcecode:: jinja Users on this page: {{ titles|map('lower')|join(', ') }} .. versionadded:: 2.7 """ context = args[0] seq = args[1] if len(args) == 2 and 'attribute' in kwargs: attribute = kwargs.pop('attribute') if kwargs: raise FilterArgumentError('Unexpected keyword argument %r' % next(iter(kwargs))) func = make_attrgetter(context.environment, attribute) else: try: name = args[2] args = args[3:] except LookupError: raise FilterArgumentError('map requires a filter argument') func = lambda item: context.environment.call_filter( name, item, args, kwargs, context=context) if seq: for item in seq: yield func(item)
def do_sorted(env, iterable, *, attribute=None, item=None, reverse=False): if attribute is None and item is None: key = None elif attribute is not None and item is not None: raise FilterArgumentError("Only one of attribute and item may be" "specified") elif attribute is not None: key = partial(env.getattr, attribute=attribute) elif item is not None: key = partial(env.getitem, argument=item) return sorted(iterable, key=key, reverse=reverse)
def prepare_map(args, kwargs): context = args[0] seq = args[1] if len(args) == 2 and 'attribute' in kwargs: attribute = kwargs.pop('attribute') if kwargs: raise FilterArgumentError('Unexpected keyword argument %r' % next(iter(kwargs))) func = make_attrgetter(context.environment, attribute) else: try: name = args[2] args = args[3:] except LookupError: raise FilterArgumentError('map requires a filter argument') func = lambda item: context.environment.call_filter( name, item, args, kwargs, context=context) return seq, func
def do_reverse(value): if isinstance(value, basestring): return value[::-1] try: return reversed(value) except TypeError: try: rv = list(value) rv.reverse() return rv except TypeError: raise FilterArgumentError('argument must be iterable')
def do_format(value, *args, **kwargs): """ Apply python string formatting on an object: .. sourcecode:: jinja {{ "%s - %s"|format("Hello?", "Foo!") }} -> Hello? - Foo! """ if args and kwargs: raise FilterArgumentError('can\'t handle positional and keyword ' 'arguments at the same time') return soft_unicode(value) % (kwargs or args)
def do_reverse(value): """Reverse the object or return an iterator that iterates over it the other way round. """ if isinstance(value, string_types): return value[::-1] try: return reversed(value) except TypeError: try: rv = list(value) rv.reverse() return rv except TypeError: raise FilterArgumentError('argument must be iterable')
def do_dictsort(value, case_sensitive=False, by='key'): if by == 'key': pos = 0 elif by == 'value': pos = 1 else: raise FilterArgumentError( 'You can only sort by either "key" or "value"') def sort_func(item): value = item[pos] if isinstance(value, basestring) and not case_sensitive: value = value.lower() return value return sorted(value.items(), key=sort_func)
def do_format(value, *args, **kwargs): """Apply the given values to a `printf-style`_ format string, like ``string % values``. .. sourcecode:: jinja {{ "%s, %s!"|format(greeting, name) }} Hello, World! In most cases it should be more convenient and efficient to use the ``%`` operator or :meth:`str.format`. .. code-block:: text {{ "%s, %s!" % (greeting, name) }} {{ "{}, {}!".format(greeting, name) }} .. _printf-style: https://docs.python.org/library/stdtypes.html #printf-style-string-formatting """ if args and kwargs: raise FilterArgumentError('can\'t handle positional and keyword ' 'arguments at the same time') return soft_unicode(value) % (kwargs or args)
def do_format(value, *args, **kwargs): if args and kwargs: raise FilterArgumentError( "can't handle positional and keyword arguments at the same time") return soft_unicode(value) % (kwargs or args)