thds.core 1.40.20250701190355__py3-none-any.whl → 1.41.20250703020848__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of thds.core might be problematic. Click here for more details.
- thds/core/link.py +10 -4
- thds/core/project_root.py +26 -0
- thds/core/tmp.py +6 -6
- {thds_core-1.40.20250701190355.dist-info → thds_core-1.41.20250703020848.dist-info}/METADATA +1 -1
- {thds_core-1.40.20250701190355.dist-info → thds_core-1.41.20250703020848.dist-info}/RECORD +8 -7
- {thds_core-1.40.20250701190355.dist-info → thds_core-1.41.20250703020848.dist-info}/WHEEL +0 -0
- {thds_core-1.40.20250701190355.dist-info → thds_core-1.41.20250703020848.dist-info}/entry_points.txt +0 -0
- {thds_core-1.40.20250701190355.dist-info → thds_core-1.41.20250703020848.dist-info}/top_level.txt +0 -0
thds/core/link.py
CHANGED
|
@@ -48,6 +48,7 @@ def link(
|
|
|
48
48
|
src = Path(src).resolve()
|
|
49
49
|
if src == Path(dest).resolve():
|
|
50
50
|
return "same"
|
|
51
|
+
|
|
51
52
|
assert os.path.exists(src), f"Source {src} does not exist"
|
|
52
53
|
|
|
53
54
|
dest_parent = _dest_parent(dest)
|
|
@@ -63,24 +64,27 @@ def link(
|
|
|
63
64
|
try:
|
|
64
65
|
subprocess.check_output(["cp", "-c", str(src), str(tmp_link_dest)])
|
|
65
66
|
os.rename(tmp_link_dest, dest)
|
|
66
|
-
logger.debug(
|
|
67
|
+
logger.debug("Created a copy-on-write reflink from %s to %s", src, dest)
|
|
67
68
|
return "ref"
|
|
69
|
+
|
|
68
70
|
except subprocess.CalledProcessError:
|
|
69
71
|
pass
|
|
70
72
|
if "hard" in attempt_types:
|
|
71
73
|
try:
|
|
72
74
|
os.link(src, tmp_link_dest)
|
|
73
75
|
os.rename(tmp_link_dest, dest)
|
|
74
|
-
logger.debug(
|
|
76
|
+
logger.debug("Created a hardlink from %s to %s", src, dest)
|
|
75
77
|
return "hard"
|
|
78
|
+
|
|
76
79
|
except OSError as oserr:
|
|
77
80
|
logger.warning(f"Unable to hard-link {src} to {dest} ({oserr})")
|
|
78
81
|
if "soft" in attempt_types:
|
|
79
82
|
try:
|
|
80
83
|
os.symlink(src, tmp_link_dest)
|
|
81
84
|
os.rename(tmp_link_dest, dest)
|
|
82
|
-
logger.debug(
|
|
85
|
+
logger.debug("Created a softlink from %s to %s", src, dest)
|
|
83
86
|
return "soft"
|
|
87
|
+
|
|
84
88
|
except OSError as oserr:
|
|
85
89
|
logger.warning(f"Unable to soft-link {src} to {dest}" f" ({oserr})")
|
|
86
90
|
|
|
@@ -112,7 +116,9 @@ def link_or_copy(src: ct.StrOrPath, dest: ct.StrOrPath, *link_types: LinkType) -
|
|
|
112
116
|
link_success_type = link(src, dest, *link_types)
|
|
113
117
|
if link_success_type:
|
|
114
118
|
return link_success_type
|
|
115
|
-
|
|
119
|
+
|
|
120
|
+
log_at_lvl = logger.debug if link_types == ("ref",) and not _IS_MAC else logger.info
|
|
121
|
+
log_at_lvl("Unable to link %s to %s using %s; falling back to copy.", src, dest, link_types)
|
|
116
122
|
|
|
117
123
|
logger.debug("Copying %s to %s", src, dest)
|
|
118
124
|
with tmp.temppath_same_fs(dest) as tmpfile:
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _find_project_root(start: Path, anchor_file_name) -> Path:
|
|
5
|
+
"""Try to find the project root path by traversing back from the starting path and finding the anchor file"""
|
|
6
|
+
project_root = start.resolve()
|
|
7
|
+
|
|
8
|
+
if not project_root.is_dir():
|
|
9
|
+
project_root = project_root.parent
|
|
10
|
+
while not (project_root / anchor_file_name).exists():
|
|
11
|
+
project_root = project_root.parent
|
|
12
|
+
if project_root == Path("/"):
|
|
13
|
+
raise ValueError("Unable to find project root")
|
|
14
|
+
|
|
15
|
+
return project_root
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def find_project_root(start: Path, anchor_file_name: str = "pyproject.toml") -> Path:
|
|
19
|
+
"""
|
|
20
|
+
Try to find the project root, identified as the first ancestor dir containing an "anchor" file.
|
|
21
|
+
If not found, return '/'.
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
return _find_project_root(start, anchor_file_name)
|
|
25
|
+
except ValueError:
|
|
26
|
+
return Path("/")
|
thds/core/tmp.py
CHANGED
|
@@ -4,12 +4,13 @@ Module is given this name partly because we tend not to name other things intern
|
|
|
4
4
|
the word 'tmp', preferring instead 'temp'. Therefore `tmp` will be a little less ambiguous
|
|
5
5
|
overall.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import contextlib
|
|
8
9
|
import shutil
|
|
9
10
|
import tempfile
|
|
10
11
|
import typing as ty
|
|
11
12
|
from pathlib import Path
|
|
12
|
-
from
|
|
13
|
+
from uuid import uuid4
|
|
13
14
|
|
|
14
15
|
from .home import HOMEDIR
|
|
15
16
|
from .types import StrOrPath
|
|
@@ -45,10 +46,7 @@ def temppath_same_fs(lcl_path: StrOrPath = "") -> ty.Iterator[Path]:
|
|
|
45
46
|
# we would prefer _not_ to reinvent the wheel here, but if the tempfiles are
|
|
46
47
|
# getting created on a different volume, then moves are no longer atomic, and
|
|
47
48
|
# that's a huge pain for lots of reasons.
|
|
48
|
-
fname_parts = [
|
|
49
|
-
".thds-core-tmp-home-fs",
|
|
50
|
-
str(SystemRandom().random())[2:], # makes a float look like a numeric string
|
|
51
|
-
]
|
|
49
|
+
fname_parts = [".core-tmp-home-fs", str(uuid4())]
|
|
52
50
|
if basename:
|
|
53
51
|
fname_parts.append(basename)
|
|
54
52
|
dpath = parent_dir / "-".join(fname_parts)
|
|
@@ -64,8 +62,10 @@ def temppath_same_fs(lcl_path: StrOrPath = "") -> ty.Iterator[Path]:
|
|
|
64
62
|
with tempfile.TemporaryDirectory() as tdir:
|
|
65
63
|
# actually check whether we're on the same filesystem.
|
|
66
64
|
if _are_same_fs(parent_dir, Path(tdir)):
|
|
67
|
-
|
|
65
|
+
# the standard path has us just using a normal temporary directory that we don't create ourselves.
|
|
66
|
+
yield Path(tdir) / "-".join(filter(None, ["core-tmp", basename]))
|
|
68
67
|
else:
|
|
68
|
+
# but if we need to do something special... here we are.
|
|
69
69
|
yield from _tempdir_same_filesystem()
|
|
70
70
|
|
|
71
71
|
|
|
@@ -23,7 +23,7 @@ thds/core/imports.py,sha256=0LVegY8I8_XKZPcqiIp2OVVzEDtyqYA3JETf9OAKNKs,568
|
|
|
23
23
|
thds/core/inspect.py,sha256=3IY9CSa7zAcAVyBDOYfMtJ2QU5cRc98JaN91XAbaSok,2368
|
|
24
24
|
thds/core/iterators.py,sha256=d3iTQDR0gCW1nMRmknQeodR_4THzR9Ajmp8F8KCCFgg,208
|
|
25
25
|
thds/core/lazy.py,sha256=e1WvG4LsbEydV0igEr_Vl1cq05zlQNIE8MFYT90yglE,3289
|
|
26
|
-
thds/core/link.py,sha256=
|
|
26
|
+
thds/core/link.py,sha256=4-9d22l_oSkKoSzlYEO-rwxO1hvvj6VETY7LwvGcX6M,5534
|
|
27
27
|
thds/core/logical_root.py,sha256=gWkIYRv9kNQfzbpxJaYiwNXVz1neZ2NvnvProtOn9d8,1399
|
|
28
28
|
thds/core/merge_args.py,sha256=7oj7dtO1-XVkfTM3aBlq3QlZbo8tb6X7E3EVIR-60t8,5781
|
|
29
29
|
thds/core/meta.py,sha256=3oX7wTO_SmrVKABFPLHHIVyNBXEil1MdGfc5s88_Isk,12134
|
|
@@ -31,6 +31,7 @@ thds/core/parallel.py,sha256=HXAn9aIYqNE5rnRN5ypxR6CUucdfzE5T5rJ_MUv-pFk,7590
|
|
|
31
31
|
thds/core/pickle_visit.py,sha256=QNMWIi5buvk2zsvx1-D-FKL7tkrFUFDs387vxgGebgU,833
|
|
32
32
|
thds/core/prof.py,sha256=5ViolfPsAPwUTHuhAe-bon7IArPGXydpGoB5uZmObDk,8264
|
|
33
33
|
thds/core/progress.py,sha256=4YGbxliDl1i-k-88w4s86uy1E69eQ6xJySGPSkpH1QM,3358
|
|
34
|
+
thds/core/project_root.py,sha256=K18U3MLthZnzmdrWmKKtHLd6iu7am9b2vNAThqknpfo,891
|
|
34
35
|
thds/core/protocols.py,sha256=4na2EeWUDWfLn5-SxfMmKegDSndJ5z-vwMhDavhCpEM,409
|
|
35
36
|
thds/core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
37
|
thds/core/scaling.py,sha256=f7CtdgK0sN6nroTq5hLAkG8xwbWhbCZUULstSKjoxO0,1615
|
|
@@ -39,7 +40,7 @@ thds/core/source_serde.py,sha256=X4c7LiT3VidejqtTel9YB6dWGB3x-ct39KF9E50Nbx4,139
|
|
|
39
40
|
thds/core/stack_context.py,sha256=17lPOuYWclUpZ-VXRkPgI4WbiMzq7_ZY6Kj1QK_1oNo,1332
|
|
40
41
|
thds/core/thunks.py,sha256=p1OvMBJ4VGMsD8BVA7zwPeAp0L3y_nxVozBF2E78t3M,1053
|
|
41
42
|
thds/core/timer.py,sha256=aOpNP-wHKaKs6ONK5fOtIOgx00FChVZquG4PeaEYH_k,5376
|
|
42
|
-
thds/core/tmp.py,sha256=
|
|
43
|
+
thds/core/tmp.py,sha256=jA8FwDbXo3hx8o4kRjAlkwpcI77X86GY4Sktkps29ho,3166
|
|
43
44
|
thds/core/types.py,sha256=sFqI_8BsB1u85PSizjBZw8PBtplC7U54E19wZZWCEvI,152
|
|
44
45
|
thds/core/log/__init__.py,sha256=bDbZvlxyymY6VrQzD8lCn0egniLEiA9hpNMAXZ7e7wY,1348
|
|
45
46
|
thds/core/log/basic_config.py,sha256=2Y9U_c4PTrIsCmaN7Ps6Xr90AhJPzdYjeUzUMqO7oFU,6704
|
|
@@ -69,8 +70,8 @@ thds/core/sqlite/structured.py,sha256=SvZ67KcVcVdmpR52JSd52vMTW2ALUXmlHEeD-VrzWV
|
|
|
69
70
|
thds/core/sqlite/types.py,sha256=oUkfoKRYNGDPZRk29s09rc9ha3SCk2SKr_K6WKebBFs,1308
|
|
70
71
|
thds/core/sqlite/upsert.py,sha256=BmKK6fsGVedt43iY-Lp7dnAu8aJ1e9CYlPVEQR2pMj4,5827
|
|
71
72
|
thds/core/sqlite/write.py,sha256=z0219vDkQDCnsV0WLvsj94keItr7H4j7Y_evbcoBrWU,3458
|
|
72
|
-
thds_core-1.
|
|
73
|
-
thds_core-1.
|
|
74
|
-
thds_core-1.
|
|
75
|
-
thds_core-1.
|
|
76
|
-
thds_core-1.
|
|
73
|
+
thds_core-1.41.20250703020848.dist-info/METADATA,sha256=eLsbync6teB85Tv_BzFaBOz8rEZxCZdCqr9nf1gpNLU,2216
|
|
74
|
+
thds_core-1.41.20250703020848.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
75
|
+
thds_core-1.41.20250703020848.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
|
|
76
|
+
thds_core-1.41.20250703020848.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
|
|
77
|
+
thds_core-1.41.20250703020848.dist-info/RECORD,,
|
|
File without changes
|
{thds_core-1.40.20250701190355.dist-info → thds_core-1.41.20250703020848.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{thds_core-1.40.20250701190355.dist-info → thds_core-1.41.20250703020848.dist-info}/top_level.txt
RENAMED
|
File without changes
|