thds.mops 3.8.20250602165815__py3-none-any.whl → 3.8.20250602182922__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.mops might be problematic. Click here for more details.

@@ -9,7 +9,7 @@ from typing_extensions import ParamSpec
9
9
  from thds.core import stack_context
10
10
  from thds.mops._utils import config_tree
11
11
 
12
- from ..core import file_blob_store, pipeline_id_mask, uris
12
+ from ..core import file_blob_store, pipeline_id, pipeline_id_mask, uris
13
13
  from ..core.memo.unique_name_for_function import full_name_and_callable
14
14
  from ..core.use_runner import use_runner
15
15
  from ..pickling.mprunner import MemoizingPicklingRunner
@@ -125,7 +125,7 @@ class Magic(ty.Generic[P, R]):
125
125
 
126
126
  def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
127
127
  """This is the wrapped function."""
128
- with pipeline_id_mask.pipeline_id_mask(self._pipeline_id):
128
+ with pipeline_id.set_pipeline_id_for_stack(self._pipeline_id):
129
129
  return self._func(*args, **kwargs)
130
130
 
131
131
  def __repr__(self) -> str:
@@ -12,6 +12,7 @@ Ask me how long it took to figure out what was going on there...
12
12
 
13
13
  import argparse
14
14
  import os
15
+ import sys
15
16
  import time
16
17
  from timeit import default_timer
17
18
 
@@ -28,7 +29,11 @@ def main() -> None:
28
29
  """Routes the top level remote function call in a new process."""
29
30
  start = default_timer()
30
31
  start_timestamp = time.time()
31
- logger.info(f"Entering remote process {os.getpid()} with installed mops version {__version__}")
32
+ remote_proc_log = f"Entering remote process {os.getpid()} with installed mops version {__version__}"
33
+ if remote_code_version := metadata.get_remote_code_version(""):
34
+ remote_proc_log += f" and remote code version {remote_code_version}"
35
+ logger.info(remote_proc_log)
36
+ logger.info("mops full sys.argv: " + " ".join(sys.argv))
32
37
  parser = argparse.ArgumentParser(description="Unknown arguments will be passed to the named runner.")
33
38
  parser.add_argument(
34
39
  "runner_name",
@@ -140,12 +140,8 @@ import typing as ty
140
140
  from thds import humenc
141
141
  from thds.core import config
142
142
 
143
- from ..pipeline_id_mask import (
144
- extract_from_docstr,
145
- get_pipeline_id,
146
- get_pipeline_id_mask,
147
- pipeline_id_mask,
148
- )
143
+ from ..pipeline_id import get_pipeline_id_for_stack
144
+ from ..pipeline_id_mask import extract_from_docstr, get_pipeline_id_mask, pipeline_id_mask
149
145
  from ..uris import lookup_blob_store
150
146
  from . import calls
151
147
  from .unique_name_for_function import make_unique_name_including_docstring_key, parse_unique_name
@@ -187,7 +183,7 @@ def matching_mask_pipeline_id(pipeline_id: str, callable_regex: str) -> _Pipelin
187
183
  def _handler(callable_name: str, runner_prefix: str) -> ty.Optional[str]:
188
184
  if re.match(callable_regex, callable_name):
189
185
  return lookup_blob_store(runner_prefix).join(
190
- runner_prefix, pipeline_id or get_pipeline_id(), callable_name
186
+ runner_prefix, pipeline_id or get_pipeline_id_for_stack(), callable_name
191
187
  )
192
188
  return None
193
189
 
@@ -1,9 +1,11 @@
1
1
  # This file must not import anything else from `remote.core` - it is a 'leaf' of our tree
2
2
  # because it is depended upon by so many other things.
3
3
  import os
4
+ import typing as ty
5
+ from contextlib import contextmanager
4
6
  from datetime import datetime
5
7
 
6
- from thds.core import hostname, log, meta
8
+ from thds.core import hostname, log, meta, stack_context
7
9
 
8
10
  from ..._utils.colorize import colorized
9
11
 
@@ -60,3 +62,16 @@ def set_pipeline_id(new_pipeline_id: str) -> None:
60
62
  return # quietly disallow empty strings, since we always want a value here.
61
63
  global _PIPELINE_ID
62
64
  _PIPELINE_ID = new_pipeline_id
65
+
66
+
67
+ _STACK_LOCAL_PIPELINE_ID = stack_context.StackContext("STACK_LOCAL_PIPELINE_ID", "")
68
+
69
+
70
+ @contextmanager
71
+ def set_pipeline_id_for_stack(new_pipeline_id: str) -> ty.Iterator[str]:
72
+ with _STACK_LOCAL_PIPELINE_ID.set(new_pipeline_id):
73
+ yield new_pipeline_id
74
+
75
+
76
+ def get_pipeline_id_for_stack() -> str:
77
+ return _STACK_LOCAL_PIPELINE_ID() or get_pipeline_id()
@@ -8,14 +8,18 @@ from functools import lru_cache
8
8
 
9
9
  from thds.core.stack_context import StackContext
10
10
 
11
- from .pipeline_id import get_pipeline_id
11
+ from .pipeline_id import get_pipeline_id_for_stack
12
12
 
13
13
  _PIPELINE_ID_MASK = StackContext("PIPELINE_ID_MASK", "")
14
14
 
15
15
 
16
16
  def get_pipeline_id_mask() -> str:
17
- """Returns the 'current' pipeline id, preferring a mask over the global."""
18
- return _PIPELINE_ID_MASK() or get_pipeline_id()
17
+ """Returns the 'current' pipeline id, preferring:
18
+ - the mask
19
+ - the stack local
20
+ - the global
21
+ """
22
+ return _PIPELINE_ID_MASK() or get_pipeline_id_for_stack()
19
23
 
20
24
 
21
25
  @contextmanager
@@ -33,6 +33,7 @@ have a Source object returned to it while it performs low-level deserialization.
33
33
  """
34
34
 
35
35
  import io
36
+ import sys
36
37
  import typing as ty
37
38
  from functools import partial
38
39
  from pathlib import Path
@@ -174,7 +175,7 @@ def prepare_source_argument(source_: Source) -> ty.Union[str, hashing.Hash]:
174
175
  partial(_write_hashref, _hashref_uri(source_.hash, "remote"), source_.uri),
175
176
  )
176
177
 
177
- return source_.hash
178
+ return hashing.Hash(algo=sys.intern(source_.hash.algo), bytes=source_.hash.bytes)
178
179
 
179
180
 
180
181
  def perform_source_uploads() -> None: # has been replaced by a general work-deferring mechanism.
@@ -9,7 +9,6 @@ from ..._utils.once import Once
9
9
  from ..core import lock, metadata, pipeline_id, uris
10
10
  from ..core.entry import route_return_value_or_exception
11
11
  from ..core.memo import results
12
- from ..core.pipeline_id_mask import pipeline_id_mask
13
12
  from ..core.serialize_big_objs import ByIdRegistry, ByIdSerializer
14
13
  from ..core.serialize_paths import CoordinatingPathSerializer
15
14
  from ..core.types import Args, BlobStore, Kwargs, T
@@ -124,7 +123,7 @@ def run_pickled_invocation(memo_uri: str, *metadata_args: str) -> None:
124
123
  def do_work_return_result() -> object:
125
124
  # ONLY failures in this code should transmit an EXCEPTION
126
125
  # back to the orchestrator side.
127
- return pipeline_id_mask(invocation_metadata.pipeline_id)(func)(*args, **kwargs)
126
+ return func(*args, **kwargs)
128
127
 
129
128
  route_return_value_or_exception(
130
129
  _ResultExcWithMetadataChannel(
@@ -122,11 +122,12 @@ def invoke_via_shim_or_return_memoized( # noqa: C901
122
122
  raise exc
123
123
  finally:
124
124
  run_summary.log_function_execution(
125
- *(run_directory, func, memo_uri, result_and_itype.invoc_type),
125
+ *(run_directory, memo_uri, result_and_itype.invoc_type),
126
126
  metadata=metadata,
127
127
  runner_prefix=function_memospace.split(pipeline_id)[0],
128
128
  was_error=not isinstance(result, memo.results.Success),
129
129
  return_value=value_t,
130
+ args_kwargs=(args, kwargs),
130
131
  )
131
132
 
132
133
  def acquire_lock() -> ty.Optional[lock.LockAcquired]:
@@ -28,6 +28,7 @@ class FunctionSummary(TypedDict):
28
28
  total_runtime_minutes: List[float] # minutes
29
29
  remote_runtime_minutes: List[float] # minutes
30
30
  uris_in_rvalue: List[str]
31
+ uris_in_args_kwargs: List[str]
31
32
 
32
33
 
33
34
  def _empty_summary() -> FunctionSummary:
@@ -46,6 +47,7 @@ def _empty_summary() -> FunctionSummary:
46
47
  "total_runtime_minutes": list(),
47
48
  "remote_runtime_minutes": list(),
48
49
  "uris_in_rvalue": list(),
50
+ "uris_in_args_kwargs": list(),
49
51
  }
50
52
 
51
53
 
@@ -77,6 +79,7 @@ def _process_log_file(log_file: Path) -> Dict[str, FunctionSummary]:
77
79
  summary["error_count"] += int(log_entry.get("was_error") or 0)
78
80
  summary["timestamps"].append(log_entry["timestamp"])
79
81
  summary["uris_in_rvalue"].extend(log_entry.get("uris_in_rvalue") or tuple())
82
+ summary["uris_in_args_kwargs"].extend(log_entry.get("uris_in_args_kwargs") or tuple())
80
83
 
81
84
  mu_parts = parse_memo_uri(
82
85
  log_entry["memo_uri"], runner_prefix=log_entry.get("runner_prefix", "")
@@ -124,6 +127,7 @@ def _combine_summaries(
124
127
  acc[function_name]["pipeline_ids"].update(data["pipeline_ids"])
125
128
  acc[function_name]["function_logic_keys"].update(data["function_logic_keys"])
126
129
  acc[function_name]["uris_in_rvalue"].extend(data["uris_in_rvalue"])
130
+ acc[function_name]["uris_in_args_kwargs"].extend(data["uris_in_args_kwargs"])
127
131
 
128
132
  for key in (
129
133
  "invoked_by",
@@ -219,6 +223,12 @@ def _format_summary(summary: Dict[str, FunctionSummary], sort_by: SortOrder, uri
219
223
  remote_code_version=", ".join(sorted(set(data["remote_code_version"]))),
220
224
  )
221
225
  )
226
+ args_uris = and_more(
227
+ sorted(data["uris_in_args_kwargs"]),
228
+ max_count=uri_limit if uri_limit >= 0 else sys.maxsize,
229
+ ).replace(", ", "\n ")
230
+ if args_uris:
231
+ report_lines.append(f" URIs in args/kwargs:\n {args_uris}\n")
222
232
  n_uris = and_more(
223
233
  sorted(data["uris_in_rvalue"]),
224
234
  max_count=uri_limit if uri_limit >= 0 else sys.maxsize,
@@ -228,8 +238,11 @@ def _format_summary(summary: Dict[str, FunctionSummary], sort_by: SortOrder, uri
228
238
  return "\n".join(report_lines)
229
239
 
230
240
 
231
- def _auto_find_run_directory() -> ty.Optional[Path]:
232
- mops_root = run_summary.MOPS_SUMMARY_DIR()
241
+ def auto_find_run_directory(start_dir: ty.Optional[Path] = None) -> Path:
242
+ if start_dir is None:
243
+ mops_root = run_summary.MOPS_SUMMARY_DIR()
244
+ else:
245
+ mops_root = start_dir / run_summary.MOPS_SUMMARY_DIR()
233
246
  if not mops_root.exists():
234
247
  raise ValueError(f"No mops summary root directory found at {mops_root}.")
235
248
  if not mops_root.is_dir():
@@ -242,16 +255,13 @@ def _auto_find_run_directory() -> ty.Optional[Path]:
242
255
  # needs to have some files for it to count for anything
243
256
  return directory
244
257
 
245
- print("No pipeline run directories found.")
246
- return None
258
+ raise ValueError(f"No pipeline run directories found in {mops_root}.")
247
259
 
248
260
 
249
261
  def summarize(
250
262
  run_directory: Optional[str] = None, sort_by: SortOrder = "name", uri_limit: int = 10
251
263
  ) -> None:
252
- run_directory_path = Path(run_directory) if run_directory else _auto_find_run_directory()
253
- if not run_directory_path:
254
- return
264
+ run_directory_path = Path(run_directory) if run_directory else auto_find_run_directory()
255
265
 
256
266
  print(f"Summarizing pipeline run '{run_directory_path}'\n")
257
267
  log_files = list(run_directory_path.glob("*.json"))
@@ -290,4 +300,7 @@ def main() -> None:
290
300
  ),
291
301
  )
292
302
  args = parser.parse_args()
293
- summarize(args.run_directory, args.sort_by, args.uri_limit)
303
+ try:
304
+ summarize(args.run_directory, args.sort_by, args.uri_limit)
305
+ except ValueError as e:
306
+ print(f"Error: {e}")
@@ -3,13 +3,11 @@ import json
3
3
  import os
4
4
  import pickle
5
5
  import typing as ty
6
- import uuid
7
6
  from pathlib import Path
8
7
 
9
8
  from thds.core import config, log, pickle_visit, source
10
9
  from thds.mops.pure.core.memo import function_memospace
11
10
  from thds.mops.pure.core.metadata import get_invoked_by
12
- from thds.mops.pure.core.types import T
13
11
 
14
12
  from ...core import metadata
15
13
 
@@ -43,6 +41,7 @@ class LogEntry(LogEntryV1, total=False):
43
41
  invoker_code_version: str
44
42
  remote_code_version: str
45
43
 
44
+ uris_in_args_kwargs: ty.List[str]
46
45
  uris_in_rvalue: ty.List[str]
47
46
 
48
47
 
@@ -68,58 +67,65 @@ def create_mops_run_directory() -> Path:
68
67
  return run_directory
69
68
 
70
69
 
71
- def _generate_log_filename(run_directory: Path) -> Path:
72
- """Generate a log filename using the current timestamp and a short UUID, ensuring uniqueness"""
73
- timestamp = dt.datetime.utcnow().strftime("%Y%m%d%H%M%S")
74
- short_uuid = str(uuid.uuid4())[:8]
75
- filename = f"{timestamp}-{short_uuid}.json"
70
+ def _generate_log_filename(
71
+ run_directory: Path, invoked_at: dt.datetime, name: str, args_hash: str
72
+ ) -> Path:
73
+ """Generate a log filename using an invoked_at timestamp, the function name, and part
74
+ of the args hash, ensuring uniqueness.
75
+ """
76
+ timestamp = invoked_at.strftime("%Y%m%d%H%M%S")
77
+ filename = f"{timestamp}-{args_hash[:20]}-{name}.json"
76
78
  return run_directory / filename
77
79
 
78
80
 
79
81
  def _extract_source_uris(result: ty.Any) -> ty.Set[str]:
80
- sources: ty.List[source.Source] = list()
82
+ uris: ty.Set[str] = set()
81
83
 
82
- def extract_source(unknown: ty.Any) -> None:
84
+ def extract_uri(unknown: ty.Any) -> None:
85
+ if hasattr(unknown, "stored_uri") and isinstance(unknown.stored_uri, str):
86
+ uris.add(unknown.stored_uri)
83
87
  if isinstance(unknown, source.Source):
84
- sources.append(unknown)
88
+ uris.add(unknown.uri)
89
+ if hasattr(unknown, "sa") and hasattr(unknown, "container") and hasattr(unknown, "path"):
90
+ uris.add(str(unknown))
91
+ if isinstance(unknown, str) and (unknown.startswith("adls://") or unknown.startswith("file://")):
92
+ uris.add(unknown)
93
+ if hasattr(unknown, "material"):
94
+ material = unknown.material
95
+ if callable(material):
96
+ mat = material()
97
+ for uri in _extract_source_uris(mat):
98
+ uris.add(uri)
85
99
 
86
100
  try:
87
- pickle_visit.recursive_visit(extract_source, result)
101
+ pickle_visit.recursive_visit(extract_uri, result)
88
102
  except pickle.PicklingError:
89
103
  pass
90
104
  except Exception as exc:
91
- logger.warning(f'Unexpected error trying to extract source URIs from "%s"; {exc}', result)
105
+ logger.warning(f'Unexpected error trying to extract URIs from "%s"; {exc}', result)
92
106
 
93
- return {source.uri for source in sources}
107
+ return uris
94
108
 
95
109
 
96
110
  def log_function_execution(
97
111
  run_directory: ty.Optional[Path],
98
- func: ty.Callable[..., T],
99
112
  memo_uri: str,
100
113
  itype: InvocationType,
101
114
  metadata: ty.Optional[metadata.ResultMetadata] = None,
102
115
  runner_prefix: str = "",
103
116
  was_error: bool = False,
104
117
  return_value: ty.Any = None,
118
+ args_kwargs: ty.Any = None,
105
119
  ) -> None:
106
120
  if not run_directory:
107
121
  logger.debug("Not writing function summary for %s", memo_uri)
108
122
  return
109
123
 
110
- log_file = _generate_log_filename(run_directory)
111
- try:
112
- func_module = func.__module__
113
- func_name = func.__name__
114
- full_function_name = f"{func_module}:{func_name}"
115
- except AttributeError:
116
- # this is incompatible with callables that aren't defs, e.g. callable objects
117
- # you can make this work by using functools.wraps/update_wrapper, but then `mops` will unpickle your
118
- # callable using `__module__` and `__name__`, which just gives you back the wrapped, and the wrapper is lost
119
- logger.warning("couldn't extract function module and name from %s", func)
120
- full_function_name = str(func)
124
+ invoked_at = metadata.invoked_at if metadata else dt.datetime.utcnow()
121
125
 
122
126
  parts = function_memospace.parse_memo_uri(memo_uri, runner_prefix)
127
+ full_function_name = f"{parts.function_module}:{parts.function_name}"
128
+ log_file = _generate_log_filename(run_directory, invoked_at, full_function_name, parts.args_hash)
123
129
 
124
130
  log_entry: LogEntry = {
125
131
  "function_name": full_function_name,
@@ -127,7 +133,7 @@ def log_function_execution(
127
133
  "runner_prefix": parts.runner_prefix,
128
134
  "pipeline_id": parts.pipeline_id,
129
135
  "function_logic_key": parts.function_logic_key,
130
- "timestamp": dt.datetime.utcnow().isoformat(),
136
+ "timestamp": invoked_at.isoformat(),
131
137
  "status": itype,
132
138
  "was_error": was_error,
133
139
  }
@@ -139,6 +145,8 @@ def log_function_execution(
139
145
  log_entry["remote_code_version"] = metadata.remote_code_version
140
146
  # we don't bother with invoked_at or remote_started_at because they can be
141
147
  # inferred from the timestamp and the wall times
148
+ if source_uris := _extract_source_uris(args_kwargs):
149
+ log_entry["uris_in_args_kwargs"] = sorted(source_uris)
142
150
  if source_uris := _extract_source_uris(return_value):
143
151
  log_entry["uris_in_rvalue"] = sorted(source_uris)
144
152
 
@@ -147,4 +155,6 @@ def log_function_execution(
147
155
  with log_file.open("w") as f:
148
156
  json.dump(log_entry, f, indent=2)
149
157
  except Exception:
150
- logger.exception(f"Unable to write mops function invocation log file at '{log_file}'")
158
+ logger.info(
159
+ f"Unable to write mops function invocation log file at '{log_file}' - you may have multiple callers for the same invocation"
160
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thds.mops
3
- Version: 3.8.20250602165815
3
+ Version: 3.8.20250602182922
4
4
  Summary: ML Ops tools for Trilliant Health
5
5
  Author-email: Trilliant Health <info@trillianthealth.com>
6
6
  Project-URL: Repository, https://github.com/TrilliantHealth/ds-monorepo
@@ -37,7 +37,7 @@ thds/mops/k8s/tools/krsync.sh,sha256=lskw4COt51Bv1yy2IAYUc8u8uQV-coSyUiOT8rADKkQ
37
37
  thds/mops/pure/__init__.py,sha256=kbG0lMvXRBS3LGbb2gPPE9-qjYMXrypyb2tJX2__aZc,1533
38
38
  thds/mops/pure/_magic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  thds/mops/pure/_magic/api.py,sha256=kSlediIZQYsmeHB8plP6osjvUuSEVW4NWdY9ADia12Y,5094
40
- thds/mops/pure/_magic/sauce.py,sha256=LDiv4YnJ4yQ7YW8t4Qr8bB6p3l5KcteSxMuO--BRJ3A,6316
40
+ thds/mops/pure/_magic/sauce.py,sha256=xmO6Kch-ofVnrVFkxWm84C0-ao9vVCYq0nGGMuYeaok,6333
41
41
  thds/mops/pure/_magic/shims.py,sha256=JI49ddv6lEUmNVsEl-XkGlsx2RpOMQoIOSSSfootYE8,1188
42
42
  thds/mops/pure/adls/__init__.py,sha256=fw67xxwnizBurScMa-_zWb94lo5gamEVRt27V4bR0jc,54
43
43
  thds/mops/pure/adls/_files.py,sha256=9m35Y4elWF0DjgAXVp4oi5CaY6fXWt8n67PilWxWJns,821
@@ -50,17 +50,17 @@ thds/mops/pure/core/file_blob_store.py,sha256=N4m4LLrBZaqTJFR4D_eYl03a-n6yQBRsv0
50
50
  thds/mops/pure/core/metadata.py,sha256=xAL2iz0pXrcKapmYnNrqSZ8nH2GVakA167NSpAfwiCI,8276
51
51
  thds/mops/pure/core/output_naming.py,sha256=ntufOVNJiVPiUM-Azl9mFpDFhIxiB-V2je9dv9AUQhg,2283
52
52
  thds/mops/pure/core/partial.py,sha256=aeNQFNHj9epU6lvk6NNTV6hXkNqNHN_czBydt7nkHmg,463
53
- thds/mops/pure/core/pipeline_id.py,sha256=rQP6uhwP-2rqpOxQiEOfQbRdQL0q8zSGJrb7YywlO-A,2102
54
- thds/mops/pure/core/pipeline_id_mask.py,sha256=jgH-ki6IkY3SOZR7EMjQLwZF80ll6dtND378qSQzF9Q,2735
53
+ thds/mops/pure/core/pipeline_id.py,sha256=MdiEZdLiRAoeLVum3S9HQVJHmV9JBOxpHQafMQ2jzag,2540
54
+ thds/mops/pure/core/pipeline_id_mask.py,sha256=Ll2yyQM5nSgzihx8i7fCrrSNlUUnIsbAOb3m8bq0E2w,2791
55
55
  thds/mops/pure/core/script_support.py,sha256=3j9Z1O5ynSSPmWSghtJgAj-Lt4GwYcA8cWcpUIRM7q0,952
56
56
  thds/mops/pure/core/serialize_big_objs.py,sha256=YcOS1ccs82ZWO7nTbeumErMzYVe4hgXCTsfvMggYmd8,2332
57
57
  thds/mops/pure/core/serialize_paths.py,sha256=bWI-AKNP_Tf29JGO7DKqshOh7b7gu51lfGryDXo3aMI,5787
58
- thds/mops/pure/core/source.py,sha256=f7qtgKE5q75_uq27mgtIDGMWSvakzzpB3kAsTKo4TWw,13549
58
+ thds/mops/pure/core/source.py,sha256=7E1e4pdwuuwc1DZP0V7vfU1PSZU8j7PDxyjG3hR9ND8,13622
59
59
  thds/mops/pure/core/types.py,sha256=w2g83miGhnjaWr2_4TW2Fc3BdIgoIHFbIr_wX1HC7A0,5452
60
60
  thds/mops/pure/core/uris.py,sha256=qO9_f-ro7kax6haNOPTPe81-_aUSRFELeeZH4PMTTU4,2694
61
61
  thds/mops/pure/core/use_runner.py,sha256=_YeKEjj6_9uc5UIjxcm-YKLUj4joApOdaTJCMaCLC2c,1547
62
62
  thds/mops/pure/core/entry/__init__.py,sha256=kiDcsj16CwjRSexOZW-4h4b4tDCYIS_eLS5wgu2yIlk,151
63
- thds/mops/pure/core/entry/main.py,sha256=H5NHl2WgKN-3czlDjJeJLhyXOZ38c2ixGTbh6T3SfgQ,1806
63
+ thds/mops/pure/core/entry/main.py,sha256=b1F5lFDK_hnpvW3bqzt5MWDcpKvCXZpWdEHI8zroC4k,2061
64
64
  thds/mops/pure/core/entry/route_result.py,sha256=2LcS9M2mYtu56kso0YcMEZbR1mbTWZm0hFlbE2yaf4k,2741
65
65
  thds/mops/pure/core/entry/runner_registry.py,sha256=LgEifOYXgjwox1BlBordX1U6g6QB2dAPVU6S1b_iOlk,835
66
66
  thds/mops/pure/core/lock/__init__.py,sha256=EP_5T_CF175I01NrVR0eIaWu-k3OM-xsr9pal2i61rU,215
@@ -73,7 +73,7 @@ thds/mops/pure/core/lock/types.py,sha256=f32t_e2svMOXUVzcnLkEizw6Q47g3HPQsyAkGT2
73
73
  thds/mops/pure/core/lock/write.py,sha256=4z3W9rsRIs5ZI-_g2Q6ZplQdez6DxCGJ-HZikQI3dHo,5614
74
74
  thds/mops/pure/core/memo/__init__.py,sha256=OAgSWsup07EKxITr3yjwJ8eXbhU6-P1DVeZaYIgylgc,277
75
75
  thds/mops/pure/core/memo/calls.py,sha256=kvm6kn-CbOLxZuo86BvzEJw69p7VlEJ8_mCiWd6uz-g,3631
76
- thds/mops/pure/core/memo/function_memospace.py,sha256=ooUoqqCDwsqE_Ni25SUW0iTx57kGiWMcewn1F6vYTEI,11620
76
+ thds/mops/pure/core/memo/function_memospace.py,sha256=PlQCs7dZ2Fu3gIjfzJMeOy7R5zPqYQDBp7OuViLqrpc,11644
77
77
  thds/mops/pure/core/memo/keyfunc.py,sha256=FAOEDzMcQ-0JvW4j1eaUzixnemo_373V-16kWZl7_i0,2053
78
78
  thds/mops/pure/core/memo/overwrite_params.py,sha256=ltuFxhr8gNo2iBoBz2eFPayjSV23gMdBuoLZD42lIAg,2425
79
79
  thds/mops/pure/core/memo/results.py,sha256=272pbb5jLqP0KZ5YL5fNTxl2sP2zALFHQs8du8jCfFo,3143
@@ -86,10 +86,10 @@ thds/mops/pure/pickling/_pickle.py,sha256=vn8f6uEsaAdLyxGNYb4ED6D1a6BXsZQxnV3c0Y
86
86
  thds/mops/pure/pickling/memoize_only.py,sha256=oI5CMy6IEJc46Gb_BGWNUuAe3fysS7HxRSTajN0WssI,837
87
87
  thds/mops/pure/pickling/mprunner.py,sha256=dVbwQA8hzEL7UiwYXmzoGwN3_jbEtGoHDPMkRmo_UtA,8378
88
88
  thds/mops/pure/pickling/pickles.py,sha256=nCg7L7CqReNWDF8FAdEmCcuXVC_kLT5zuyW3V8Vvvs4,4704
89
- thds/mops/pure/pickling/remote.py,sha256=XMR4-DdhxhBgbskmXCC2G9BEXJ15j6i_Rcg_-JQi_W8,6025
89
+ thds/mops/pure/pickling/remote.py,sha256=SynT9gVE3D2G2KO9oROa1iopMXxCXprP6_A3xl2IEJ4,5921
90
90
  thds/mops/pure/pickling/sha256_b64.py,sha256=HL0cPixHPZYuZDVDBscxsnI-3a2amWEfw-LseOX-PyY,2916
91
91
  thds/mops/pure/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
- thds/mops/pure/runner/local.py,sha256=qnA8d4j6cVfSqPvc_LwaPTWX-GucezGpULlE-ft0nOA,11958
92
+ thds/mops/pure/runner/local.py,sha256=UHVv_N6Fcm5XvAry-Fl2v0ay8KVr0dnDwdfCiC1wZ6w,12000
93
93
  thds/mops/pure/runner/shim_builder.py,sha256=DkOXbPaOWPj2uUsJhjlWmh8ijG9OQc4ciHqa-vHPfXw,709
94
94
  thds/mops/pure/runner/simple_shims.py,sha256=oJ8sC5EVD-JFZx8CYE3_QwaQTuFa5F3IYH5PJ9mdMtY,702
95
95
  thds/mops/pure/runner/strings.py,sha256=PYAYMxZ2ehgahKIBXJilENNE6OrdNkueNBel8LPsoh8,26
@@ -101,12 +101,12 @@ thds/mops/pure/tools/inspect.py,sha256=PYXmR9-ATB3UsJUDG5Up8B6mdfenOGx2nktjw3sxM
101
101
  thds/mops/pure/tools/sha256_b64_addressed.py,sha256=SECAiw3xSqpsrBBZix0MgJRTQrbHiUk2oFHYa7ln3q4,1137
102
102
  thds/mops/pure/tools/stress.py,sha256=f7pL5n9BmVYSZrmDJxKnUC70AIfeHhU5B9E9UDs5GJ8,2544
103
103
  thds/mops/pure/tools/summarize/__init__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
104
- thds/mops/pure/tools/summarize/cli.py,sha256=gaechsJhRZsOxGJGG1dQsW5dMBlgSv2sUmExOloDtkI,10828
105
- thds/mops/pure/tools/summarize/run_summary.py,sha256=ujJC24J0XsF5W5P-eHiIq-4gmedmFXk2g1uljuvqOvc,5373
104
+ thds/mops/pure/tools/summarize/cli.py,sha256=7kDtn24ok8oBO3jFjlMmOK3jnZYpMoE_5Y8fmDH8Imc,11524
105
+ thds/mops/pure/tools/summarize/run_summary.py,sha256=LUtvbankAYbss2NCF_XbNl05jkNgxYz_SLyERJlp4sk,5773
106
106
  thds/mops/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
107
107
  thds/mops/testing/deferred_imports.py,sha256=f0ezCgQAtzTqW1yAOb0OWgsB9ZrlztLB894LtpWDaVw,3780
108
- thds_mops-3.8.20250602165815.dist-info/METADATA,sha256=n2UMvUOVlRJyUdci9jw3NCa2KxeYMLSdpZqyMPxMxCM,2222
109
- thds_mops-3.8.20250602165815.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
110
- thds_mops-3.8.20250602165815.dist-info/entry_points.txt,sha256=GShNqjcjbq0TAJuwpyeCI5XCltiwdZxnNHkBpmYbNkU,329
111
- thds_mops-3.8.20250602165815.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
112
- thds_mops-3.8.20250602165815.dist-info/RECORD,,
108
+ thds_mops-3.8.20250602182922.dist-info/METADATA,sha256=sigW-qM8htEhi0hjYjve882Zv2GpAaxWdmnOsUc4J8o,2222
109
+ thds_mops-3.8.20250602182922.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
110
+ thds_mops-3.8.20250602182922.dist-info/entry_points.txt,sha256=GShNqjcjbq0TAJuwpyeCI5XCltiwdZxnNHkBpmYbNkU,329
111
+ thds_mops-3.8.20250602182922.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
112
+ thds_mops-3.8.20250602182922.dist-info/RECORD,,