My first thought was that this is a job for string.Template, which has
always struck me as subclassing-friendly.   Took about a half hour of
wrangling the regex to get here:

from string import Template, _sentinel_dict

class TemplateWithDefaults(Template):
    braceidpattern = r'([_a-z][_a-z0-9]*))((:(?P<default>([^}]*)))?'

    def substitute(self, mapping=_sentinel_dict, /, **kws):
        if mapping is _sentinel_dict:
            mapping = kws
        elif kws:
            mapping = _ChainMap(kws, mapping)
        def convert(mo):
            named = mo.group('named') or mo.group('braced')
            if named is not None:
                try:
                    return str(mapping[named])
                except KeyError:
                    default = mo.group('default')
                    if not default:
                        raise
                    return default
            if mo.group('escaped') is not None:
                return self.delimiter
            if mo.group('invalid') is not None:
                self._invalid(mo)
            raise ValueError('Unrecognized named group in pattern',
self.pattern)
        return self.pattern.sub(convert, self.template)

template = TemplateWithDefaults('Where ${prep:was} my default?  ${here}.')

options = {'prep':'is', 'here':'Nowhere'}
print(template.substitute(options))
print(template.substitute(here='Here'))
print(template.substitute())  # Should fail with key error on 'here'

On Fri, Apr 1, 2022 at 8:13 AM Brian McCall <brian.patrick.mcc...@gmail.com>
wrote:

> Oh, I didn't even know about `format_map`! Or `__format__` for that
> matter. This makes everything much easier. For my purposes, I don't even
> need to use `__format__` since I am not using format strings.
>
> In a show of appreciation, here is a URL to a GIF of James Corden bowing:
> https://media.giphy.com/media/l2R0eYcNq9rJUsVAA/giphy.gif
>
> ```
> class Options(UserDict):
>     def __getitem__(self, key):
>         if key in self:
>             return super().__getitem__(key)
>         key, *default = key.split('?')
>         if key in self:
>             return super().__getitem__(key)
>         return ''.join(default)
>
> options = {'baud': 19200}
> result = 'BAUD: {baud?9600}'.format_map(Options(options))
> print(result)
>
> options = {}
> result = 'BAUD: {baud?9600}'.format_map(Options(options))
> print(result)
>
> ```
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/HPV3AJ4PUYDGVWAKLQQQL7EEHSRBP7N7/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/UM7BUM3N3UYC3KTMO7QIHACIMR2P5GCP/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to