MCPcopy
hub / github.com/psf/black / normalize_string_quotes

Function normalize_string_quotes

src/black/strings.py:169–239  ·  view source on GitHub ↗

Prefer double quotes but only if it doesn't cause more escaping. Adds or removes backslashes as appropriate.

(s: str)

Source from the content-addressed store, hash-verified

167
168
169def normalize_string_quotes(s: str) -> str:
170 """Prefer double quotes but only if it doesn't cause more escaping.
171
172 Adds or removes backslashes as appropriate.
173 """
174 value = s.lstrip(STRING_PREFIX_CHARS)
175 if value[:3] == '"""':
176 return s
177
178 elif value[:3] == "'''":
179 orig_quote = "'''"
180 new_quote = '"""'
181 elif value[0] == '"':
182 orig_quote = '"'
183 new_quote = "'"
184 else:
185 orig_quote = "'"
186 new_quote = '"'
187 first_quote_pos = s.find(orig_quote)
188 assert first_quote_pos != -1, f"INTERNAL ERROR: Malformed string {s!r}"
189
190 prefix = s[:first_quote_pos]
191 unescaped_new_quote = _cached_compile(rf"(([^\\]|^)(\\\\)*){new_quote}")
192 escaped_new_quote = _cached_compile(rf"([^\\]|^)\\((?:\\\\)*){new_quote}")
193 escaped_orig_quote = _cached_compile(rf"([^\\]|^)\\((?:\\\\)*){orig_quote}")
194 body = s[first_quote_pos + len(orig_quote) : -len(orig_quote)]
195 if "r" in prefix.casefold():
196 if unescaped_new_quote.search(body):
197 # There's at least one unescaped new_quote in this raw string
198 # so converting is impossible
199 return s
200
201 # Do not introduce or remove backslashes in raw strings
202 new_body = body
203 else:
204 # remove unnecessary escapes
205 new_body = sub_twice(escaped_new_quote, rf"\1\2{new_quote}", body)
206 if body != new_body:
207 # Consider the string without unnecessary escapes as the original
208 body = new_body
209 s = f"{prefix}{orig_quote}{body}{orig_quote}"
210 new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body)
211 new_body = sub_twice(unescaped_new_quote, rf"\1\\{new_quote}", new_body)
212
213 if "f" in prefix.casefold():
214 matches = re.findall(
215 r"""
216 (?:(?<!\{)|^)\{ # start of the string or a non-{ followed by a single {
217 ([^{].*?) # contents of the brackets except if begins with {{
218 \}(?:(?!\})|$) # A } followed by end of the string or a non-}
219 """,
220 new_body,
221 re.VERBOSE,
222 )
223 for m in matches:
224 if "\\" in str(m):
225 # Do not introduce backslashes in interpolated expressions
226 return s

Callers 3

visit_STRINGMethod · 0.90

Calls 2

_cached_compileFunction · 0.85
sub_twiceFunction · 0.85

Tested by

no test coverage detected