thds.mops 3.9.20251029034848__py3-none-any.whl → 3.10.20251106191559__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.
@@ -51,9 +51,14 @@ class _MagicApi:
51
51
  calls: ty.Collection[ty.Callable] = tuple(),
52
52
  ) -> ty.Callable[[ty.Callable[P, R]], sauce.Magic[P, R]]:
53
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.
54
+ at the site of function definition, i.e. on the `def`. We dynamically capture the
55
+ fully qualified name of the function being decorated and use that to look up the
56
+ appropriate 'magic' configuration at the time of each call to the function. Any
57
+ configuration passed here will be entered into the global magic config registry as
58
+ the 'base case' for this function.
59
+
60
+ DO NOT use this decorator multiple times on the same function, as this will overwrite
61
+ config globally in a way that is very hard to understand.
57
62
  """
58
63
  return sauce.make_magic(_get_config(), shim_or_builder, blob_root, pipeline_id, calls)
59
64
 
@@ -75,6 +80,11 @@ class _MagicApi:
75
80
 
76
81
  We attempt to detect this and raise an error if it happens. If it does, you should
77
82
  provide an explicit unique config_path for each usage.
83
+
84
+ NOTE: In many cases, you may be better off using pure.magic.wand instead, which
85
+ will allow you to prevent any 'outside' configuration from unintentionally
86
+ affecting your function, because the explicitly-provided configuration is used but
87
+ not entered into the global 'magic' config registry.
78
88
  """
79
89
  return ty.cast(
80
90
  ty.Callable[[F], F],
@@ -88,6 +98,26 @@ class _MagicApi:
88
98
  ),
89
99
  )
90
100
 
101
+ @staticmethod
102
+ def wand(
103
+ shim_or_builder: ty.Union[ShimName, ShimOrBuilder, None] = None,
104
+ *,
105
+ blob_root: uris.UriResolvable = "",
106
+ pipeline_id: str = "",
107
+ calls: ty.Collection[ty.Callable] = tuple(),
108
+ ) -> ty.Callable[[F], F]:
109
+ """Meant for truly dynamic (i.e. runtime-controlled) use cases. This picks up
110
+ _current_ magic configuration at the time of wrapping the function, but does not allow
111
+ further magic configuration at the time of function call, and does not enter any
112
+ of the supplied configuration into the global 'magic' config registry.
113
+
114
+ Suitable for cases where you want to fall back to existing module and config-file
115
+ configuration at the time of wrapping the function for anything that you don't supply explicitly.
116
+ """
117
+ return sauce.wand(
118
+ _get_config(), shim_or_builder, blob_root=blob_root, pipeline_id=pipeline_id, calls=calls
119
+ )
120
+
91
121
  @staticmethod
92
122
  def blob_root(
93
123
  blob_root_uri: uris.UriResolvable, pathable: config_tree.Pathable = None, *, mask: bool = False
@@ -9,7 +9,7 @@ from typing_extensions import ParamSpec
9
9
  from thds.core import futures, log, stack_context
10
10
  from thds.mops._utils import config_tree
11
11
 
12
- from ..core import file_blob_store, pipeline_id, pipeline_id_mask, uris
12
+ from .. import core
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
@@ -18,7 +18,7 @@ from ..runner.simple_shims import samethread_shim
18
18
  from ..runner.types import Shim, ShimBuilder
19
19
  from .shims import ShimName, ShimOrBuilder, to_shim_builder
20
20
 
21
- _local_root = lambda: f"file://{file_blob_store.MOPS_ROOT()}" # noqa: E731
21
+ _local_root = lambda: f"file://{core.file_blob_store.MOPS_ROOT()}" # noqa: E731
22
22
  P = ParamSpec("P")
23
23
  R = ty.TypeVar("R")
24
24
 
@@ -31,7 +31,7 @@ class _MagicConfig:
31
31
  "mops.pure.magic.shim", parse=to_shim_builder # type: ignore
32
32
  )
33
33
  self.blob_root = config_tree.ConfigTree[ty.Callable[[], str]](
34
- "mops.pure.magic.blob_root", parse=uris.to_lazy_uri
34
+ "mops.pure.magic.blob_root", parse=core.uris.to_lazy_uri
35
35
  )
36
36
  self.pipeline_id = config_tree.ConfigTree[str]("mops.pure.magic.pipeline_id")
37
37
  self.blob_root[""] = _local_root # default Blob Store
@@ -78,7 +78,7 @@ class Magic(ty.Generic[P, R]):
78
78
 
79
79
  self.config = config
80
80
 
81
- if p_id := pipeline_id_mask.extract_from_docstr(func, require=False):
81
+ if p_id := core.pipeline_id_mask.extract_from_docstr(func, require=False):
82
82
  # this allows the docstring pipeline id to become 'the most specific' config.
83
83
  self.config.pipeline_id.setv(p_id, self._magic_config_path)
84
84
  self._shim = stack_context.StackContext[ty.Union[None, ShimName, ShimOrBuilder]](
@@ -132,12 +132,12 @@ class Magic(ty.Generic[P, R]):
132
132
  function call, but returns a PFuture once either a result has been found or a a
133
133
  new invocation has been started.
134
134
  """
135
- with pipeline_id.set_pipeline_id_for_stack(self._pipeline_id):
135
+ with core.pipeline_id.set_pipeline_id_for_stack(self._pipeline_id):
136
136
  return self.runner.submit(self.__wrapped__, *args, **kwargs)
137
137
 
138
138
  def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
139
139
  """This is the wrapped function - call this as though it were the function itself."""
140
- with pipeline_id.set_pipeline_id_for_stack(self._pipeline_id):
140
+ with core.pipeline_id.set_pipeline_id_for_stack(self._pipeline_id):
141
141
  return self._func(*args, **kwargs)
142
142
 
143
143
  def __repr__(self) -> str:
@@ -158,7 +158,7 @@ class MagicReregistrationError(ValueError):
158
158
  def make_magic(
159
159
  config: _MagicConfig,
160
160
  shim_or_builder: ty.Union[ShimName, ShimOrBuilder, None],
161
- blob_root: uris.UriResolvable,
161
+ blob_root: core.uris.UriResolvable,
162
162
  pipeline_id: str,
163
163
  calls: ty.Collection[ty.Callable],
164
164
  *,
@@ -210,7 +210,7 @@ def make_magic(
210
210
  if shim_or_builder is not None:
211
211
  config.shim_bld[magic_config_path] = to_shim_builder(shim_or_builder)
212
212
  if blob_root: # could be empty string
213
- config.blob_root[magic_config_path] = uris.to_lazy_uri(blob_root)
213
+ config.blob_root[magic_config_path] = core.uris.to_lazy_uri(blob_root)
214
214
  if pipeline_id: # could be empty string
215
215
  config.pipeline_id[magic_config_path] = pipeline_id
216
216
 
@@ -219,3 +219,44 @@ def make_magic(
219
219
  return Magic(func, config, magic_config_path, calls)
220
220
 
221
221
  return deco
222
+
223
+
224
+ F = ty.TypeVar("F", bound=ty.Callable)
225
+
226
+
227
+ def wand(
228
+ config: _MagicConfig,
229
+ shim_or_builder: ty.Union[ShimName, ShimOrBuilder, None] = None,
230
+ # None means 'pull from config' - 'off' means off.
231
+ *,
232
+ blob_root: core.uris.UriResolvable = "",
233
+ pipeline_id: str = "",
234
+ calls: ty.Collection[ty.Callable] = tuple(),
235
+ ) -> ty.Callable[[F], F]:
236
+ """A higher-order function factory that prefers your arguments but falls back to magic
237
+ config at the time of wrapping the function.
238
+
239
+ You are creating a magic wand, not doing magic. In fact, the wand doesn't actually use
240
+ Magic at all - it resolves things from config as soon as the function is _wrapped_,
241
+ not at the time of function call.
242
+ """
243
+
244
+ def deco_that_resolves_and_locks_in_config(func: F) -> F:
245
+ magic_config_path = make_magic_config_path(func)
246
+ shim_builder = (
247
+ to_shim_builder(shim_or_builder)
248
+ if shim_or_builder
249
+ else config.shim_bld.getv(magic_config_path)
250
+ )
251
+ if not shim_builder: # this means 'off'
252
+ return func # just run the function normally
253
+
254
+ blob_root_uri = (
255
+ core.uris.to_lazy_uri(blob_root) if blob_root else config.blob_root.getv(magic_config_path)()
256
+ )
257
+
258
+ return core.pipeline_id.set_pipeline_id_for_stack(
259
+ pipeline_id or config.pipeline_id.getv(magic_config_path)
260
+ )(use_runner(MemoizingPicklingRunner(shim_builder, blob_root_uri).calls(func, *calls))(func))
261
+
262
+ return deco_that_resolves_and_locks_in_config
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thds.mops
3
- Version: 3.9.20251029034848
3
+ Version: 3.10.20251106191559
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
@@ -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=f2lF7_0XzRleYWksD3uxxl_dssl0wW_CLGHIY1WZLUM,8019
43
+ thds/mops/pure/_magic/sauce.py,sha256=lMZ4StInNH7vn1t96Ajo4KKCE99ebw0orGRatMqWrKM,11331
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
@@ -109,8 +109,8 @@ thds/mops/pure/tools/summarize/cli.py,sha256=7kDtn24ok8oBO3jFjlMmOK3jnZYpMoE_5Y8
109
109
  thds/mops/pure/tools/summarize/run_summary.py,sha256=glEN_YxUGADzp2Ofvr4ZDeHvnZ1znNR7HD7EATn1sPI,5644
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.20251029034848.dist-info/METADATA,sha256=IEHnqNgaNRJYpo-vWxapPQ6cmLixZ5KsXAwbDG8npsg,2225
113
- thds_mops-3.9.20251029034848.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
114
- thds_mops-3.9.20251029034848.dist-info/entry_points.txt,sha256=qKvCAaB80syXfxVR3xx6x9J0YJdaQWkIbVSw-NwFgMw,322
115
- thds_mops-3.9.20251029034848.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
116
- thds_mops-3.9.20251029034848.dist-info/RECORD,,
112
+ thds_mops-3.10.20251106191559.dist-info/METADATA,sha256=BX_qLAaa6x7Oa20s9H3iEzraK5YKy111k_kcBuiAF6g,2226
113
+ thds_mops-3.10.20251106191559.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
114
+ thds_mops-3.10.20251106191559.dist-info/entry_points.txt,sha256=qKvCAaB80syXfxVR3xx6x9J0YJdaQWkIbVSw-NwFgMw,322
115
+ thds_mops-3.10.20251106191559.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
116
+ thds_mops-3.10.20251106191559.dist-info/RECORD,,