@@ -5402,246 +5402,6 @@ def _int(x):
54025402_exact_half = re .compile ("50*$" ).match
54035403del re
54045404
5405- ### ##### PEP3101 support functions ##############################################
5406- ### # The functions in this section have little to do with the Decimal
5407- ### # class, and could potentially be reused or adapted for other pure
5408- ### # Python numeric classes that want to implement __format__
5409- ### #
5410- ### # A format specifier for Decimal looks like:
5411- ### #
5412- ### # [[fill]align][sign][#][0][minimumwidth][,][.precision][type]
5413- ###
5414- ### _parse_format_specifier_regex = re.compile(r"""\A
5415- ### (?:
5416- ### (?P<fill>.)?
5417- ### (?P<align>[<>=^])
5418- ### )?
5419- ### (?P<sign>[-+ ])?
5420- ### (?P<alt>\#)?
5421- ### (?P<zeropad>0)?
5422- ### (?P<minimumwidth>(?!0)\d+)?
5423- ### (?P<thousands_sep>,)?
5424- ### (?:\.(?P<precision>0|(?!0)\d+))?
5425- ### (?P<type>[eEfFgGn%])?
5426- ### \Z
5427- ### """, re.VERBOSE|re.DOTALL)
5428-
5429-
5430- ### def _parse_format_specifier(format_spec, _localeconv=None):
5431- ### """Parse and validate a format specifier.
5432- ###
5433- ### Turns a standard numeric format specifier into a dict, with the
5434- ### following entries:
5435- ###
5436- ### fill: fill character to pad field to minimum width
5437- ### align: alignment type, either '<', '>', '=' or '^'
5438- ### sign: either '+', '-' or ' '
5439- ### minimumwidth: nonnegative integer giving minimum width
5440- ### zeropad: boolean, indicating whether to pad with zeros
5441- ### thousands_sep: string to use as thousands separator, or ''
5442- ### grouping: grouping for thousands separators, in format
5443- ### used by localeconv
5444- ### decimal_point: string to use for decimal point
5445- ### precision: nonnegative integer giving precision, or None
5446- ### type: one of the characters 'eEfFgG%', or None
5447- ###
5448- ### """
5449- ### m = _parse_format_specifier_regex.match(format_spec)
5450- ### if m is None:
5451- ### raise ValueError("Invalid format specifier: " + format_spec)
5452- ###
5453- ### # get the dictionary
5454- ### format_dict = m.groupdict()
5455- ###
5456- ### # zeropad; defaults for fill and alignment. If zero padding
5457- ### # is requested, the fill and align fields should be absent.
5458- ### fill = format_dict['fill']
5459- ### align = format_dict['align']
5460- ### format_dict['zeropad'] = (format_dict['zeropad'] is not None)
5461- ### if format_dict['zeropad']:
5462- ### if fill is not None:
5463- ### raise ValueError("Fill character conflicts with '0'"
5464- ### " in format specifier: " + format_spec)
5465- ### if align is not None:
5466- ### raise ValueError("Alignment conflicts with '0' in "
5467- ### "format specifier: " + format_spec)
5468- ### format_dict['fill'] = fill or ' '
5469- ### # PEP 3101 originally specified that the default alignment should
5470- ### # be left; it was later agreed that right-aligned makes more sense
5471- ### # for numeric types. See http://bugs.python.org/issue6857.
5472- ### format_dict['align'] = align or '>'
5473- ###
5474- ### # default sign handling: '-' for negative, '' for positive
5475- ### if format_dict['sign'] is None:
5476- ### format_dict['sign'] = '-'
5477- ###
5478- ### # minimumwidth defaults to 0; precision remains None if not given
5479- ### format_dict['minimumwidth'] = int(format_dict['minimumwidth'] or '0')
5480- ### if format_dict['precision'] is not None:
5481- ### format_dict['precision'] = int(format_dict['precision'])
5482- ###
5483- ### # if format type is 'g' or 'G' then a precision of 0 makes little
5484- ### # sense; convert it to 1. Same if format type is unspecified.
5485- ### if format_dict['precision'] == 0:
5486- ### if format_dict['type'] is None or format_dict['type'] in 'gGn':
5487- ### format_dict['precision'] = 1
5488- ###
5489- ### # determine thousands separator, grouping, and decimal separator, and
5490- ### # add appropriate entries to format_dict
5491- ### if format_dict['type'] == 'n':
5492- ### # apart from separators, 'n' behaves just like 'g'
5493- ### format_dict['type'] = 'g'
5494- ### if _localeconv is None:
5495- ### _localeconv = _locale.localeconv()
5496- ### if format_dict['thousands_sep'] is not None:
5497- ### raise ValueError("Explicit thousands separator conflicts with "
5498- ### "'n' type in format specifier: " + format_spec)
5499- ### format_dict['thousands_sep'] = _localeconv['thousands_sep']
5500- ### format_dict['grouping'] = _localeconv['grouping']
5501- ### format_dict['decimal_point'] = _localeconv['decimal_point']
5502- ### else:
5503- ### if format_dict['thousands_sep'] is None:
5504- ### format_dict['thousands_sep'] = ''
5505- ### format_dict['grouping'] = [3, 0]
5506- ### format_dict['decimal_point'] = '.'
5507- ###
5508- ### return format_dict
5509- ###
5510- ### def _format_align(sign, body, spec):
5511- ### """Given an unpadded, non-aligned numeric string 'body' and sign
5512- ### string 'sign', add padding and alignment conforming to the given
5513- ### format specifier dictionary 'spec' (as produced by
5514- ### parse_format_specifier).
5515- ###
5516- ### """
5517- ### # how much extra space do we have to play with?
5518- ### minimumwidth = spec['minimumwidth']
5519- ### fill = spec['fill']
5520- ### padding = fill*(minimumwidth - len(sign) - len(body))
5521- ###
5522- ### align = spec['align']
5523- ### if align == '<':
5524- ### result = sign + body + padding
5525- ### elif align == '>':
5526- ### result = padding + sign + body
5527- ### elif align == '=':
5528- ### result = sign + padding + body
5529- ### elif align == '^':
5530- ### half = len(padding)//2
5531- ### result = padding[:half] + sign + body + padding[half:]
5532- ### else:
5533- ### raise ValueError('Unrecognised alignment field')
5534- ###
5535- ### return result
5536- ###
5537- ### def _group_lengths(grouping):
5538- ### """Convert a localeconv-style grouping into a (possibly infinite)
5539- ### iterable of integers representing group lengths.
5540- ###
5541- ### """
5542- ### # The result from localeconv()['grouping'], and the input to this
5543- ### # function, should be a list of integers in one of the
5544- ### # following three forms:
5545- ### #
5546- ### # (1) an empty list, or
5547- ### # (2) nonempty list of positive integers + [0]
5548- ### # (3) list of positive integers + [locale.CHAR_MAX], or
5549- ###
5550- ### from itertools import chain, repeat
5551- ### if not grouping:
5552- ### return []
5553- ### elif grouping[-1] == 0 and len(grouping) >= 2:
5554- ### return chain(grouping[:-1], repeat(grouping[-2]))
5555- ### elif grouping[-1] == _locale.CHAR_MAX:
5556- ### return grouping[:-1]
5557- ### else:
5558- ### raise ValueError('unrecognised format for grouping')
5559- ###
5560- ### def _insert_thousands_sep(digits, spec, min_width=1):
5561- ### """Insert thousands separators into a digit string.
5562- ###
5563- ### spec is a dictionary whose keys should include 'thousands_sep' and
5564- ### 'grouping'; typically it's the result of parsing the format
5565- ### specifier using _parse_format_specifier.
5566- ###
5567- ### The min_width keyword argument gives the minimum length of the
5568- ### result, which will be padded on the left with zeros if necessary.
5569- ###
5570- ### If necessary, the zero padding adds an extra '0' on the left to
5571- ### avoid a leading thousands separator. For example, inserting
5572- ### commas every three digits in '123456', with min_width=8, gives
5573- ### '0,123,456', even though that has length 9.
5574- ###
5575- ### """
5576- ###
5577- ### sep = spec['thousands_sep']
5578- ### grouping = spec['grouping']
5579- ###
5580- ### groups = []
5581- ### for l in _group_lengths(grouping):
5582- ### if l <= 0:
5583- ### raise ValueError("group length should be positive")
5584- ### # max(..., 1) forces at least 1 digit to the left of a separator
5585- ### l = min(max(len(digits), min_width, 1), l)
5586- ### groups.append('0'*(l - len(digits)) + digits[-l:])
5587- ### digits = digits[:-l]
5588- ### min_width -= l
5589- ### if not digits and min_width <= 0:
5590- ### break
5591- ### min_width -= len(sep)
5592- ### else:
5593- ### l = max(len(digits), min_width, 1)
5594- ### groups.append('0'*(l - len(digits)) + digits[-l:])
5595- ### return sep.join(reversed(groups))
5596- ###
5597- ### def _format_sign(is_negative, spec):
5598- ### """Determine sign character."""
5599- ###
5600- ### if is_negative:
5601- ### return '-'
5602- ### elif spec['sign'] in ' +':
5603- ### return spec['sign']
5604- ### else:
5605- ### return ''
5606- ###
5607- ### def _format_number(is_negative, intpart, fracpart, exp, spec):
5608- ### """Format a number, given the following data:
5609- ###
5610- ### is_negative: true if the number is negative, else false
5611- ### intpart: string of digits that must appear before the decimal point
5612- ### fracpart: string of digits that must come after the point
5613- ### exp: exponent, as an integer
5614- ### spec: dictionary resulting from parsing the format specifier
5615- ###
5616- ### This function uses the information in spec to:
5617- ### insert separators (decimal separator and thousands separators)
5618- ### format the sign
5619- ### format the exponent
5620- ### add trailing '%' for the '%' type
5621- ### zero-pad if necessary
5622- ### fill and align if necessary
5623- ### """
5624- ###
5625- ### sign = _format_sign(is_negative, spec)
5626- ###
5627- ### if fracpart or spec['alt']:
5628- ### fracpart = spec['decimal_point'] + fracpart
5629- ###
5630- ### if exp != 0 or spec['type'] in 'eE':
5631- ### echar = {'E': 'E', 'e': 'e', 'G': 'E', 'g': 'e'}[spec['type']]
5632- ### fracpart += "{0}{1:+}".format(echar, exp)
5633- ### if spec['type'] == '%':
5634- ### fracpart += '%'
5635- ###
5636- ### if spec['zeropad']:
5637- ### min_width = spec['minimumwidth'] - len(fracpart) - len(sign)
5638- ### else:
5639- ### min_width = 0
5640- ### intpart = _insert_thousands_sep(intpart, spec, min_width)
5641- ###
5642- ### return _format_align(sign, intpart+fracpart, spec)
5643- ###
5644- ###
56455405##### Useful Constants (internal use only) ################################
56465406
56475407# Reusable defaults
0 commit comments