mirror of
https://github.com/python/cpython.git
synced 2025-09-11 19:27:07 +00:00
Backport of PEP 3101, Advanced String Formatting, from py3k.
Highlights: - Adding PyObject_Format. - Adding string.Format class. - Adding __format__ for str, unicode, int, long, float, datetime. - Adding builtin format. - Adding ''.format and u''.format. - str/unicode fixups for formatters. The files in Objects/stringlib that implement PEP 3101 (stringdefs.h, unicodedefs.h, formatter.h, string_format.h) are identical in trunk and py3k. Any changes from here on should be made to trunk, and changes will propogate to py3k).
This commit is contained in:
parent
e139688d34
commit
a9f7d62480
27 changed files with 3873 additions and 23 deletions
112
Lib/string.py
112
Lib/string.py
|
@ -527,3 +527,115 @@ try:
|
|||
letters = lowercase + uppercase
|
||||
except ImportError:
|
||||
pass # Use the original versions
|
||||
|
||||
########################################################################
|
||||
# the Formatter class
|
||||
# see PEP 3101 for details and purpose of this class
|
||||
|
||||
# The hard parts are reused from the C implementation. They're
|
||||
# exposed here via the sys module. sys was chosen because it's always
|
||||
# available and doesn't have to be dynamically loaded.
|
||||
|
||||
# The overall parser is implemented in str._formatter_parser.
|
||||
# The field name parser is implemented in str._formatter_field_name_split
|
||||
|
||||
class Formatter(object):
|
||||
def format(self, format_string, *args, **kwargs):
|
||||
return self.vformat(format_string, args, kwargs)
|
||||
|
||||
def vformat(self, format_string, args, kwargs):
|
||||
used_args = set()
|
||||
result = self._vformat(format_string, args, kwargs, used_args, 2)
|
||||
self.check_unused_args(used_args, args, kwargs)
|
||||
return result
|
||||
|
||||
def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
|
||||
if recursion_depth < 0:
|
||||
raise ValueError('Max string recursion exceeded')
|
||||
result = []
|
||||
for literal_text, field_name, format_spec, conversion in \
|
||||
self.parse(format_string):
|
||||
|
||||
# output the literal text
|
||||
if literal_text:
|
||||
result.append(literal_text)
|
||||
|
||||
# if there's a field, output it
|
||||
if field_name is not None:
|
||||
# this is some markup, find the object and do
|
||||
# the formatting
|
||||
|
||||
# given the field_name, find the object it references
|
||||
# and the argument it came from
|
||||
obj, arg_used = self.get_field(field_name, args, kwargs)
|
||||
used_args.add(arg_used)
|
||||
|
||||
# do any conversion on the resulting object
|
||||
obj = self.convert_field(obj, conversion)
|
||||
|
||||
# expand the format spec, if needed
|
||||
format_spec = self._vformat(format_spec, args, kwargs,
|
||||
used_args, recursion_depth-1)
|
||||
|
||||
# format the object and append to the result
|
||||
result.append(self.format_field(obj, format_spec))
|
||||
|
||||
return ''.join(result)
|
||||
|
||||
|
||||
def get_value(self, key, args, kwargs):
|
||||
if isinstance(key, (int, long)):
|
||||
return args[key]
|
||||
else:
|
||||
return kwargs[key]
|
||||
|
||||
|
||||
def check_unused_args(self, used_args, args, kwargs):
|
||||
pass
|
||||
|
||||
|
||||
def format_field(self, value, format_spec):
|
||||
return format(value, format_spec)
|
||||
|
||||
|
||||
def convert_field(self, value, conversion):
|
||||
# do any conversion on the resulting object
|
||||
if conversion == 'r':
|
||||
return repr(value)
|
||||
elif conversion == 's':
|
||||
return str(value)
|
||||
elif conversion is None:
|
||||
return value
|
||||
raise ValueError("Unknown converion specifier {0!s}".format(conversion))
|
||||
|
||||
|
||||
# returns an iterable that contains tuples of the form:
|
||||
# (literal_text, field_name, format_spec, conversion)
|
||||
# literal_text can be zero length
|
||||
# field_name can be None, in which case there's no
|
||||
# object to format and output
|
||||
# if field_name is not None, it is looked up, formatted
|
||||
# with format_spec and conversion and then used
|
||||
def parse(self, format_string):
|
||||
return format_string._formatter_parser()
|
||||
|
||||
|
||||
# given a field_name, find the object it references.
|
||||
# field_name: the field being looked up, e.g. "0.name"
|
||||
# or "lookup[3]"
|
||||
# used_args: a set of which args have been used
|
||||
# args, kwargs: as passed in to vformat
|
||||
def get_field(self, field_name, args, kwargs):
|
||||
first, rest = field_name._formatter_field_name_split()
|
||||
|
||||
obj = self.get_value(first, args, kwargs)
|
||||
|
||||
# loop through the rest of the field_name, doing
|
||||
# getattr or getitem as needed
|
||||
for is_attr, i in rest:
|
||||
if is_attr:
|
||||
obj = getattr(obj, i)
|
||||
else:
|
||||
obj = obj[i]
|
||||
|
||||
return obj, first
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue