You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							146 lines
						
					
					
						
							4.0 KiB
						
					
					
				
			
		
		
	
	
							146 lines
						
					
					
						
							4.0 KiB
						
					
					
				| from functools import wraps
 | |
| 
 | |
| from jinja2.asyncsupport import auto_aiter
 | |
| from jinja2 import filters
 | |
| 
 | |
| 
 | |
| async def auto_to_seq(value):
 | |
|     seq = []
 | |
|     if hasattr(value, '__aiter__'):
 | |
|         async for item in value:
 | |
|             seq.append(item)
 | |
|     else:
 | |
|         for item in value:
 | |
|             seq.append(item)
 | |
|     return seq
 | |
| 
 | |
| 
 | |
| async def async_select_or_reject(args, kwargs, modfunc, lookup_attr):
 | |
|     seq, func = filters.prepare_select_or_reject(
 | |
|         args, kwargs, modfunc, lookup_attr)
 | |
|     if seq:
 | |
|         async for item in auto_aiter(seq):
 | |
|             if func(item):
 | |
|                 yield item
 | |
| 
 | |
| 
 | |
| def dualfilter(normal_filter, async_filter):
 | |
|     wrap_evalctx = False
 | |
|     if getattr(normal_filter, 'environmentfilter', False):
 | |
|         is_async = lambda args: args[0].is_async
 | |
|         wrap_evalctx = False
 | |
|     else:
 | |
|         if not getattr(normal_filter, 'evalcontextfilter', False) and \
 | |
|            not getattr(normal_filter, 'contextfilter', False):
 | |
|             wrap_evalctx = True
 | |
|         is_async = lambda args: args[0].environment.is_async
 | |
| 
 | |
|     @wraps(normal_filter)
 | |
|     def wrapper(*args, **kwargs):
 | |
|         b = is_async(args)
 | |
|         if wrap_evalctx:
 | |
|             args = args[1:]
 | |
|         if b:
 | |
|             return async_filter(*args, **kwargs)
 | |
|         return normal_filter(*args, **kwargs)
 | |
| 
 | |
|     if wrap_evalctx:
 | |
|         wrapper.evalcontextfilter = True
 | |
| 
 | |
|     wrapper.asyncfiltervariant = True
 | |
| 
 | |
|     return wrapper
 | |
| 
 | |
| 
 | |
| def asyncfiltervariant(original):
 | |
|     def decorator(f):
 | |
|         return dualfilter(original, f)
 | |
|     return decorator
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_first)
 | |
| async def do_first(environment, seq):
 | |
|     try:
 | |
|         return await auto_aiter(seq).__anext__()
 | |
|     except StopAsyncIteration:
 | |
|         return environment.undefined('No first item, sequence was empty.')
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_groupby)
 | |
| async def do_groupby(environment, value, attribute):
 | |
|     expr = filters.make_attrgetter(environment, attribute)
 | |
|     return [filters._GroupTuple(key, await auto_to_seq(values))
 | |
|             for key, values in filters.groupby(sorted(
 | |
|                 await auto_to_seq(value), key=expr), expr)]
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_join)
 | |
| async def do_join(eval_ctx, value, d=u'', attribute=None):
 | |
|     return filters.do_join(eval_ctx, await auto_to_seq(value), d, attribute)
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_list)
 | |
| async def do_list(value):
 | |
|     return await auto_to_seq(value)
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_reject)
 | |
| async def do_reject(*args, **kwargs):
 | |
|     return async_select_or_reject(args, kwargs, lambda x: not x, False)
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_rejectattr)
 | |
| async def do_rejectattr(*args, **kwargs):
 | |
|     return async_select_or_reject(args, kwargs, lambda x: not x, True)
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_select)
 | |
| async def do_select(*args, **kwargs):
 | |
|     return async_select_or_reject(args, kwargs, lambda x: x, False)
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_selectattr)
 | |
| async def do_selectattr(*args, **kwargs):
 | |
|     return async_select_or_reject(args, kwargs, lambda x: x, True)
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_map)
 | |
| async def do_map(*args, **kwargs):
 | |
|     seq, func = filters.prepare_map(args, kwargs)
 | |
|     if seq:
 | |
|         async for item in auto_aiter(seq):
 | |
|             yield func(item)
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_sum)
 | |
| async def do_sum(environment, iterable, attribute=None, start=0):
 | |
|     rv = start
 | |
|     if attribute is not None:
 | |
|         func = filters.make_attrgetter(environment, attribute)
 | |
|     else:
 | |
|         func = lambda x: x
 | |
|     async for item in auto_aiter(iterable):
 | |
|         rv += func(item)
 | |
|     return rv
 | |
| 
 | |
| 
 | |
| @asyncfiltervariant(filters.do_slice)
 | |
| async def do_slice(value, slices, fill_with=None):
 | |
|     return filters.do_slice(await auto_to_seq(value), slices, fill_with)
 | |
| 
 | |
| 
 | |
| ASYNC_FILTERS = {
 | |
|     'first':        do_first,
 | |
|     'groupby':      do_groupby,
 | |
|     'join':         do_join,
 | |
|     'list':         do_list,
 | |
|     # we intentionally do not support do_last because that would be
 | |
|     # ridiculous
 | |
|     'reject':       do_reject,
 | |
|     'rejectattr':   do_rejectattr,
 | |
|     'map':          do_map,
 | |
|     'select':       do_select,
 | |
|     'selectattr':   do_selectattr,
 | |
|     'sum':          do_sum,
 | |
|     'slice':        do_slice,
 | |
| }
 | |
| 
 |