From ce02c9ba0655f43923ce5e9369f1bf88f9bb30e8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 18 Sep 2019 09:14:32 +0300 Subject: [PATCH 1/3] bpo-38208: Simplify string.Template by using __init_subclass__(). --- Lib/dataclasses.py | 9 ++++----- Lib/string.py | 45 +++++++++++++++++++++------------------------ 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 9020c905d1176d..508b09560c4662 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -199,11 +199,7 @@ def __repr__(self): # https://bugs.python.org/issue33453 for details. _MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)') -class _InitVarMeta(type): - def __getitem__(self, params): - return InitVar(params) - -class InitVar(metaclass=_InitVarMeta): +class InitVar: __slots__ = ('type', ) def __init__(self, type): @@ -212,6 +208,9 @@ def __init__(self, type): def __repr__(self): return f'dataclasses.InitVar[{self.type.__name__}]' + def __class_getitem__(cls, params): + return InitVar(params) + # Instances of Field are only ever created from within this module, # and only from the field() function, although Field instances are diff --git a/Lib/string.py b/Lib/string.py index b423ff5dc6f69f..2fb81f4cffd694 100644 --- a/Lib/string.py +++ b/Lib/string.py @@ -54,30 +54,7 @@ def capwords(s, sep=None): _sentinel_dict = {} -class _TemplateMetaclass(type): - pattern = r""" - %(delim)s(?: - (?P%(delim)s) | # Escape sequence of two delimiters - (?P%(id)s) | # delimiter and a Python identifier - {(?P%(bid)s)} | # delimiter and a braced identifier - (?P) # Other ill-formed delimiter exprs - ) - """ - - def __init__(cls, name, bases, dct): - super(_TemplateMetaclass, cls).__init__(name, bases, dct) - if 'pattern' in dct: - pattern = cls.pattern - else: - pattern = _TemplateMetaclass.pattern % { - 'delim' : _re.escape(cls.delimiter), - 'id' : cls.idpattern, - 'bid' : cls.braceidpattern or cls.idpattern, - } - cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE) - - -class Template(metaclass=_TemplateMetaclass): +class Template: """A string class for supporting $-substitutions.""" delimiter = '$' @@ -89,6 +66,25 @@ class Template(metaclass=_TemplateMetaclass): braceidpattern = None flags = _re.IGNORECASE + def __init_subclass__(cls): + super().__init_subclass__() + if 'pattern' in cls.__dict__: + pattern = cls.pattern + else: + pattern = r""" + %(delim)s(?: + (?P%(delim)s) | # Escape sequence of two delimiters + (?P%(id)s) | # delimiter and a Python identifier + {(?P%(bid)s)} | # delimiter and a braced identifier + (?P) # Other ill-formed delimiter exprs + ) + """ % { + 'delim' : _re.escape(cls.delimiter), + 'id' : cls.idpattern, + 'bid' : cls.braceidpattern or cls.idpattern, + } + cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE) + def __init__(self, template): self.template = template @@ -146,6 +142,7 @@ def convert(mo): self.pattern) return self.pattern.sub(convert, self.template) +Template.__init_subclass__() # setup pattern ######################################################################## From 606a4daf33b9b1f5bf7de252faff77ee223446e4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 18 Sep 2019 23:10:01 +0300 Subject: [PATCH 2/3] Remove unrelated changes. --- Lib/dataclasses.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 508b09560c4662..9020c905d1176d 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -199,7 +199,11 @@ def __repr__(self): # https://bugs.python.org/issue33453 for details. _MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)') -class InitVar: +class _InitVarMeta(type): + def __getitem__(self, params): + return InitVar(params) + +class InitVar(metaclass=_InitVarMeta): __slots__ = ('type', ) def __init__(self, type): @@ -208,9 +212,6 @@ def __init__(self, type): def __repr__(self): return f'dataclasses.InitVar[{self.type.__name__}]' - def __class_getitem__(cls, params): - return InitVar(params) - # Instances of Field are only ever created from within this module, # and only from the field() function, although Field instances are From 68d895b36e908ef670fbf18580cba5e381a4e097 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 18 Sep 2019 23:30:41 +0300 Subject: [PATCH 3/3] Address review comments. --- Lib/string.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Lib/string.py b/Lib/string.py index 2fb81f4cffd694..489777b10c25df 100644 --- a/Lib/string.py +++ b/Lib/string.py @@ -71,18 +71,17 @@ def __init_subclass__(cls): if 'pattern' in cls.__dict__: pattern = cls.pattern else: - pattern = r""" - %(delim)s(?: - (?P%(delim)s) | # Escape sequence of two delimiters - (?P%(id)s) | # delimiter and a Python identifier - {(?P%(bid)s)} | # delimiter and a braced identifier - (?P) # Other ill-formed delimiter exprs + delim = _re.escape(cls.delimiter) + id = cls.idpattern + bid = cls.braceidpattern or cls.idpattern + pattern = fr""" + {delim}(?: + (?P{delim}) | # Escape sequence of two delimiters + (?P{id}) | # delimiter and a Python identifier + {{(?P{bid})}} | # delimiter and a braced identifier + (?P) # Other ill-formed delimiter exprs ) - """ % { - 'delim' : _re.escape(cls.delimiter), - 'id' : cls.idpattern, - 'bid' : cls.braceidpattern or cls.idpattern, - } + """ cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE) def __init__(self, template): @@ -142,7 +141,9 @@ def convert(mo): self.pattern) return self.pattern.sub(convert, self.template) -Template.__init_subclass__() # setup pattern +# Initialize Template.pattern. __init_subclass__() is automatically called +# only for subclasses, not for the Template class itself. +Template.__init_subclass__() ########################################################################