1

A format string with : and / present. When tried formatting with a value dict it's throwing:

ValueError: Missing ']' in format string

Example:

In [312]: value
Out[312]: {'key:/key_part': 1}

In [313]: string_to_format
Out[313]: '{v[key:/key_part]}'

In [314]: string_to_format.format(v=SafeDict(value))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-314-3ee97d9dfb86> in <module>()
----> 1 string_to_format.format(v=SafeDict(value))

ValueError: Missing ']' in format string

where SafeDict is the implementation used from this SO answer.

In [311]: class SafeDict(dict):
     ...:     def __missing__(self, key):
     ...:         return "NULL"

Any ideas on how to get through this?

martineau
  • 119,623
  • 25
  • 170
  • 301
Yogaraj
  • 322
  • 1
  • 4
  • 17
  • 1
    Change to Python 3, where it works. – wim Jul 15 '20 at 15:44
  • Perhaps `string_to_format = '{v}'; string_to_format.format(v=SafeDict(value)['key:/key_part'])` instead? – 0x5453 Jul 15 '20 at 16:01
  • @0x5453 there will be multiple keys in the format string like mentioned above. I guess this wouldn't work on multiple keys. – Yogaraj Jul 15 '20 at 16:03
  • @wim, Yes, I already tried it in python3 and it works. But I need this to work on python2 instead. Any ideas on how to achieve this in python2? – Yogaraj Jul 15 '20 at 16:11
  • @Yogaraj No. Does not work in Python 2 and never will, because it's EOL. – wim Jul 15 '20 at 22:04

1 Answers1

3

This is a known limitation of the basic parsing used in string formatting implementation. The section Simple and Compound Field Names in PEP 3101 describes 'getitem' support in str.format syntax (emphasis mine):

An example of the 'getitem' syntax:

"My name is {0[name]}".format(dict(name='Fred'))

It should be noted that the use of 'getitem' within a format string is much more limited than its conventional usage. In the above example, the string 'name' really is the literal string 'name', not a variable named 'name'. The rules for parsing an item key are very simple. If it starts with a digit, then it is treated as a number, otherwise it is used as a string.

Because keys are not quote-delimited, it is not possible to specify arbitrary dictionary keys (e.g., the strings "10" or ":-]") from within a format string.

And later under the "Implementation note":

The str.format() function will have a minimalist parser which only attempts to figure out when it is "done" with an identifier (by finding a '.' or a ']', or '}', etc.).

So this a shortcoming of str.format by design. The attentive reader may note that the OP's string formatting works in Python 3. Some edge cases were patched up in Python 3.4, yet the same issue is still present in Python 3.3 and below.

The relevant ticket was issue12014: str.format parses replacement field incorrectly. Since Python 2.7 is end-of-life now, the chances of getting those improvements from Python 3.4 backported to 2.7 are zero, so you will have to choose between two options:

  1. Upgrade to Python 3
  2. Refactor your code so that string formatting only uses simple names or numbers
wim
  • 338,267
  • 99
  • 616
  • 750