spaceapi-server/spaceapi_server/template/__init__.py

56 lines
1.6 KiB
Python
Raw Normal View History

2019-11-25 02:48:12 +01:00
import json
import jinja2
# The Jinja2 environment
2019-11-25 04:35:50 +01:00
__ENV = None
2019-11-25 02:48:12 +01:00
2019-11-25 04:35:50 +01:00
def _env_init(force: bool = False):
2019-11-25 03:14:14 +01:00
"""
2019-11-25 02:48:12 +01:00
Initialize the Jinja2 environment.
2019-11-25 04:10:20 +01:00
:param force: If true, force reload the environment.
2019-11-25 03:14:14 +01:00
"""
2019-11-25 04:35:50 +01:00
global __ENV
if __ENV is None or force:
2019-11-25 02:48:12 +01:00
# Use json.dumps as finalizer in order to preserve complex data structures
2019-11-25 04:35:50 +01:00
__ENV = jinja2.Environment(finalize=json.dumps)
return __ENV
2019-11-25 02:48:12 +01:00
def render(template: str):
2019-11-25 03:14:14 +01:00
"""
2019-11-25 02:48:12 +01:00
Render the given string as a Jinja2 template.
2019-11-25 04:10:20 +01:00
:param template: The template string to render.
2019-11-25 03:14:14 +01:00
"""
2019-11-25 04:35:50 +01:00
# Make sure the Jinja2 environment is initialized
env = _env_init()
2019-11-25 02:48:12 +01:00
# Create a Jinja2 template from the input string
t = env.from_string(template)
decoder = json.JSONDecoder()
2019-11-25 02:48:12 +01:00
# Render the template and turn the JSON dump back into complex data structures
# Only parse the first JSON object in the string, ignore the rest
obj, i = decoder.raw_decode(t.render())
return obj
2019-11-25 04:35:50 +01:00
def render_traverse(obj):
"""
Walk through a complex, JSON-serializable data structure, and pass
string objects through the Jinja2 templating engine.
:param obj: The object to traverse.
"""
if isinstance(obj, list):
# list -> recurse into each item
return [render_traverse(x) for x in obj]
2019-11-25 04:35:50 +01:00
elif isinstance(obj, dict):
# dict -> recurse into the value of each (key, value)
return {k: render_traverse(v) for k, v in obj.items()}
2019-11-25 04:35:50 +01:00
elif isinstance(obj, str):
# str -> template
return render(obj)
else:
# anything else -> return as-is
return obj