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 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(f"Created a copy-on-write reflink from {src} to {dest}")
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(f"Created a hardlink from {src} to {dest}")
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(f"Created a softlink from {src} to {dest}")
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
- logger.info(f"Unable to link {src} to {dest}; falling back to copy.")
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 random import SystemRandom
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
- yield Path(tdir) / "-".join(filter(None, ["thds-core-tmp-def-fs", basename]))
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thds.core
3
- Version: 1.40.20250701190355
3
+ Version: 1.41.20250703020848
4
4
  Summary: Core utilities.
5
5
  Author-email: Trilliant Health <info@trillianthealth.com>
6
6
  License: MIT
@@ -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=kmFJIFvEZc16-7S7IGvtTpzwl3VuvFl3yPlE6WJJ03w,5404
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=KgBAwQCmpm7I762eLRu-3MSfH3dKnqlrJkZ5nmPcRbc,3110
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.40.20250701190355.dist-info/METADATA,sha256=0dIbr5SQsLbx0vRbK1R78no19nLyuBIa0dOCzoUA4RY,2216
73
- thds_core-1.40.20250701190355.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
74
- thds_core-1.40.20250701190355.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
75
- thds_core-1.40.20250701190355.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
76
- thds_core-1.40.20250701190355.dist-info/RECORD,,
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,,