There are two somewhat related problems here, the simple answer to how to debug is: you can't, at least not with print statements, or anything itself using string formatting because that happens during another string format and destroys the state of the formatter.
That it throws an error is caused by the fact that string.Formatter()
doesn't support empty fields, this was an addition to the formatting going from 2.6 to 3.1 (and 2.7), which is in the C code, but not reflected in the string
module.
You can simulate the new behavior by subclassing the class MyFormatter
:
from __future__ import print_function
from string import Formatter
import sys
w = 10
x = dict(a=1, ab=2, abc=3)
if sys.version_info < (3,):
int_type = (int, long)
else:
int_type = (int)
class MyFormatter(Formatter):
def vformat(self, *args):
self._automatic = None
return super(MyFormatter, self).vformat(*args)
def get_value(self, key, args, kwargs):
if key == '':
if self._automatic is None:
self._automatic = 0
elif self._automatic == -1:
raise ValueError("cannot switch from manual field specification "
"to automatic field numbering")
key = self._automatic
self._automatic += 1
elif isinstance(key, int_type):
if self._automatic is None:
self._automatic = -1
elif self._automatic != -1:
raise ValueError("cannot switch from automatic field numbering "
"to manual field specification")
return super(MyFormatter, self).get_value(key, args, kwargs)
that should get rid of the KeyError
. After that you should override the method format_field
instead of parse
:
if sys.version_info < (3,):
string_type = basestring
else:
string_type = str
class TrailingFormatter(MyFormatter):
def format_field(self, value, spec):
if isinstance(value, string_type) and len(spec) > 1 and spec[0] == 't':
value += spec[1] # append the extra character
spec = spec[2:]
return super(TrailingFormatter, self).format_field(value, spec)
kf = TrailingFormatter()
w = 10
for k in sorted(x):
v = x[k]
print(kf.format('key {:t:<{}} {}', k, w, v))
and get:
key a: 1
key ab: 2
key abc: 3
Note the format specifier (t
) that introduces the trailing character in the format string.
The Python formatting routines are actually smart enough to let you insert the trailing character in the string just like the width formatting:
print(kf.format('key {:t{}<{}} {}', k, ':', w, v))
gives the same result and lets you dynamically change the ':
'
You can also change format_field
to be:
def format_field(self, value, spec):
if len(spec) > 1 and spec[0] == 't':
value = str(value) + spec[1] # append the extra character
spec = spec[2:]
return super(TrailingFormatter, self).format_field(value, spec)
and hand in any type:
print(kf.format('key {:t{}<{}} {}', (1, 2), '@', 10, 3))
to get:
key (1, 2)@ 3
but since you convert the value to a string before handing it to Formatter.formatfield()
that might get you a different result if str(val)
gets you a different value than using {0}.format(val)
and/or with options after t:
that only apply to non-string types (such as +
and -
)