How can I extract keywords from a Python format string?
python, string, string-formatting
Solution
You can use the `string.Formatter()` class to parse out the fields in a string, with the `Formatter.parse()` method:
from string import Formatter
fieldnames = [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname]
Demo:
>>> from string import Formatter
>>> yourstring = "path/to/{self.category}/{self.name}"
>>> [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname]
['self.category', 'self.name']
>>> yourstring = "non-keyword {keyword1} {{escaped brackets}} {} {keyword2}"
>>> [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname]
['keyword1', 'keyword2']
You can parse those field names further; for that you can use the `str._formatter_field_name_split()` method (Python 2) / `_string.formatter_field_name_split()` function (Python 3) (this internal implementation detail is not otherwise exposed; `Formatter.get_field()` uses it internally). This function returns the first part of the name, the one that'd be looked up on in the arguments passed to `str.format()`, plus a generator for the rest of the field.
The generator yields `(is_attribute, name)` tuples; `is_attribute` is true if the next name is to be treated as an attribute, false if it is an item to look up with `obj[name]`:
try:
# Python 3
from _string import formatter_field_name_split
except ImportError:
formatter_field_name_split = str._formatter_field_name_split
from string import Formatter
field_references = {formatter_field_name_split(fname)[0]
for _, fname, _, _ in Formatter().parse(yourstring) if fname}
Demo:
>>> from string import Formatter
>>> from _string import formatter_field_name_split
>>> yourstring = "path/to/{self.category}/{self.name}"
>>> {formatter_field_name_split(fname)[0]
... for _, fname, _, _ in Formatter().parse(yourstring) if fname}
{'self'}
Take into account that this function is part of the internal implementation details of the `Formatter()` class and can be changed or removed from Python without notice, and may not even be available in other Python implementations.
Problem
I want to provide automatic string formatting in an API such that: ``` my_api("path/to/{self.category}/{self.name}", ...) ``` can be replaced with the values of attributes called out in the formatting string. How do I extract the keyword arguments from a Python format string: ``` "non-keyword {keyword1} {{escaped brackets}} {} {keyword2}" => 'keyword1', 'keyword2' ```