Coverage for texgit / repository / fix_path.py: 100%
25 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-22 02:50 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-22 02:50 +0000
1"""A tool for fixing all occurrences of a Path."""
3from contextlib import suppress
4from itertools import chain
5from os import sep
6from re import MULTILINE, Match, escape, sub
7from typing import Final
9from pycommons.io.path import Path
11#: the replacement string for base paths
12BASE_PATH_REPLACEMENT: Final[str] = "{...}"
14#: the literal string start and ends.
15__SE: Final[tuple[tuple[str, str], ...]] = tuple(sorted(chain(
16 ((escape(strs), escape(stre)) for strs, stre in (
17 (" ", " "), ("'", "'"), ("(", ")"), ("{", "}"), ("[", "]"),
18 ("<", ">"), ("`", "`"), (",", " "), (",", ","), ('"', '"'),
19 (";", " "), (";", ";"), (" ", ". "))),
20 (("^", "$"), ("^", " "), (" ", "$"), ("^", ","), (",", "$"),
21 ("^", ";"), (";", "$"), ("^", escape(". ")),
22 ("^", escape(".") + "$"))),
23))
26def replace_base_path(orig: str, base_path: str) -> str:
27 r"""
28 Replace all occurrences of the `base_path` in the original string.
30 Any reasonably delimited occurrence of `base_path` as well as any sub-path
31 under `base_path` that points to an existing file or directory are
32 replaced with relativizations starting with `{...}`.
34 :param orig: the original string
35 :param base_path: the base path
36 :return: the fixed string
38 >>> from pycommons.io.temp import temp_dir
39 >>> with temp_dir() as td:
40 ... td.resolve_inside("x").ensure_dir_exists()
41 ... td.resolve_inside("x/y").write_all_str("5")
42 ... a = replace_base_path(f"blablabla {td}/x ", td)
43 ... b = replace_base_path(f"{td}/x/y", td)
44 ... c = replace_base_path(f"{td}/x.", td)
45 ... d = replace_base_path("\n".join(("blaa", f"{td}/x.x", "y")), td)
46 ... e = replace_base_path("\n".join(("blaa", f"{td}/x.", "y")), td)
47 ... f = replace_base_path(f"xc'{td}/x/y'yy", td)
48 ... g = replace_base_path(td, td)
49 ... h = replace_base_path(td + "/", td)
50 >>> a
51 'blablabla {...}/x '
53 >>> b
54 '{...}/x/y'
56 >>> c
57 '{...}/x.'
59 >>> d[-6:]
60 '/x.x\ny'
62 >>> e
63 'blaa\n{...}/x.\ny'
65 >>> f
66 "xc'{...}/x/y'yy"
68 >>> g
69 '{...}'
71 >>> h
72 '{...}/'
73 """
74 if str.__len__(orig) <= 0:
75 return ""
76 path: Final[Path] = Path(base_path)
77 path_re: Final[str] = escape(path)
79 def __replacer(data: Match, __bp: Path = path) -> str:
80 prefix: Final[str] = data.group(1)
81 subpath: Final[str] = data.group(2)
82 suffix: Final[str] = data.group(3)
83 with suppress(ValueError):
84 usesubpath: Final[str] = subpath[str.__len__(sep):] \
85 if subpath.startswith(sep) else subpath
86 if (str.__len__(usesubpath) <= 0) \
87 or __bp.resolve_inside(usesubpath).exists():
88 return f"{prefix}{{...}}{subpath}{suffix}"
89 return data.group(0)
91 for start, end in __SE:
92 orig = sub(f"({start}){path_re}(.*?)({end})", __replacer, orig,
93 flags=MULTILINE)
94 return orig