1

So, I'm writing a small backup solution that loads some configuration settings from a YAML file. I would like to allow the user to set a naming scheme for the generated backup. Something like:

{database_name} @ {host} {month}_{year}

And allow them to freely choose fields from a set. The first thing that comes to my mind while thinking about how to convert this to a final string, is using the string's format method.

The code would then check for every possible field and if it exists, format the string accordingly. I wonder, however if there is a more pythonic way to go about this than just looping through the string, checking for every possible field and replacing the value.

FBidu
  • 972
  • 9
  • 21
  • Why would it need to 'check every possible field'? Usually templates (including format-from-dictionary) parse out the fields to replace following a set of rules. – user2864740 Mar 24 '16 at 04:39
  • Because the user could use one or more fields from a set – FBidu Mar 24 '16 at 04:40
  • maybe `grep` the used fields and replace them? – FBidu Mar 24 '16 at 04:40
  • How does that differ from (eg.) http://stackoverflow.com/questions/5952344/how-do-i-format-a-string-using-a-dictionary-in-python-3-x? – user2864740 Mar 24 '16 at 04:41
  • Because I don't know beforehand which fields I will have to replace. – FBidu Mar 24 '16 at 04:42
  • And if I just throw a dictionary with all of the possibilities, I will get an error – FBidu Mar 24 '16 at 04:42
  • @FBidu: so? the template doesn't have to use all of the fields you provide. – Martijn Pieters Mar 24 '16 at 04:43
  • really? I thought so... Gonna check it out – FBidu Mar 24 '16 at 04:43
  • 1
    Anyway, if wishing to do this manually (ie. not using str.format or another template library for whatever reason), a regular-expression-with-replacement-function would be a decent minimal approach: it allows performing a custom action for each matched token. – user2864740 Mar 24 '16 at 04:44

1 Answers1

4

Simply create a dictionary fields with all the fields you want to support, and apply that dictionary using the **keywords call syntax:

filename = template.format(**fields)

The template can use as many or as few of those fields as it requires.

Demo:

>>> fields = {'foo': 'The Foo value', 'bar': 'A barren area', 'spam': 'The greatest canned meat!', 'eggs': 'scrambled or easy over?'}
>>> template = 'Please provide me with eggs, {eggs}'
>>> template.format(**fields)
'Please provide me with eggs, scrambled or easy over?'

In this sample, the template only uses the egg field, the other available names are not used but are available for other templates.

If you do ever need to list all field names, use a string.Formatter() instance to parse out the fields:

>>> from string import Formatter
>>> list(Formatter().parse('{foo} {bar:042d}'))
[('', 'foo', '', None), (' ', 'bar', '042d', None)]

The Formatter.parse() method yields (literal_text, field_name, format_spec, conversion) tuples.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Wow, thank you! I really thought this would give me an error for throwing arguments that won't necessarily be used. Thank you – FBidu Mar 24 '16 at 04:44
  • 2
    @FBidu: always test your hypotheses! Note that neither the [`str.format()` method documentation](https://docs.python.org/2/library/stdtypes.html#str.format) nor the [format string syntax documentation](https://docs.python.org/2/library/string.html#formatstrings) state that all arguments must be used. – Martijn Pieters Mar 24 '16 at 04:49
  • yeah, I was really reckless jumping to that conclusion. Thanks for the thorough answer :D – FBidu Mar 24 '16 at 05:47