mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Upgrade string from CPython 3.14.2
This commit is contained in:
committed by
Jeong, YunWon
parent
346481d95e
commit
076d692b42
60
Lib/string.py → Lib/string/__init__.py
vendored
60
Lib/string.py → Lib/string/__init__.py
vendored
@@ -49,11 +49,18 @@ def capwords(s, sep=None):
|
||||
|
||||
|
||||
####################################################################
|
||||
import re as _re
|
||||
from collections import ChainMap as _ChainMap
|
||||
|
||||
_sentinel_dict = {}
|
||||
|
||||
|
||||
class _TemplatePattern:
|
||||
# This descriptor is overwritten in ``Template._compile_pattern()``.
|
||||
def __get__(self, instance, cls=None):
|
||||
if cls is None:
|
||||
return self
|
||||
return cls._compile_pattern()
|
||||
_TemplatePattern = _TemplatePattern()
|
||||
|
||||
|
||||
class Template:
|
||||
"""A string class for supporting $-substitutions."""
|
||||
|
||||
@@ -64,14 +71,21 @@ class Template:
|
||||
# See https://bugs.python.org/issue31672
|
||||
idpattern = r'(?a:[_a-z][_a-z0-9]*)'
|
||||
braceidpattern = None
|
||||
flags = _re.IGNORECASE
|
||||
flags = None # default: re.IGNORECASE
|
||||
|
||||
pattern = _TemplatePattern # use a descriptor to compile the pattern
|
||||
|
||||
def __init_subclass__(cls):
|
||||
super().__init_subclass__()
|
||||
if 'pattern' in cls.__dict__:
|
||||
pattern = cls.pattern
|
||||
else:
|
||||
delim = _re.escape(cls.delimiter)
|
||||
cls._compile_pattern()
|
||||
|
||||
@classmethod
|
||||
def _compile_pattern(cls):
|
||||
import re # deferred import, for performance
|
||||
|
||||
pattern = cls.__dict__.get('pattern', _TemplatePattern)
|
||||
if pattern is _TemplatePattern:
|
||||
delim = re.escape(cls.delimiter)
|
||||
id = cls.idpattern
|
||||
bid = cls.braceidpattern or cls.idpattern
|
||||
pattern = fr"""
|
||||
@@ -82,7 +96,10 @@ class Template:
|
||||
(?P<invalid>) # Other ill-formed delimiter exprs
|
||||
)
|
||||
"""
|
||||
cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE)
|
||||
if cls.flags is None:
|
||||
cls.flags = re.IGNORECASE
|
||||
pat = cls.pattern = re.compile(pattern, cls.flags | re.VERBOSE)
|
||||
return pat
|
||||
|
||||
def __init__(self, template):
|
||||
self.template = template
|
||||
@@ -105,7 +122,8 @@ class Template:
|
||||
if mapping is _sentinel_dict:
|
||||
mapping = kws
|
||||
elif kws:
|
||||
mapping = _ChainMap(kws, mapping)
|
||||
from collections import ChainMap
|
||||
mapping = ChainMap(kws, mapping)
|
||||
# Helper function for .sub()
|
||||
def convert(mo):
|
||||
# Check the most common path first.
|
||||
@@ -124,7 +142,8 @@ class Template:
|
||||
if mapping is _sentinel_dict:
|
||||
mapping = kws
|
||||
elif kws:
|
||||
mapping = _ChainMap(kws, mapping)
|
||||
from collections import ChainMap
|
||||
mapping = ChainMap(kws, mapping)
|
||||
# Helper function for .sub()
|
||||
def convert(mo):
|
||||
named = mo.group('named') or mo.group('braced')
|
||||
@@ -170,10 +189,6 @@ class Template:
|
||||
self.pattern)
|
||||
return ids
|
||||
|
||||
# Initialize Template.pattern. __init_subclass__() is automatically called
|
||||
# only for subclasses, not for the Template class itself.
|
||||
Template.__init_subclass__()
|
||||
|
||||
|
||||
########################################################################
|
||||
# the Formatter class
|
||||
@@ -212,19 +227,20 @@ class Formatter:
|
||||
# this is some markup, find the object and do
|
||||
# the formatting
|
||||
|
||||
# handle arg indexing when empty field_names are given.
|
||||
if field_name == '':
|
||||
# handle arg indexing when empty field first parts are given.
|
||||
field_first, _ = _string.formatter_field_name_split(field_name)
|
||||
if field_first == '':
|
||||
if auto_arg_index is False:
|
||||
raise ValueError('cannot switch from manual field '
|
||||
'specification to automatic field '
|
||||
'numbering')
|
||||
field_name = str(auto_arg_index)
|
||||
field_name = str(auto_arg_index) + field_name
|
||||
auto_arg_index += 1
|
||||
elif field_name.isdigit():
|
||||
elif isinstance(field_first, int):
|
||||
if auto_arg_index:
|
||||
raise ValueError('cannot switch from manual field '
|
||||
'specification to automatic field '
|
||||
'numbering')
|
||||
raise ValueError('cannot switch from automatic field '
|
||||
'numbering to manual field '
|
||||
'specification')
|
||||
# disable auto arg incrementing, if it gets
|
||||
# used later on, then an exception will be raised
|
||||
auto_arg_index = False
|
||||
33
Lib/string/templatelib.py
vendored
Normal file
33
Lib/string/templatelib.py
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
"""Support for template string literals (t-strings)."""
|
||||
|
||||
t = t"{0}"
|
||||
Template = type(t)
|
||||
Interpolation = type(t.interpolations[0])
|
||||
del t
|
||||
|
||||
def convert(obj, /, conversion):
|
||||
"""Convert *obj* using formatted string literal semantics."""
|
||||
if conversion is None:
|
||||
return obj
|
||||
if conversion == 'r':
|
||||
return repr(obj)
|
||||
if conversion == 's':
|
||||
return str(obj)
|
||||
if conversion == 'a':
|
||||
return ascii(obj)
|
||||
raise ValueError(f'invalid conversion specifier: {conversion}')
|
||||
|
||||
def _template_unpickle(*args):
|
||||
import itertools
|
||||
|
||||
if len(args) != 2:
|
||||
raise ValueError('Template expects tuple of length 2 to unpickle')
|
||||
|
||||
strings, interpolations = args
|
||||
parts = []
|
||||
for string, interpolation in itertools.zip_longest(strings, interpolations):
|
||||
if string is not None:
|
||||
parts.append(string)
|
||||
if interpolation is not None:
|
||||
parts.append(interpolation)
|
||||
return Template(*parts)
|
||||
Reference in New Issue
Block a user