fred-oss 0.43.0__tar.gz → 0.45.0__tar.gz

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.
Files changed (93) hide show
  1. {fred_oss-0.43.0/src/main/fred_oss.egg-info → fred_oss-0.45.0}/PKG-INFO +1 -1
  2. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/impl.py +108 -3
  3. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/result.py +32 -7
  4. fred_oss-0.45.0/src/main/fred/version +1 -0
  5. {fred_oss-0.43.0 → fred_oss-0.45.0/src/main/fred_oss.egg-info}/PKG-INFO +1 -1
  6. fred_oss-0.43.0/src/main/fred/version +0 -1
  7. {fred_oss-0.43.0 → fred_oss-0.45.0}/MANIFEST.in +0 -0
  8. {fred_oss-0.43.0 → fred_oss-0.45.0}/NOTICE.txt +0 -0
  9. {fred_oss-0.43.0 → fred_oss-0.45.0}/README.md +0 -0
  10. {fred_oss-0.43.0 → fred_oss-0.45.0}/requirements.txt +0 -0
  11. {fred_oss-0.43.0 → fred_oss-0.45.0}/setup.cfg +0 -0
  12. {fred_oss-0.43.0 → fred_oss-0.45.0}/setup.py +0 -0
  13. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/cli/__init__.py +0 -0
  14. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/cli/__main__.py +0 -0
  15. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/cli/interface.py +0 -0
  16. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/cli/main.py +0 -0
  17. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/__init__.py +0 -0
  18. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/comp/__init__.py +0 -0
  19. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/comp/_keyval.py +0 -0
  20. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/comp/_pubsub.py +0 -0
  21. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/comp/_queue.py +0 -0
  22. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/comp/catalog.py +0 -0
  23. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/comp/interface.py +0 -0
  24. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/service/__init__.py +0 -0
  25. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/service/_redis.py +0 -0
  26. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/service/_stdlib.py +0 -0
  27. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/service/catalog.py +0 -0
  28. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/service/interface.py +0 -0
  29. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/dao/service/utils.py +0 -0
  30. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/__init__.py +0 -0
  31. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/callback/__init__.py +0 -0
  32. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/callback/_function.py +0 -0
  33. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/callback/catalog.py +0 -0
  34. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/callback/interface.py +0 -0
  35. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/settings.py +0 -0
  36. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/future/utils.py +0 -0
  37. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/databricks/__init__.py +0 -0
  38. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/databricks/cli_ext.py +0 -0
  39. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/databricks/runtime.py +0 -0
  40. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/databricks/runtimes/__init__.py +0 -0
  41. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/databricks/runtimes/scanner.py +0 -0
  42. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/databricks/runtimes/sync.py +0 -0
  43. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/databricks/wrappers/__init__.py +0 -0
  44. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/databricks/wrappers/dbutils.py +0 -0
  45. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/runpod/__init__.py +0 -0
  46. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/runpod/cli_ext.py +0 -0
  47. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/integrations/runpod/helper.py +0 -0
  48. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/maturity.py +0 -0
  49. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/monad/__init__.py +0 -0
  50. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/monad/_either.py +0 -0
  51. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/monad/catalog.py +0 -0
  52. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/monad/interface.py +0 -0
  53. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/settings.py +0 -0
  54. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/utils/__init__.py +0 -0
  55. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/utils/dateops.py +0 -0
  56. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/utils/runtime.py +0 -0
  57. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/version.py +0 -0
  58. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/__init__.py +0 -0
  59. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/interface.py +0 -0
  60. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/__init__.py +0 -0
  61. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/backend.py +0 -0
  62. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/client.py +0 -0
  63. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/handler.py +0 -0
  64. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/model/__init__.py +0 -0
  65. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/model/_handler.py +0 -0
  66. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/model/_item.py +0 -0
  67. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/model/_request.py +0 -0
  68. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/model/_runner_spec.py +0 -0
  69. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/model/catalog.py +0 -0
  70. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/model/interface.py +0 -0
  71. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/plugins/__init__.py +0 -0
  72. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/plugins/_local.py +0 -0
  73. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/plugins/_runpod.py +0 -0
  74. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/plugins/catalog.py +0 -0
  75. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/plugins/interface.py +0 -0
  76. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/__init__.py +0 -0
  77. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/auth.py +0 -0
  78. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/cli_ext.py +0 -0
  79. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/routers/__init__.py +0 -0
  80. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/routers/_runner.py +0 -0
  81. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/routers/catalog.py +0 -0
  82. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/routers/interface.py +0 -0
  83. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/server.py +0 -0
  84. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/rest/settings.py +0 -0
  85. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/settings.py +0 -0
  86. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/signal.py +0 -0
  87. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/status.py +0 -0
  88. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred/worker/runner/utils.py +0 -0
  89. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred_oss.egg-info/SOURCES.txt +0 -0
  90. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred_oss.egg-info/dependency_links.txt +0 -0
  91. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred_oss.egg-info/entry_points.txt +0 -0
  92. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred_oss.egg-info/requires.txt +0 -0
  93. {fred_oss-0.43.0 → fred_oss-0.45.0}/src/main/fred_oss.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fred-oss
3
- Version: 0.43.0
3
+ Version: 0.45.0
4
4
  Summary: FREDOSS
5
5
  Home-page: https://fred.fahera.mx
6
6
  Author: Fahera Research, Education, and Development
@@ -1,3 +1,4 @@
1
+ import time
1
2
  from threading import Thread
2
3
  from typing import (
3
4
  Callable,
@@ -63,6 +64,7 @@ class Future(MonadInterface[A]):
63
64
  on_start: Optional[CallbackInterface] = None,
64
65
  on_complete: Optional[CallbackInterface] = None,
65
66
  parent_id: Optional[str] = None,
67
+ broadcast: bool = False,
66
68
  **kwargs
67
69
  ):
68
70
  """Initializes a Future with the provided function to be executed asynchronously.
@@ -77,7 +79,11 @@ class Future(MonadInterface[A]):
77
79
  All keyword arguments except 'future_id' are forwarded to the target function.
78
80
  """
79
81
  # Create a new available future
80
- future = FutureUndefinedPending.auto(parent_id=parent_id, future_id=kwargs.pop("future_id", None))
82
+ future = FutureUndefinedPending.auto(
83
+ parent_id=parent_id,
84
+ broadcast=broadcast,
85
+ future_id=kwargs.pop("future_id", None),
86
+ )
81
87
  # Register the Future-ID and define the available future via the provided function.
82
88
  # Note: The 'apply' method is blocking by itself; thus, we run it in a separate thread.
83
89
  # Note: The thread is a daemon to ensure it does not block program exit.
@@ -199,8 +205,22 @@ class Future(MonadInterface[A]):
199
205
  return self.wait(timeout=timeout).resolve()
200
206
 
201
207
  @classmethod
202
- def from_value(cls, val: A) -> 'Future[A]':
203
- return Future(function=lambda: val)
208
+ def from_value(cls, val: A, **kwargs) -> 'Future[A]':
209
+ """
210
+ Creates a Future that is immediately resolved with the given value.
211
+
212
+ Args:
213
+ val (A): The value to resolve the Future with.
214
+ **kwargs: Additional keyword arguments forwarded to the Future constructor.
215
+ These may include parameters such as:
216
+ - parent_id (Optional[str]): The parent future's ID.
217
+ - expiration (Optional[float]): Expiration time for the future.
218
+ - callback (Optional[CallbackInterface]): Callback to invoke on completion.
219
+ For a full list of accepted parameters, see the Future class documentation.
220
+ Returns:
221
+ Future[A]: A Future instance resolved with the provided value.
222
+ """
223
+ return Future(function=lambda: val, **kwargs)
204
224
 
205
225
  def flat_map(self, function: Callable[[A], 'Future[B]'], timeout: Optional[float] = None) -> 'Future[B]':
206
226
  """Chains the current future with another future-producing function.
@@ -276,6 +296,10 @@ class Future(MonadInterface[A]):
276
296
  Returns:
277
297
  Future[A]: A Future instance representing the pulled future.
278
298
  """
299
+ logger.warning(
300
+ "The 'pullsync' method is scheduled for deprecation and will be removed in future versions. "
301
+ "Please use the 'subscribe' method instead that uses a pubsub mechanism."
302
+ )
279
303
  from fred.future.utils import pull_future_result
280
304
 
281
305
  return cls(
@@ -289,6 +313,87 @@ class Future(MonadInterface[A]):
289
313
  on_complete=on_complete,
290
314
  **kwargs
291
315
  )
316
+
317
+ @classmethod
318
+ def subscribe(
319
+ cls,
320
+ future_id: str,
321
+ on_start: Optional[CallbackInterface] = None,
322
+ on_complete: Optional[CallbackInterface] = None,
323
+ retry_delay: float = 0.2,
324
+ retry: int = 3,
325
+ ) -> 'Future[A]':
326
+ """Subscribes to updates for an existing future using a publish-subscribe mechanism.
327
+ This method allows for receiving real-time updates about the future's state
328
+ and result without blocking.
329
+ Args:
330
+ future_id (str): The unique identifier of the future to subscribe to.
331
+ on_start (Optional[CallbackInterface]): An optional callback to be executed
332
+ when the subscription starts.
333
+ on_complete (Optional[CallbackInterface]): An optional callback to be executed
334
+ when the future completes.
335
+ Returns:
336
+ Future[A]: A Future instance that will execute the subscription logic.
337
+ """
338
+ # TODO: Consider adding a timeout parameter to avoid waiting indefinitely...
339
+ # TODO: There's a known issue where if the future completes before we subscribe,
340
+ # we might miss the completion message.
341
+ # Define a closure that will handle incoming messages from the pub-sub channel
342
+ def closure():
343
+ for payload in FutureResult._get_bcast_channel(future_id=future_id).subscribe():
344
+ logger.info(f"Received pubsub message for future '{future_id}': {payload}")
345
+ if payload.get("type") != "message":
346
+ continue
347
+ message = payload.get("data")
348
+ if not message:
349
+ continue
350
+ match FutureResult.from_string(message):
351
+ case FutureDefined(value=value):
352
+ return value.resolve()
353
+ case FutureUndefinedPending():
354
+ continue
355
+ case FutureUndefinedInProgress():
356
+ continue
357
+ case _:
358
+ raise TypeError("Unknown FutureResult type")
359
+ shared_params = {
360
+ "parent_id": future_id,
361
+ "broadcast": False,
362
+ "on_start": on_start,
363
+ "on_complete": on_complete,
364
+ }
365
+ # Depending on the current state of the future, either return the resolved value
366
+ # or subscribe to the broadcast channel to wait for updates (via closure).
367
+ match FutureResult.from_backend(future_id=future_id):
368
+ case FutureDefined(value=value):
369
+ return cls(
370
+ function=lambda: value.resolve(),
371
+ **shared_params
372
+ )
373
+ case instance:
374
+ # The future-result can be None if the future_id does not exist
375
+ if not instance:
376
+ if retry <= 0:
377
+ raise ValueError(f"Future with ID '{future_id}' does not exist.")
378
+ logger.error(f"Future with ID '{future_id}' does not exist; attempting to retry ({retry} retries left).")
379
+ time.sleep(retry_delay)
380
+ return cls.subscribe(
381
+ future_id=future_id,
382
+ on_start=on_start,
383
+ on_complete=on_complete,
384
+ retry_delay=retry_delay,
385
+ retry=max(0, retry - 1),
386
+ )
387
+ # If the future exists, but is not configured for broadcast, raise an error...
388
+ if not instance.broadcast:
389
+ raise ValueError("Future is not configured for broadcast; cannot subscribe.")
390
+ # If the future exists and is configured for broadcast, subscribe to updates...
391
+ logger.info(f"Subscribing to future '{future_id}' via broadcast channel.")
392
+ return cls(
393
+ function=closure,
394
+ **shared_params
395
+ )
396
+
292
397
  def lineage(self) -> list[str]:
293
398
  """Retrieves the lineage of the future, tracing back through its parent futures.
294
399
  This method is useful for debugging and understanding the sequence of computations
@@ -20,7 +20,7 @@ from fred.future.settings import (
20
20
  from fred.future.callback.interface import CallbackInterface
21
21
  from fred.dao.service.catalog import ServiceCatalog
22
22
  from fred.utils.dateops import datetime_utcnow
23
- from fred.dao.comp.catalog import FredKeyVal
23
+ from fred.dao.comp.catalog import FredKeyVal, FredQueue, FredPubSub
24
24
  from fred.monad.catalog import EitherMonad
25
25
 
26
26
  logger = logger_manager.get_logger(__name__)
@@ -30,6 +30,8 @@ A = TypeVar("A")
30
30
 
31
31
  class FutureBackend:
32
32
  keyval: type[FredKeyVal]
33
+ queue: type[FredQueue]
34
+ pubsub: type[FredPubSub]
33
35
 
34
36
  @classmethod
35
37
  def with_backend(cls, service: ServiceCatalog, **kwargs) -> type['FutureBackend']:
@@ -47,7 +49,9 @@ class FutureBackend:
47
49
  f"{service.name.title()}{cls.__name__}",
48
50
  (cls,),
49
51
  {
50
- "keyval": components.KEYVAL.value
52
+ "keyval": components.KEYVAL.value,
53
+ "queue": components.QUEUE.value,
54
+ "pubsub": components.PUBSUB.value,
51
55
  },
52
56
  )
53
57
 
@@ -80,6 +84,7 @@ class FutureResult(Generic[A], FutureBackend.infer_backend()):
80
84
  retrieval and management of asynchronous tasks."""
81
85
  future_id: str
82
86
  parent_id: Optional[str]
87
+ broadcast: bool
83
88
 
84
89
  @staticmethod
85
90
  def _get_future_keyname(future_id: str) -> str:
@@ -89,6 +94,20 @@ class FutureResult(Generic[A], FutureBackend.infer_backend()):
89
94
  def future_keyname(self) -> str:
90
95
  return self._get_future_keyname(future_id=self.future_id)
91
96
 
97
+ @classmethod
98
+ def _get_bcast_channel(cls, future_id: str) -> FredPubSub:
99
+ return cls.pubsub(name=":".join([cls._get_future_keyname(future_id=future_id), "bcast"]))
100
+
101
+ @property
102
+ def bcast_channel(self) -> FredPubSub:
103
+ return self._get_bcast_channel(future_id=self.future_id)
104
+
105
+ def bcast_now(self, item: Optional[str] = None, ignore_flag: bool = False) -> bool:
106
+ if ignore_flag or self.broadcast:
107
+ self.bcast_channel.publish(item=item or self.stringify())
108
+ return True
109
+ return False
110
+
92
111
  @classmethod
93
112
  def _get_status_key(cls, future_id: str) -> FredKeyVal:
94
113
  return cls.keyval(key=":".join([cls._get_future_keyname(future_id=future_id), "status"]))
@@ -132,7 +151,7 @@ class FutureResult(Generic[A], FutureBackend.infer_backend()):
132
151
 
133
152
  @classmethod
134
153
  def from_backend(cls, future_id: str) -> Optional['FutureResult[A]']:
135
- return FutureResult(future_id=future_id, parent_id=None)._from_backend()
154
+ return FutureResult(future_id=future_id, parent_id=None, broadcast=False)._from_backend()
136
155
 
137
156
  @property
138
157
  def _pre(self) -> Optional['FutureResult']:
@@ -169,7 +188,8 @@ class FutureUndefinedPending(FutureResult[A]):
169
188
  import uuid
170
189
  parent_id = kwargs.pop("parent_id", None)
171
190
  future_id = kwargs.pop("future_id", None) or str(uuid.uuid4())
172
- return FutureUndefinedPending[A](future_id=future_id, parent_id=parent_id, **kwargs)
191
+ broadcast = kwargs.pop("broadcast", False)
192
+ return FutureUndefinedPending[A](future_id=future_id, parent_id=parent_id, broadcast=broadcast, **kwargs)
173
193
 
174
194
  def __post_init__(self):
175
195
  logger.debug(f"Future[{self.future_id}] initialized and pending execution")
@@ -178,9 +198,10 @@ class FutureUndefinedPending(FutureResult[A]):
178
198
  expire=FRD_FUTURE_DEFAULT_EXPIRATION
179
199
  )
180
200
  self.obj.set(
181
- value=self.stringify(),
201
+ value=(obj_payload := self.stringify()),
182
202
  expire=FRD_FUTURE_DEFAULT_EXPIRATION
183
203
  )
204
+ self.bcast_now(item=obj_payload, ignore_flag=False)
184
205
 
185
206
  def apply(
186
207
  self,
@@ -203,6 +224,7 @@ class FutureUndefinedPending(FutureResult[A]):
203
224
  fip = FutureUndefinedInProgress[A](
204
225
  future_id=self.future_id,
205
226
  parent_id=self.parent_id,
227
+ broadcast=self.broadcast,
206
228
  started_at=perf_counter(),
207
229
  function_name=function.__name__,
208
230
  )
@@ -227,9 +249,10 @@ class FutureUndefinedInProgress(FutureResult[A]):
227
249
  expire=FRD_FUTURE_DEFAULT_EXPIRATION
228
250
  )
229
251
  self.obj.set(
230
- value=self.stringify(),
252
+ value=(obj_payload := self.stringify()),
231
253
  expire=FRD_FUTURE_DEFAULT_EXPIRATION
232
254
  )
255
+ self.bcast_now(item=obj_payload, ignore_flag=False)
233
256
 
234
257
  def exec(
235
258
  self,
@@ -278,6 +301,7 @@ class FutureUndefinedInProgress(FutureResult[A]):
278
301
  future_defined = FutureDefined(
279
302
  future_id=self.future_id,
280
303
  parent_id=self.parent_id,
304
+ broadcast=self.broadcast,
281
305
  value=value,
282
306
  ok=ok,
283
307
  )
@@ -308,9 +332,10 @@ class FutureDefined(FutureResult[A]):
308
332
  expire=FRD_FUTURE_DEFAULT_EXPIRATION
309
333
  )
310
334
  self.obj.set(
311
- value=self.stringify(),
335
+ value=(obj_payload := self.stringify()),
312
336
  expire=FRD_FUTURE_DEFAULT_EXPIRATION
313
337
  )
338
+ self.bcast_now(item=obj_payload, ignore_flag=False)
314
339
  match self.value:
315
340
  case EitherMonad.Right(value=value):
316
341
  # TODO: Consider using a more robust serialization method...
@@ -0,0 +1 @@
1
+ 0.45.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fred-oss
3
- Version: 0.43.0
3
+ Version: 0.45.0
4
4
  Summary: FREDOSS
5
5
  Home-page: https://fred.fahera.mx
6
6
  Author: Fahera Research, Education, and Development
@@ -1 +0,0 @@
1
- 0.43.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes