"""Jinja2 extensions."""
import json
import string
import uuid
from secrets import choice
import arrow
from jinja2 import nodes
from jinja2.ext import Extension
from slugify import slugify as pyslugify
[docs]
class JsonifyExtension(Extension):
"""Jinja2 extension to convert a Python object to JSON."""
def __init__(self, environment):
"""Initialize the extension with the given environment."""
super().__init__(environment)
def jsonify(obj):
return json.dumps(obj, sort_keys=True, indent=4)
environment.filters['jsonify'] = jsonify
[docs]
class RandomStringExtension(Extension):
"""Jinja2 extension to create a random string."""
def __init__(self, environment):
"""Jinja2 Extension Constructor."""
super().__init__(environment)
def random_ascii_string(length, punctuation=False):
if punctuation:
corpus = "".join((string.ascii_letters, string.punctuation))
else:
corpus = string.ascii_letters
return "".join(choice(corpus) for _ in range(length))
environment.globals.update(random_ascii_string=random_ascii_string)
[docs]
class SlugifyExtension(Extension):
"""Jinja2 Extension to slugify string."""
def __init__(self, environment):
"""Jinja2 Extension constructor."""
super().__init__(environment)
def slugify(value, **kwargs):
"""Slugifies the value."""
return pyslugify(value, **kwargs)
environment.filters['slugify'] = slugify
[docs]
class UUIDExtension(Extension):
"""Jinja2 Extension to generate uuid4 string."""
def __init__(self, environment):
"""Jinja2 Extension constructor."""
super().__init__(environment)
def uuid4():
"""Generate UUID4."""
return str(uuid.uuid4())
environment.globals.update(uuid4=uuid4)
[docs]
class TimeExtension(Extension):
"""Jinja2 Extension for dates and times."""
tags = {'now'}
def __init__(self, environment):
"""Jinja2 Extension constructor."""
super().__init__(environment)
environment.extend(datetime_format='%Y-%m-%d')
def _datetime(self, timezone, operator, offset, datetime_format):
d = arrow.now(timezone)
# parse shift params from offset and include operator
shift_params = {}
for param in offset.split(','):
interval, value = param.split('=')
shift_params[interval.strip()] = float(operator + value.strip())
d = d.shift(**shift_params)
if datetime_format is None:
datetime_format = self.environment.datetime_format
return d.strftime(datetime_format)
def _now(self, timezone, datetime_format):
if datetime_format is None:
datetime_format = self.environment.datetime_format
return arrow.now(timezone).strftime(datetime_format)
[docs]
def parse(self, parser):
"""Parse datetime template and add datetime value."""
lineno = next(parser.stream).lineno
node = parser.parse_expression()
if parser.stream.skip_if('comma'):
datetime_format = parser.parse_expression()
else:
datetime_format = nodes.Const(None)
if isinstance(node, nodes.Add):
call_method = self.call_method(
'_datetime',
[node.left, nodes.Const('+'), node.right, datetime_format],
lineno=lineno,
)
elif isinstance(node, nodes.Sub):
call_method = self.call_method(
'_datetime',
[node.left, nodes.Const('-'), node.right, datetime_format],
lineno=lineno,
)
else:
call_method = self.call_method(
'_now',
[node, datetime_format],
lineno=lineno,
)
return nodes.Output([call_method], lineno=lineno)