New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-38208: Simplify string.Template by using __init_subclass__(). #16256
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,30 +54,7 @@ def capwords(s, sep=None): | |
|
||
_sentinel_dict = {} | ||
|
||
class _TemplateMetaclass(type): | ||
pattern = r""" | ||
%(delim)s(?: | ||
(?P<escaped>%(delim)s) | # Escape sequence of two delimiters | ||
(?P<named>%(id)s) | # delimiter and a Python identifier | ||
{(?P<braced>%(bid)s)} | # delimiter and a braced identifier | ||
(?P<invalid>) # 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): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like a better approach, but if you're modernizing this then I have a few other suggestions. |
||
super().__init_subclass__() | ||
if 'pattern' in cls.__dict__: | ||
pattern = cls.pattern | ||
else: | ||
pattern = r""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps this pattern ought to be put at module scope, just above the class definition? The verbose representation might be more readable without all that leading whitespace. |
||
%(delim)s(?: | ||
(?P<escaped>%(delim)s) | # Escape sequence of two delimiters | ||
(?P<named>%(id)s) | # delimiter and a Python identifier | ||
{(?P<braced>%(bid)s)} | # delimiter and a braced identifier | ||
(?P<invalid>) # Other ill-formed delimiter exprs | ||
) | ||
""" % { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Too bad we can't convert this to a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can. We can even convert it to f-string. I tried, but returned to the old format. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only problem with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With f-string it would look: def __init_subclass__(cls):
super().__init_subclass__()
if 'pattern' in cls.__dict__:
pattern = cls.pattern
else:
delim = _re.escape(cls.delimiter)
id = cls.idpattern
bid = cls.braceidpattern or cls.idpattern
pattern = fr"""
{delim}(?:
(?P<escaped>{delim}) | # Escape sequence of two delimiters
(?P<named>{id}) | # delimiter and a Python identifier
{{(?P<braced>{bid})}} | # delimiter and a braced identifier
(?P<invalid>) # Other ill-formed delimiter exprs
)
"""
cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE) |
||
'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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit of a head scratcher, but I think the comment could be improved to make it more clear. What's really going on is that this is required to initialize There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would appreciate your help with a comment. |
||
|
||
|
||
######################################################################## | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes aren't related to the title of this PR. Please either split it out into a separate PR, or retitle this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yes. They are from other issue.