Skip to content

Commit 76e61fd

Browse files
committed
Replace remaining .format() calls with fstrings
1 parent 62da3cd commit 76e61fd

File tree

6 files changed

+43
-62
lines changed

6 files changed

+43
-62
lines changed

soupsieve/css_match.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -1571,11 +1571,9 @@ def iselect(self, tag: bs4.Tag, limit: int = 0) -> Iterator[bs4.Tag]:
15711571
def __repr__(self) -> str: # pragma: no cover
15721572
"""Representation."""
15731573

1574-
return "SoupSieve(pattern={!r}, namespaces={!r}, custom={!r}, flags={!r})".format(
1575-
self.pattern,
1576-
self.namespaces,
1577-
self.custom,
1578-
self.flags
1574+
return (
1575+
f"SoupSieve(pattern={self.pattern!r}, namespaces={self.namespaces!r}, "
1576+
f"custom={self.custom!r}, flags={self.flags!r})"
15791577
)
15801578

15811579
__str__ = __repr__

soupsieve/css_parser.py

+29-45
Original file line numberDiff line numberDiff line change
@@ -101,32 +101,26 @@
101101
CSS_ESCAPES = fr'(?:\\(?:[a-f0-9]{{1,6}}{WS}?|[^\r\n\f]|$))'
102102
CSS_STRING_ESCAPES = fr'(?:\\(?:[a-f0-9]{{1,6}}{WS}?|[^\r\n\f]|$|{NEWLINE}))'
103103
# CSS Identifier
104-
IDENTIFIER = r'''
105-
(?:(?:-?(?:[^\x00-\x2f\x30-\x40\x5B-\x5E\x60\x7B-\x9f]|{esc})+|--)
106-
(?:[^\x00-\x2c\x2e\x2f\x3A-\x40\x5B-\x5E\x60\x7B-\x9f]|{esc})*)
107-
'''.format(esc=CSS_ESCAPES)
104+
IDENTIFIER = fr'''
105+
(?:(?:-?(?:[^\x00-\x2f\x30-\x40\x5B-\x5E\x60\x7B-\x9f]|{CSS_ESCAPES})+|--)
106+
(?:[^\x00-\x2c\x2e\x2f\x3A-\x40\x5B-\x5E\x60\x7B-\x9f]|{CSS_ESCAPES})*)
107+
'''
108108
# `nth` content
109-
NTH = r'(?:[-+])?(?:[0-9]+n?|n)(?:(?<=n){ws}*(?:[-+]){ws}*(?:[0-9]+))?'.format(ws=WSC)
109+
NTH = fr'(?:[-+])?(?:[0-9]+n?|n)(?:(?<=n){WSC}*(?:[-+]){WSC}*(?:[0-9]+))?'
110110
# Value: quoted string or identifier
111-
VALUE = r'''
112-
(?:"(?:\\(?:.|{nl})|[^\\"\r\n\f]+)*?"|'(?:\\(?:.|{nl})|[^\\'\r\n\f]+)*?'|{ident}+)
113-
'''.format(nl=NEWLINE, ident=IDENTIFIER)
111+
VALUE = fr'''(?:"(?:\\(?:.|{NEWLINE})|[^\\"\r\n\f]+)*?"|'(?:\\(?:.|{NEWLINE})|[^\\'\r\n\f]+)*?'|{IDENTIFIER}+)'''
114112
# Attribute value comparison. `!=` is handled special as it is non-standard.
115-
ATTR = r'''
116-
(?:{ws}*(?P<cmp>[!~^|*$]?=){ws}*(?P<value>{value})(?:{ws}*(?P<case>[is]))?)?{ws}*\]
117-
'''.format(ws=WSC, value=VALUE)
113+
ATTR = fr'(?:{WSC}*(?P<cmp>[!~^|*$]?=){WSC}*(?P<value>{VALUE})(?:{WSC}*(?P<case>[is]))?)?{WSC}*\]'
118114

119115
# Selector patterns
120116
# IDs (`#id`)
121117
PAT_ID = fr'\#{IDENTIFIER}'
122118
# Classes (`.class`)
123119
PAT_CLASS = fr'\.{IDENTIFIER}'
124120
# Prefix:Tag (`prefix|tag`)
125-
PAT_TAG = r'(?P<tag_ns>(?:{ident}|\*)?\|)?(?P<tag_name>{ident}|\*)'.format(ident=IDENTIFIER)
121+
PAT_TAG = fr'(?P<tag_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<tag_name>{IDENTIFIER}|\*)'
126122
# Attributes (`[attr]`, `[attr=value]`, etc.)
127-
PAT_ATTR = r'''
128-
\[{ws}*(?P<attr_ns>(?:{ident}|\*)?\|)?(?P<attr_name>{ident}){attr}
129-
'''.format(ws=WSC, ident=IDENTIFIER, attr=ATTR)
123+
PAT_ATTR = fr'\[{WSC}*(?P<attr_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<attr_name>{IDENTIFIER}){ATTR}'
130124
# Pseudo class (`:pseudo-class`, `:pseudo-class(`)
131125
PAT_PSEUDO_CLASS = fr'(?P<name>:{IDENTIFIER})(?P<open>\({WSC}*)?'
132126
# Pseudo class special patterns. Matches `:pseudo-class(` for special case pseudo classes.
@@ -140,45 +134,36 @@
140134
# At rule (`@page`, etc.) (not supported)
141135
PAT_AT_RULE = fr'@P{IDENTIFIER}'
142136
# Pseudo class `nth-child` (`:nth-child(an+b [of S]?)`, `:first-child`, etc.)
143-
PAT_PSEUDO_NTH_CHILD = r'''
144-
(?P<pseudo_nth_child>{name}
145-
(?P<nth_child>{nth}|even|odd))(?:{wsc}*\)|(?P<of>{comments}*{ws}{wsc}*of{comments}*{ws}{wsc}*))
146-
'''.format(name=PAT_PSEUDO_CLASS_SPECIAL, wsc=WSC, comments=COMMENTS, ws=WS, nth=NTH)
137+
PAT_PSEUDO_NTH_CHILD = fr'''
138+
(?P<pseudo_nth_child>{PAT_PSEUDO_CLASS_SPECIAL}
139+
(?P<nth_child>{NTH}|even|odd))(?:{WSC}*\)|(?P<of>{COMMENTS}*{WS}{WSC}*of{COMMENTS}*{WS}{WSC}*))
140+
'''
147141
# Pseudo class `nth-of-type` (`:nth-of-type(an+b)`, `:first-of-type`, etc.)
148-
PAT_PSEUDO_NTH_TYPE = r'''
149-
(?P<pseudo_nth_type>{name}
150-
(?P<nth_type>{nth}|even|odd)){ws}*\)
151-
'''.format(name=PAT_PSEUDO_CLASS_SPECIAL, ws=WSC, nth=NTH)
142+
PAT_PSEUDO_NTH_TYPE = fr'''
143+
(?P<pseudo_nth_type>{PAT_PSEUDO_CLASS_SPECIAL}
144+
(?P<nth_type>{NTH}|even|odd)){WSC}*\)
145+
'''
152146
# Pseudo class language (`:lang("*-de", en)`)
153-
PAT_PSEUDO_LANG = r'{name}(?P<values>{value}(?:{ws}*,{ws}*{value})*){ws}*\)'.format(
154-
name=PAT_PSEUDO_CLASS_SPECIAL, ws=WSC, value=VALUE
155-
)
147+
PAT_PSEUDO_LANG = fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<values>{VALUE}(?:{WSC}*,{WSC}*{VALUE})*){WSC}*\)'
156148
# Pseudo class direction (`:dir(ltr)`)
157149
PAT_PSEUDO_DIR = fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<dir>ltr|rtl){WSC}*\)'
158150
# Combining characters (`>`, `~`, ` `, `+`, `,`)
159-
PAT_COMBINE = r'{wsc}*?(?P<relation>[,+>~]|{ws}(?![,+>~])){wsc}*'.format(ws=WS, wsc=WSC)
151+
PAT_COMBINE = fr'{WSC}*?(?P<relation>[,+>~]|{WS}(?![,+>~])){WSC}*'
160152
# Extra: Contains (`:contains(text)`)
161-
PAT_PSEUDO_CONTAINS = r'{name}(?P<values>{value}(?:{ws}*,{ws}*{value})*){ws}*\)'.format(
162-
name=PAT_PSEUDO_CLASS_SPECIAL, ws=WSC, value=VALUE
163-
)
153+
PAT_PSEUDO_CONTAINS = fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<values>{VALUE}(?:{WSC}*,{WSC}*{VALUE})*){WSC}*\)'
164154

165155
# Regular expressions
166156
# CSS escape pattern
167157
RE_CSS_ESC = re.compile(fr'(?:(\\[a-f0-9]{{1,6}}{WSC}?)|(\\[^\r\n\f])|(\\$))', re.I)
168-
RE_CSS_STR_ESC = re.compile(
169-
fr'(?:(\\[a-f0-9]{{1,6}}{WS}?)|(\\[^\r\n\f])|(\\$)|(\\{NEWLINE}))', re.I
170-
)
158+
RE_CSS_STR_ESC = re.compile(fr'(?:(\\[a-f0-9]{{1,6}}{WS}?)|(\\[^\r\n\f])|(\\$)|(\\{NEWLINE}))', re.I)
171159
# Pattern to break up `nth` specifiers
172-
RE_NTH = re.compile(
173-
r'(?P<s1>[-+])?(?P<a>[0-9]+n?|n)(?:(?<=n){ws}*(?P<s2>[-+]){ws}*(?P<b>[0-9]+))?'.format(ws=WSC),
174-
re.I
175-
)
160+
RE_NTH = re.compile(fr'(?P<s1>[-+])?(?P<a>[0-9]+n?|n)(?:(?<=n){WSC}*(?P<s2>[-+]){WSC}*(?P<b>[0-9]+))?', re.I)
176161
# Pattern to iterate multiple values.
177-
RE_VALUES = re.compile(r'(?:(?P<value>{value})|(?P<split>{ws}*,{ws}*))'.format(ws=WSC, value=VALUE), re.X)
162+
RE_VALUES = re.compile(fr'(?:(?P<value>{VALUE})|(?P<split>{WSC}*,{WSC}*))', re.X)
178163
# Whitespace checks
179164
RE_WS = re.compile(WS)
180-
RE_WS_BEGIN = re.compile(f'^{WSC}*')
181-
RE_WS_END = re.compile(f'{WSC}*$')
165+
RE_WS_BEGIN = re.compile(fr'^{WSC}*')
166+
RE_WS_END = re.compile(fr'{WSC}*$')
182167
RE_CUSTOM = re.compile(fr'^{PAT_PSEUDO_CLASS_CUSTOM}$', re.X)
183168

184169
# Constants
@@ -419,11 +404,10 @@ def __str__(self) -> str: # pragma: no cover
419404
"""String representation."""
420405

421406
return (
422-
'_Selector(tag={!r}, ids={!r}, classes={!r}, attributes={!r}, nth={!r}, selectors={!r}, '
423-
'relations={!r}, rel_type={!r}, contains={!r}, lang={!r}, flags={!r}, no_match={!r})'
424-
).format(
425-
self.tag, self.ids, self.classes, self.attributes, self.nth, self.selectors,
426-
self.relations, self.rel_type, self.contains, self.lang, self.flags, self.no_match
407+
f'_Selector(tag={self.tag!r}, ids={self.ids!r}, classes={self.classes!r}, attributes={self.attributes!r}, '
408+
f'nth={self.nth!r}, selectors={self.selectors!r}, relations={self.relations!r}, '
409+
f'rel_type={self.rel_type!r}, contains={self.contains!r}, lang={self.lang!r}, flags={self.flags!r}, '
410+
f'no_match={self.no_match!r})'
427411
)
428412

429413
__repr__ = __str__

soupsieve/css_types.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,8 @@ def __setattr__(self, name: str, value: Any) -> None:
8383
def __repr__(self) -> str: # pragma: no cover
8484
"""Representation."""
8585

86-
return "{}({})".format(
87-
self.__class__.__name__, ', '.join([f"{k}={getattr(self, k)!r}" for k in self.__slots__[:-1]])
88-
)
86+
r = ', '.join([f"{k}={getattr(self, k)!r}" for k in self.__slots__[:-1]])
87+
return f"{self.__class__.__name__}({r})"
8988

9089
__str__ = __repr__
9190

soupsieve/pretty.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,14 @@ def pretty(obj: Any) -> str: # pragma: no cover
124124
index = m.end(0)
125125
if name in ('class', 'lstrt', 'dstrt', 'tstrt'):
126126
indent += 4
127-
output.append('{}\n{}'.format(m.group(0), " " * indent))
127+
output.append(f'{m.group(0)}\n{" " * indent}')
128128
elif name in ('param', 'int', 'kword', 'sqstr', 'dqstr', 'empty'):
129129
output.append(m.group(0))
130130
elif name in ('lend', 'dend', 'tend'):
131131
indent -= 4
132132
output.append(m.group(0))
133133
elif name in ('sep',):
134-
output.append('{}\n{}'.format(m.group(1), " " * indent))
134+
output.append(f'{m.group(1)}\n{" " * indent}')
135135
elif name in ('dsep',):
136136
output.append(f'{m.group(1)} ')
137137
break

tests/test_level3/test_namespace.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,18 @@ def wrap_xlink(self, content, xhtml=False):
6262

6363
xhtml_ns = 'xmlns="http://www.w3.org/1999/xhtml"' if xhtml else ''
6464

65-
return """
65+
return f"""
6666
<?xml version="1.0" encoding="UTF-8"?>
6767
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
6868
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
69-
<html {} xmlns:xlink="http://www.w3.org/1999/xlink">
69+
<html {xhtml_ns} xmlns:xlink="http://www.w3.org/1999/xlink">
7070
<head>
7171
</head>
7272
<body>
73-
{}
73+
{content}
7474
</body>
7575
</html>
76-
""".format(xhtml_ns, content)
76+
"""
7777

7878
def test_namespace(self):
7979
"""Test namespace."""

tests/util.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,18 @@ class TestCase(unittest.TestCase):
4343
def wrap_xhtml(self, html):
4444
"""Wrap HTML content with XHTML header and body."""
4545

46-
return """
46+
return f"""
4747
<?xml version="1.0" encoding="UTF-8"?>
4848
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
4949
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
5050
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
5151
<head>
5252
</head>
5353
<body>
54-
{}
54+
{html}
5555
</body>
5656
</html>
57-
""".format(html)
57+
"""
5858

5959
def setUp(self):
6060
"""Setup."""

0 commit comments

Comments
 (0)