thds.mops 3.9.20251023235807__py3-none-any.whl → 3.9.20251024053258__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.

@@ -154,10 +154,6 @@ class ConfigTree(ty.Generic[V]):
154
154
  def __setitem__(self, key: str, value: V) -> None:
155
155
  self.setv(value, pathable=key)
156
156
 
157
- def __contains__(self, key: str) -> bool:
158
- """Only answers the specific question - does this exact key exist in the config?"""
159
- return key in self.registry
160
-
161
157
  def load_config(self, config: ty.Mapping[str, ty.Any]) -> None:
162
158
  """Loads things with an inner key matching this name into the config.
163
159
 
thds/mops/parallel.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import concurrent
2
2
  import typing as ty
3
3
 
4
- from thds.core import inspect, log, parallel
4
+ from thds.core import parallel
5
5
  from thds.core.parallel import ( # noqa: F401; for backward-compatibility, since these came from here originally.
6
6
  IterableWithLen,
7
7
  IteratorWithLen,
@@ -29,7 +29,6 @@ def parallel_yield_results(
29
29
  error_fmt=ERROR,
30
30
  success_fmt=DONE,
31
31
  named=named,
32
- progress_logger=log.getLogger(inspect.caller_module_name(__name__) or __name__).info,
33
32
  )
34
33
 
35
34
 
@@ -50,11 +50,6 @@ class _MagicApi:
50
50
  pipeline_id: str = "",
51
51
  calls: ty.Collection[ty.Callable] = tuple(),
52
52
  ) -> ty.Callable[[ty.Callable[P, R]], sauce.Magic[P, R]]:
53
- """This is the main pure.magic() decorator. It is designed to be applied directly
54
- at the site of function definition, i.e. on the `def`. We dynamically capture
55
- the fully qualified name of the function being decorated and use that to
56
- look up the appropriate 'magic' configuration at the time of each call to the function.
57
- """
58
53
  return sauce.make_magic(_get_config(), shim_or_builder, blob_root, pipeline_id, calls)
59
54
 
60
55
  @staticmethod
@@ -63,29 +58,10 @@ class _MagicApi:
63
58
  *,
64
59
  blob_root: uris.UriResolvable = "",
65
60
  pipeline_id: str = "",
66
- config_path: str = "",
67
61
  ) -> ty.Callable[[F], F]: # cleaner type for certain use cases
68
- """This alternative API is designed for more dynamic use cases - rather than
69
- decorating a function def directly, you can use this to create a more generic
70
- decorator that can be applied within other code (not at module-level).
71
-
72
- However, you must never apply pure.magic.deco to the same function from multiple
73
- places, as this means that you have multiple different uses sharing the same
74
- configuration path, which will lead to subtle bugs.
75
-
76
- We attempt to detect this and raise an error if it happens. If it does, you should
77
- provide an explicit unique config_path for each usage.
78
- """
79
62
  return ty.cast(
80
63
  ty.Callable[[F], F],
81
- sauce.make_magic(
82
- _get_config(),
83
- shim_or_builder,
84
- blob_root=blob_root,
85
- pipeline_id=pipeline_id,
86
- calls=tuple(),
87
- config_path=config_path,
88
- ),
64
+ _MagicApi.__call__(shim_or_builder, blob_root=blob_root, pipeline_id=pipeline_id),
89
65
  )
90
66
 
91
67
  @staticmethod
@@ -146,10 +122,6 @@ class _MagicApi:
146
122
  m_config.blob_root.load_config(all_config)
147
123
  m_config.pipeline_id.load_config(all_config)
148
124
 
149
- @staticmethod
150
- def config_path(func: ty.Callable) -> str:
151
- return sauce.make_magic_config_path(func)
152
-
153
125
 
154
126
  magic: ty.Final = _MagicApi()
155
127
  # we only instantiate this so we can have a call to magic() that is not __init__.
@@ -6,7 +6,7 @@ import typing as ty
6
6
 
7
7
  from typing_extensions import ParamSpec
8
8
 
9
- from thds.core import futures, log, stack_context
9
+ from thds.core import futures, stack_context
10
10
  from thds.mops._utils import config_tree
11
11
 
12
12
  from ..core import file_blob_store, pipeline_id, pipeline_id_mask, uris
@@ -38,8 +38,6 @@ class _MagicConfig:
38
38
  self.shim_bld[""] = make_builder(samethread_shim) # default Shim
39
39
  self.pipeline_id[""] = "magic" # default pipeline_id
40
40
 
41
- self.all_registered_paths: set[str] = set()
42
-
43
41
  def __repr__(self) -> str:
44
42
  return f"MagicConfig(shim_bld={self.shim_bld}, blob_root={self.blob_root}, pipeline_id={self.pipeline_id})"
45
43
 
@@ -70,17 +68,15 @@ class Magic(ty.Generic[P, R]):
70
68
  self,
71
69
  func: ty.Callable[P, R],
72
70
  config: _MagicConfig,
73
- magic_config_path: str,
74
71
  calls: ty.Collection[ty.Callable] = frozenset(),
75
72
  ):
76
73
  functools.update_wrapper(self, func)
77
- self._magic_config_path = magic_config_path
74
+ self._func_config_path = full_name_and_callable(func)[0].replace("--", ".")
78
75
 
79
76
  self.config = config
80
-
81
77
  if p_id := pipeline_id_mask.extract_from_docstr(func, require=False):
82
78
  # this allows the docstring pipeline id to become 'the most specific' config.
83
- self.config.pipeline_id.setv(p_id, self._magic_config_path)
79
+ self.config.pipeline_id.setv(p_id, self._func_config_path)
84
80
  self._shim = stack_context.StackContext[ty.Union[None, ShimName, ShimOrBuilder]](
85
81
  str(func) + "_SHIM", None # none means nothing has been set stack-local
86
82
  )
@@ -108,7 +104,7 @@ class Magic(ty.Generic[P, R]):
108
104
  def _shim_builder_or_off(self) -> ty.Optional[ShimBuilder]:
109
105
  if stack_local_shim := self._shim():
110
106
  return to_shim_builder(stack_local_shim)
111
- return self.config.shim_bld.getv(self._magic_config_path)
107
+ return self.config.shim_bld.getv(self._func_config_path)
112
108
 
113
109
  def _is_off(self) -> bool:
114
110
  return self._shim_builder_or_off is None
@@ -121,11 +117,11 @@ class Magic(ty.Generic[P, R]):
121
117
  return sb(f, args, kwargs)
122
118
 
123
119
  def _get_blob_root(self) -> str:
124
- return self.config.blob_root.getv(self._magic_config_path)()
120
+ return self.config.blob_root.getv(self._func_config_path)()
125
121
 
126
122
  @property
127
123
  def _pipeline_id(self) -> str:
128
- return self.config.pipeline_id.getv(self._magic_config_path)
124
+ return self.config.pipeline_id.getv(self._func_config_path)
129
125
 
130
126
  def submit(self, *args: P.args, **kwargs: P.kwargs) -> futures.PFuture[R]:
131
127
  """A futures-based interface that doesn't block on the result of the wrapped
@@ -142,80 +138,26 @@ class Magic(ty.Generic[P, R]):
142
138
 
143
139
  def __repr__(self) -> str:
144
140
  return (
145
- f"Magic('{self._magic_config_path}', shim={self._shim_builder_or_off},"
141
+ f"Magic('{self._func_config_path}', shim={self._shim_builder_or_off},"
146
142
  f" blob_root='{self._get_blob_root()}', pipeline_id='{self._pipeline_id}')"
147
143
  )
148
144
 
149
145
 
150
- def make_magic_config_path(func: ty.Callable) -> str:
151
- return full_name_and_callable(func)[0].replace("--", ".")
152
-
153
-
154
- class MagicReregistrationError(ValueError):
155
- pass
156
-
157
-
158
146
  def make_magic(
159
147
  config: _MagicConfig,
160
148
  shim_or_builder: ty.Union[ShimName, ShimOrBuilder, None],
161
149
  blob_root: uris.UriResolvable,
162
150
  pipeline_id: str,
163
151
  calls: ty.Collection[ty.Callable],
164
- *,
165
- config_path: str = "",
166
152
  ) -> ty.Callable[[ty.Callable[P, R]], Magic[P, R]]:
167
- """config_path is a dot-separated path that must be unique throughout your application.
168
-
169
- By default it will be set to the thds.other.module.function_name of the decorated function.
170
- """
171
- error_logger = log.auto(__name__, "thds.mops.pure._magic.api").error
172
- err_msg = (
173
- "You are probably using pure.magic(.deco) from multiple places on the same function. You will need to specify a unique config_path for each usage."
174
- if not config_path
175
- else f"You supplied a config_path ({config_path}) but you reused the decorator on different functions with the same config_path."
176
- )
177
- err_msg += " See the comment in mops.pure._magic.sauce for more details."
178
-
179
- def must_not_remagic_same_func(msg: str) -> None:
180
- error_logger(f"{msg}; {err_msg}")
181
- # if you see either of the above messages, consider whether you really need the magic
182
- # configurability of pure.magic, or whether it might be better to instantiate and use
183
- # MemoizingPicklingRunner directly without configurability. The reason overwriting
184
- # configs, by applying pure.magic to the same callable from more than one location is
185
- # disallowed is that you will get 'spooky action at a distance' between different parts
186
- # of your application that are overwriting the base config for the same function.
187
- # Another approach would be to use a wrapper `def` with a static @pure.magic decorator
188
- # on it that calls the inner function, so that they are completely different functions
189
- # as far as pure.magic is concerned.
190
- raise MagicReregistrationError(msg)
191
-
192
- magic_config_path_cache: set[str] = set()
193
- # the reason for this cache is that there are cases where you may want to apply the _exact
194
- # same_ base config to the same function multiple times - just for ease of use. And
195
- # since this is the exact same config, we should allow it and treat it as though you
196
- # had only applied it once. Of course, if you later try to configure these
197
- # applications separately, it won't work - these _are_ the same magic config path, so
198
- # they're bound together via that config.
199
-
200
153
  def deco(func: ty.Callable[P, R]) -> Magic[P, R]:
201
- fully_qualified_name = make_magic_config_path(func)
202
- magic_config_path = config_path or fully_qualified_name
203
-
204
- def deco_being_reapplied_to_same_func() -> bool:
205
- return fully_qualified_name in magic_config_path_cache
206
-
207
- if magic_config_path in config.all_registered_paths and not deco_being_reapplied_to_same_func():
208
- must_not_remagic_same_func(f"Cannot re-register {magic_config_path} using pure.magic")
209
-
154
+ fully_qualified_name = full_name_and_callable(func)[0].replace("--", ".")
210
155
  if shim_or_builder is not None:
211
- config.shim_bld[magic_config_path] = to_shim_builder(shim_or_builder)
156
+ config.shim_bld[fully_qualified_name] = to_shim_builder(shim_or_builder)
212
157
  if blob_root: # could be empty string
213
- config.blob_root[magic_config_path] = uris.to_lazy_uri(blob_root)
158
+ config.blob_root[fully_qualified_name] = uris.to_lazy_uri(blob_root)
214
159
  if pipeline_id: # could be empty string
215
- config.pipeline_id[magic_config_path] = pipeline_id
216
-
217
- magic_config_path_cache.add(fully_qualified_name)
218
- config.all_registered_paths.add(magic_config_path)
219
- return Magic(func, config, magic_config_path, calls)
160
+ config.pipeline_id[fully_qualified_name] = pipeline_id
161
+ return Magic(func, config, calls)
220
162
 
221
163
  return deco
@@ -5,7 +5,7 @@ import pickle
5
5
  import typing as ty
6
6
  from pathlib import Path
7
7
 
8
- from thds.core import config, files, log, pickle_visit, source
8
+ from thds.core import config, log, pickle_visit, source
9
9
  from thds.mops.pure.core.memo import function_memospace
10
10
  from thds.mops.pure.core.metadata import get_invoked_by
11
11
 
@@ -152,7 +152,10 @@ def log_function_execution(
152
152
  log_entry["uris_in_rvalue"] = sorted(source_uris)
153
153
 
154
154
  try:
155
- with files.atomic_text_writer(log_file) as file:
156
- json.dump(log_entry, file, indent=2)
155
+ assert not log_file.exists(), f"Log file '{log_file}' should not already exist"
156
+ with log_file.open("w") as f:
157
+ json.dump(log_entry, f, indent=2)
157
158
  except Exception:
158
- logger.exception(f"Failed to write mops function invocation log file at '{log_file}'")
159
+ logger.info(
160
+ f"Unable to write mops function invocation log file at '{log_file}' - you may have multiple callers for the same invocation"
161
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thds.mops
3
- Version: 3.9.20251023235807
3
+ Version: 3.9.20251024053258
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
@@ -2,10 +2,10 @@ thds/mops/__about__.py,sha256=IW_3wy8wEdrVducoBdiVgD7oYOY4J8yO1ezBaPtrc6U,215
2
2
  thds/mops/__init__.py,sha256=dbujDxVVfHpWP7OyfjEdNVHLtKx99rsNQPYfjTKn5Lg,127
3
3
  thds/mops/_compat.py,sha256=fO1YYEu6LF1re-VXl4P_8RXXLeKt4BgI9NTlHTgNpLk,357
4
4
  thds/mops/config.py,sha256=T62YskXvzAfxNgpq2jMatHgoIHfRV_z4cvJ8Rl_TZ6E,2015
5
- thds/mops/parallel.py,sha256=F6vUhSTO--CY82vyYtWFtspmgd0RxoxQ_EUrCnTm93Q,1039
5
+ thds/mops/parallel.py,sha256=ynzT7uEtF1sfUi7NS9fHg1I5EhQtSs3p5hNzP3xwAWE,931
6
6
  thds/mops/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  thds/mops/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- thds/mops/_utils/config_tree.py,sha256=Q9mPAAolYPqKe6dkvfetg-wmVARyD7WOx123OLQ8_sU,7326
8
+ thds/mops/_utils/config_tree.py,sha256=wMwkw81FDOo2Ld9rEmtobZMW2ZCUmxWSI2Bp_p0pwa8,7151
9
9
  thds/mops/_utils/exception.py,sha256=Itj6ceieCdGrKZ2JdW_DIM88Wgvvw104cfbH1RNn6Go,394
10
10
  thds/mops/_utils/locked_cache.py,sha256=ROIkwu-_FcXlNyCreWQeE5cyL9XrNW7drWsolTgeajM,2523
11
11
  thds/mops/_utils/names.py,sha256=tPPaXCyduUXqmbdvIg3ygevERnKM3YIs868BeaKX5XY,824
@@ -39,8 +39,8 @@ thds/mops/k8s/tools/krsync.py,sha256=us7pXX0-bRMwD2oAno7Z6BJcPs6FgaUabHW0STyQJYg
39
39
  thds/mops/k8s/tools/krsync.sh,sha256=fWgwkdzWnJeTbzEA_uBiIIi-bNU4nXAYj3dNovyRluU,747
40
40
  thds/mops/pure/__init__.py,sha256=3xLimQ2JWdeq1YgPs7bPwlwOspzPRwaR2w2KX7vfJU0,1624
41
41
  thds/mops/pure/_magic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
- thds/mops/pure/_magic/api.py,sha256=eG1NEl9FR_FE1yLfN0hiLd0uLWu-gKzw1FCIJR5pMbw,6424
43
- thds/mops/pure/_magic/sauce.py,sha256=BfzQfEnQarcLuTbKyCKLU8F6BtJ-v6kn1SRIf675cTc,9804
42
+ thds/mops/pure/_magic/api.py,sha256=kSlediIZQYsmeHB8plP6osjvUuSEVW4NWdY9ADia12Y,5094
43
+ thds/mops/pure/_magic/sauce.py,sha256=xLaseOhoGgntmz6nZdj2te85sOaOiWExBLMGdeNmKsI,6870
44
44
  thds/mops/pure/_magic/shims.py,sha256=CXN8wlHv039oKRzDtp5YFDlwGXmmaheWLCi2I95gSeM,1212
45
45
  thds/mops/pure/adls/__init__.py,sha256=fw67xxwnizBurScMa-_zWb94lo5gamEVRt27V4bR0jc,54
46
46
  thds/mops/pure/adls/_files.py,sha256=9m35Y4elWF0DjgAXVp4oi5CaY6fXWt8n67PilWxWJns,821
@@ -106,11 +106,11 @@ thds/mops/pure/tools/sha256_b64_addressed.py,sha256=SECAiw3xSqpsrBBZix0MgJRTQrbH
106
106
  thds/mops/pure/tools/stress.py,sha256=N7C8kLpaGbImeEYlT5jsEl1metvsUu8cnfyQ8vFN0H8,2541
107
107
  thds/mops/pure/tools/summarize/__init__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
108
108
  thds/mops/pure/tools/summarize/cli.py,sha256=7kDtn24ok8oBO3jFjlMmOK3jnZYpMoE_5Y8fmDH8Imc,11524
109
- thds/mops/pure/tools/summarize/run_summary.py,sha256=glEN_YxUGADzp2Ofvr4ZDeHvnZ1znNR7HD7EATn1sPI,5644
109
+ thds/mops/pure/tools/summarize/run_summary.py,sha256=w45qiQr7elrHDiK9Hgs85gtU3gwLuXa447ih1Y23BBY,5776
110
110
  thds/mops/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
111
  thds/mops/testing/deferred_imports.py,sha256=f0ezCgQAtzTqW1yAOb0OWgsB9ZrlztLB894LtpWDaVw,3780
112
- thds_mops-3.9.20251023235807.dist-info/METADATA,sha256=1TVYLso0yfYN4naRHNhwq0jYcnA2owie6zAq507TJC4,2225
113
- thds_mops-3.9.20251023235807.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
114
- thds_mops-3.9.20251023235807.dist-info/entry_points.txt,sha256=qKvCAaB80syXfxVR3xx6x9J0YJdaQWkIbVSw-NwFgMw,322
115
- thds_mops-3.9.20251023235807.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
116
- thds_mops-3.9.20251023235807.dist-info/RECORD,,
112
+ thds_mops-3.9.20251024053258.dist-info/METADATA,sha256=0-4Fp-EsLZ_3Ck6-BDmI2p0X6HzLvoL744sXsXRH5n4,2225
113
+ thds_mops-3.9.20251024053258.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
114
+ thds_mops-3.9.20251024053258.dist-info/entry_points.txt,sha256=qKvCAaB80syXfxVR3xx6x9J0YJdaQWkIbVSw-NwFgMw,322
115
+ thds_mops-3.9.20251024053258.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
116
+ thds_mops-3.9.20251024053258.dist-info/RECORD,,