Template.get_identifiers / is_valid
Two read-only checks added in 3.11. get_identifiers lists $name and ${name} placeholders (duplicates once) and skips invalid ones; is_valid is False exactly when substitute() would raise ValueError.
Demo
from string import Template t = Template('Dear $title $last, re: ${subject}') (t.get_identifiers(), t.is_valid())
Names come back in the order they first appear, each once, braced or not. $$ is an escaped dollar, not a placeholder, so it neither adds a name nor makes the template invalid. An invalid placeholder ($5, ${ x }) is skipped by get_identifiers and makes is_valid() False — the same templates on which substitute() raises ValueError.
Common patterns
from string import Template ALLOWED = {'name', 'plan', 'date'} t = Template(text) if not t.is_valid(): raise ValueError('use $$ for a literal dollar sign') unknown = set(t.get_identifiers()) - ALLOWED if unknown: raise ValueError(f'unknown placeholders: {sorted(unknown)}')
from string import Template t = Template(text) values = {name: providers[name]() for name in t.get_identifiers()} t.substitute(values)
Examples
Pitfalls
from string import Template t = Template('$name') t.substitute() if t.is_valid() else None
from string import Template t = Template('$name') values = {} t.is_valid() and set(t.get_identifiers()) <= set(values)
from string import Template Template('${first name} ${last}').get_identifiers()
from string import Template class Spaced(Template): braceidpattern = r'(?a:[_a-z][_a-z0-9 ]*)' Spaced('${first name} ${last}').get_identifiers()
When to use
- Validating templates entered in an admin UI or config
- Finding which values a template needs before computing them
- Format strings in {field} syntax → Formatter.parse
Notes
FAQ
Template(text).get_identifiers() on Python 3.11+ returns the placeholder names in the order they first appear, without duplicates. On older versions, iterate t.pattern.finditer(t.template) and read the 'named' and 'braced' groups.