prefix = leaf.value[:first_quote_pos]
unescaped_new_quote = re.compile(rf"(([^\\]|^)(\\\\)*){new_quote}")
- escaped_new_quote = re.compile(rf"([^\\]|^)\\(\\\\)*{new_quote}")
- escaped_orig_quote = re.compile(rf"([^\\]|^)\\(\\\\)*{orig_quote}")
+ escaped_new_quote = re.compile(rf"([^\\]|^)\\((?:\\\\)*){new_quote}")
+ escaped_orig_quote = re.compile(rf"([^\\]|^)\\((?:\\\\)*){orig_quote}")
body = leaf.value[first_quote_pos + len(orig_quote) : -len(orig_quote)]
if "r" in prefix.casefold():
if unescaped_new_quote.search(body):
# Do not introduce or remove backslashes in raw strings
new_body = body
else:
- # remove unnecessary quotes
+ # remove unnecessary escapes
new_body = sub_twice(escaped_new_quote, rf"\1\2{new_quote}", body)
if body != new_body:
- # Consider the string without unnecessary quotes as the original
+ # Consider the string without unnecessary escapes as the original
body = new_body
leaf.value = f"{prefix}{orig_quote}{body}{orig_quote}"
new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body)
"""Generate all files under `path` whose paths are not excluded by the
`exclude` regex, but are included by the `include` regex.
+ Symbolic links pointing outside of the root directory are ignored.
+
`report` is where output about exclusions goes.
"""
assert root.is_absolute(), f"INTERNAL ERROR: `root` must be absolute but is {root}"
for child in path.iterdir():
- normalized_path = "/" + child.resolve().relative_to(root).as_posix()
+ try:
+ normalized_path = "/" + child.resolve().relative_to(root).as_posix()
+ except ValueError:
+ if child.is_symlink():
+ report.path_ignored(
+ child,
+ "is a symbolic link that points outside of the root directory",
+ )
+ continue
+
+ raise
+
if child.is_dir():
normalized_path += "/"
exclude_match = exclude.search(normalized_path)