String.Formatter throws KeyError ''

I want to print the key + value pairs, as in this question ,

key a:         1
key ab:        2
key abc:       3
       ^ this colon is what I want

but I don't like the answer there, and I tried to subclass string.Formatteras follows:

from __future__ import print_function

from string import Formatter

class KeyFormatter(Formatter):
    def parse(self, fmtstr):
        res = super(KeyFormatter, self).parse(fmtstr)
        #for r in res:
        #    print(r)
        return res

kf = KeyFormatter()
w = 10

x = dict(a=1, ab=2, abc=3)

for k in sorted(x):
    v = x[k]
    print(kf.format('key {::<{}} {}', k, w, v))

I want to debug parsing to see if I can get an extra " :" inserted in the format string, but this gives

KeyError: '' in both Python 2.7 and 3.4. If I uncomment the for loop to see what happens in the error, it leaves, but the final print statement only shows a new line.

When I do the last line:

print('key {:<{}} {}'.format(k, w, v))

this works (with spaces after the key), and when I do:

print('key {::<{}} {}'.format(k, w, v))

I get a few ':' instead of spaces. But without KeyError.

Why am I getting KeyError? How can I debug this?

+4
1

: : , , , - , , .

, , , string.Formatter() , , 2.6 3.1 ( 2.7), C, string.

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)

KeyError. format_field 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))

:

key a:         1
key ab:        2
key abc:       3

(t), .

Python , , :

    print(kf.format('key {:t{}<{}} {}', k, ':', w, v))

':'

format_field :

    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)

:

print(kf.format('key {:t{}<{}} {}', (1, 2), '@', 10, 3))

:

key (1, 2)@    3

Formatter.formatfield(), , str(val) , {0}.format(val) / t:, (, + -)

0

Source: https://habr.com/ru/post/1606404/


All Articles