Using Template References¶
When the same pattern is used repetitively in several templates, it can be useful to extract it out into a separate template that can be referenced.
To reference another template, use its name prefixed by the at symbol, @, in a placeholder:
>>> shot_path = lucidity.Template('shot_path', '{@job_path}/shots/{shot.code}')
Template references are resolved on demand when performing operations with the
template, such as calling Template.parse()
or Template.format()
.
This is why the above didn’t produce an error even though no job_path template
has been defined (or a way to lookup that template by name even). This
behaviour allows discovery of templates
without worrying about the order of template construction.
As soon as you attempt to perform an operation on the template that does require
resolving references, errors will be raised accordingly. For example, try
calling the Template.keys()
method:
>>> print shot_path.keys()
ResolveError: Failed to resolve reference 'job_path' as no template resolver set.
The error indicates that we have not provided the template with a way to
actually resolve template references. To do this we need to set the
template_resolver attribute on the template to an object that matches the
Resolver
interface. Fortunately, the resolver interface is simple so
a even a basic dictionary can act as a resolver:
>>> resolver = {}
>>> shot_path.template_resolver = resolver
Note
The template resolver can also be passed as an argument when instantiating a
new Template
.
Try getting the keys again:
>>> print shot_path.keys()
ResolveError: Failed to resolve reference 'job_path' using template resolver.
Slightly better. Now we have a resolver in place we just need to add the other template to the resolver so that it can be looked up by name:
>>> job_path = lucidity.Template('job_path', '/jobs/{job.code}')
>>> resolver[job_path.name] = job_path
Note
In a future release a dedicated template collection class will make dealing with template references even easier.
Print the keys again and it should resolve all the references and give back the full list of keys that make up the expanded template:
>>> print shot_path.keys()
set(['job.code', 'shot.code'])
There is also a method for listing the references found in a template:
>>> print shot_path.references()
set(['job_path'])
Additionally, if you would like to see the fully expanded pattern you can
manually call the Template.expanded_pattern()
method at any time:
>>> print shot_path.expanded_pattern()
/jobs/{job.code}/shots/{shot.code}
Anchor behaviour¶
A Template
has an anchor setting that
determines how the template pattern is matched when parsing. When a template is
referenced in another template its anchor setting is ignored and only the anchor
setting of the outermost template is used:
>>> template_a = lucidity.Template(
... 'a', 'path/{variable}', anchor=lucidity.Template.ANCHOR_START
... )
>>> print template_a.parse('/some/path/value')
ParseError: Path '/some/path/value' did not match template pattern.
>>> resolver = {}
>>> resolver[template_a.name] = template_a
>>> template_b = lucidity.Template(
... 'b', '{@a}', anchor=lucidity.Template.ANCHOR_END,
... template_resolver=resolver
... )
>>> print template_b.parse('/some/path/value')
{'variable': 'value'}