prediction-market-agent-tooling 0.56.0.dev1859__py3-none-any.whl → 0.56.0.dev1861__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.
@@ -49,8 +49,7 @@ def db_cache(
49
49
  api_keys: APIKeys | None = None,
50
50
  ignore_args: Sequence[str] | None = None,
51
51
  ignore_arg_types: Sequence[type] | None = None,
52
- ) -> Callable[[FunctionT], FunctionT]:
53
- ...
52
+ ) -> Callable[[FunctionT], FunctionT]: ...
54
53
 
55
54
 
56
55
  @overload
@@ -62,8 +61,7 @@ def db_cache(
62
61
  api_keys: APIKeys | None = None,
63
62
  ignore_args: Sequence[str] | None = None,
64
63
  ignore_arg_types: Sequence[type] | None = None,
65
- ) -> FunctionT:
66
- ...
64
+ ) -> FunctionT: ...
67
65
 
68
66
 
69
67
  def db_cache(
@@ -114,6 +112,7 @@ def db_cache(
114
112
 
115
113
  @wraps(func)
116
114
  def wrapper(*args: Any, **kwargs: Any) -> Any:
115
+ # If caching is disabled, just call the function and return it
117
116
  if not api_keys.ENABLE_CACHE:
118
117
  return func(*args, **kwargs)
119
118
 
@@ -183,11 +182,15 @@ def db_cache(
183
182
 
184
183
  if cached_result:
185
184
  logger.info(
186
- f"Cache hit for {full_function_name} with args {args_dict} and output {cached_result.result}"
185
+ # Keep the special [case-hit] identifier so we can easily track it in GCP.
186
+ f"[cache-hit] Cache hit for {full_function_name} with args {args_dict} and output {cached_result.result}"
187
187
  )
188
188
  if is_pydantic_model:
189
+ # If the output contains any Pydantic models, we need to initialise them.
189
190
  try:
190
- return convert_to_pydantic(return_type, cached_result.result)
191
+ return convert_cached_output_to_pydantic(
192
+ return_type, cached_result.result
193
+ )
191
194
  except ValueError as e:
192
195
  # In case of backward-incompatible pydantic model, just treat it as cache miss, to not error out.
193
196
  logger.warning(
@@ -199,13 +202,14 @@ def db_cache(
199
202
 
200
203
  # On cache miss, compute the result
201
204
  computed_result = func(*args, **kwargs)
205
+ # Keep the special [case-miss] identifier so we can easily track it in GCP.
202
206
  logger.info(
203
- f"Cache miss for {full_function_name} with args {args_dict}, computed the output {computed_result}"
207
+ f"[cache-miss] Cache miss for {full_function_name} with args {args_dict}, computed the output {computed_result}"
204
208
  )
205
209
 
206
- # If postgres access was specified, save it to dB.
210
+ # If postgres access was specified, save it.
207
211
  if engine is not None and (cache_none or computed_result is not None):
208
- # Call the original function
212
+ # In case of Pydantic outputs, we need to dictionarize it for it to be serializable.
209
213
  result_data = (
210
214
  convert_pydantic_to_dict(computed_result)
211
215
  if is_pydantic_model
@@ -229,18 +233,25 @@ def db_cache(
229
233
  return cast(FunctionT, wrapper)
230
234
 
231
235
 
232
- def contains_pydantic_model(tp: Any) -> bool:
233
- if tp is None:
236
+ def contains_pydantic_model(return_type: Any) -> bool:
237
+ """
238
+ Check if the return type contains anything that's a Pydantic model (including nested structures, like `list[BaseModel]`, `dict[str, list[BaseModel]]`, etc.)
239
+ """
240
+ if return_type is None:
234
241
  return False
235
- origin = get_origin(tp)
242
+ origin = get_origin(return_type)
236
243
  if origin is not None:
237
- return any(contains_pydantic_model(arg) for arg in get_args(tp))
238
- if inspect.isclass(tp):
239
- return issubclass(tp, BaseModel)
244
+ return any(contains_pydantic_model(arg) for arg in get_args(return_type))
245
+ if inspect.isclass(return_type):
246
+ return issubclass(return_type, BaseModel)
240
247
  return False
241
248
 
242
249
 
243
- def json_serializer_default_fn(y: Any) -> Any:
250
+ def json_serializer_default_fn(y: DatetimeUTC | timedelta | date) -> str:
251
+ """
252
+ Used to serialize objects that don't support it by default into a specific string that can be deserialized out later.
253
+ If you add something here, also add it to `replace_custom_stringified_objects` below.
254
+ """
244
255
  if isinstance(y, DatetimeUTC):
245
256
  return f"DatetimeUTC::{y.isoformat()}"
246
257
  elif isinstance(y, timedelta):
@@ -257,6 +268,9 @@ def json_serializer(x: Any) -> str:
257
268
 
258
269
 
259
270
  def replace_custom_stringified_objects(obj: Any) -> Any:
271
+ """
272
+ Used to deserialize objects from `json_serializer_default_fn` into their proper form.
273
+ """
260
274
  if isinstance(obj, str):
261
275
  if obj.startswith("DatetimeUTC::"):
262
276
  iso_str = obj[len("DatetimeUTC::") :]
@@ -283,6 +297,9 @@ def json_deserializer(s: str) -> Any:
283
297
 
284
298
 
285
299
  def convert_pydantic_to_dict(value: Any) -> Any:
300
+ """
301
+ Convert Pydantic models to dictionaries, including if they are in nested structures.
302
+ """
286
303
  if isinstance(value, BaseModel):
287
304
  return value.model_dump()
288
305
  elif isinstance(value, dict):
@@ -295,20 +312,25 @@ def convert_pydantic_to_dict(value: Any) -> Any:
295
312
  return value
296
313
 
297
314
 
298
- def convert_to_pydantic(model: Any, data: Any) -> Any:
315
+ def convert_cached_output_to_pydantic(return_type: Any, data: Any) -> Any:
316
+ """
317
+ Used to initialize Pydantic models from anything cached that was originally a Pydantic model in the output. Including models in nested structures.
318
+ """
299
319
  # Get the origin and arguments of the model type
300
- origin = get_origin(model)
301
- args = get_args(model)
320
+ origin = get_origin(return_type)
321
+ args = get_args(return_type)
302
322
 
303
323
  # Check if the data is a dictionary
304
324
  if isinstance(data, dict):
305
325
  # If the model has no origin, check if it is a subclass of BaseModel
306
326
  if origin is None:
307
- if inspect.isclass(model) and issubclass(model, BaseModel):
327
+ if inspect.isclass(return_type) and issubclass(return_type, BaseModel):
308
328
  # Convert the dictionary to a Pydantic model
309
- return model(
329
+ return return_type(
310
330
  **{
311
- k: convert_to_pydantic(getattr(model, k, None), v)
331
+ k: convert_cached_output_to_pydantic(
332
+ getattr(return_type, k, None), v
333
+ )
312
334
  for k, v in data.items()
313
335
  }
314
336
  )
@@ -319,20 +341,25 @@ def convert_to_pydantic(model: Any, data: Any) -> Any:
319
341
  elif origin is dict:
320
342
  key_type, value_type = args
321
343
  return {
322
- convert_to_pydantic(key_type, k): convert_to_pydantic(value_type, v)
344
+ convert_cached_output_to_pydantic(
345
+ key_type, k
346
+ ): convert_cached_output_to_pydantic(value_type, v)
323
347
  for k, v in data.items()
324
348
  }
325
349
  else:
326
350
  # If the origin is not a dictionary, return the data as is
327
351
  return data
328
352
  # Check if the data is a list
329
- elif isinstance(data, list):
330
- # If the origin is a list, convert each item
331
- if origin is list:
353
+ elif isinstance(data, (list, tuple)):
354
+ # If the origin is a list or tuple, convert each item
355
+ if origin in {list, tuple}:
332
356
  item_type = args[0]
333
- return [convert_to_pydantic(item_type, item) for item in data]
357
+ converted_items = [
358
+ convert_cached_output_to_pydantic(item_type, item) for item in data
359
+ ]
360
+ return type(data)(converted_items)
334
361
  else:
335
- # If the origin is not a list, return the data as is
362
+ # If the origin is not a list or tuple, return the data as is
336
363
  return data
337
364
  else:
338
365
  # If the data is neither a dictionary nor a list, return it as is
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.56.0.dev1859
3
+ Version: 0.56.0.dev1861
4
4
  Summary: Tools to benchmark, deploy and monitor prediction market agents.
5
5
  Author: Gnosis
6
6
  Requires-Python: >=3.10,<3.12
@@ -69,7 +69,7 @@ prediction_market_agent_tooling/tools/betting_strategies/market_moving.py,sha256
69
69
  prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py,sha256=-FUSuQQgjcWSSnoFxnlAyTeilY6raJABJVM2QKkFqAY,438
70
70
  prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py,sha256=THMXwFlskvzbjnX_OiYtDSzI8XVFyULWfP2525_9UGc,429
71
71
  prediction_market_agent_tooling/tools/betting_strategies/utils.py,sha256=kpIb-ci67Vc1Yqqaa-_S4OUkbhWSIYog4_Iwp69HU_k,97
72
- prediction_market_agent_tooling/tools/caches/db_cache.py,sha256=2a1bIDQk1KmVcp6cR8nSDKyT7rWnBQ7oqmqLjw49sps,12196
72
+ prediction_market_agent_tooling/tools/caches/db_cache.py,sha256=AEU-DQ19sS3ZZJKljM9ydRoa07duFhTTzG-vadYRsJg,13851
73
73
  prediction_market_agent_tooling/tools/caches/inmemory_cache.py,sha256=tGHHd9HCiE_hCCtPtloHZQdDfBuiow9YsqJNYi2Tx_0,499
74
74
  prediction_market_agent_tooling/tools/contract.py,sha256=s3yo8IbXTcvAJcPfLM0_NbgaEsWwLsPmyVnOgyjq_xI,20919
75
75
  prediction_market_agent_tooling/tools/costs.py,sha256=EaAJ7v9laD4VEV3d8B44M4u3_oEO_H16jRVCdoZ93Uw,954
@@ -97,8 +97,8 @@ prediction_market_agent_tooling/tools/tavily/tavily_models.py,sha256=5ldQs1pZe6u
97
97
  prediction_market_agent_tooling/tools/tavily/tavily_search.py,sha256=Kw2mXNkMTYTEe1MBSTqhQmLoeXtgb6CkmHlcAJvhtqE,3809
98
98
  prediction_market_agent_tooling/tools/utils.py,sha256=W-9SqeCKd51BYMRhDjYPQ7lfNO_zE9EvYpmu2r5WXGA,7163
99
99
  prediction_market_agent_tooling/tools/web3_utils.py,sha256=44W8siSLNQxeib98bbwAe7V5C609NHNlUuxwuWIRDiY,11838
100
- prediction_market_agent_tooling-0.56.0.dev1859.dist-info/LICENSE,sha256=6or154nLLU6bELzjh0mCreFjt0m2v72zLi3yHE0QbeE,7650
101
- prediction_market_agent_tooling-0.56.0.dev1859.dist-info/METADATA,sha256=wjkMWBepYIs-EtTIlQLUXsg4Vkg_XNEop7Pz-l789Po,8114
102
- prediction_market_agent_tooling-0.56.0.dev1859.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
103
- prediction_market_agent_tooling-0.56.0.dev1859.dist-info/entry_points.txt,sha256=m8PukHbeH5g0IAAmOf_1Ahm-sGAMdhSSRQmwtpmi2s8,81
104
- prediction_market_agent_tooling-0.56.0.dev1859.dist-info/RECORD,,
100
+ prediction_market_agent_tooling-0.56.0.dev1861.dist-info/LICENSE,sha256=6or154nLLU6bELzjh0mCreFjt0m2v72zLi3yHE0QbeE,7650
101
+ prediction_market_agent_tooling-0.56.0.dev1861.dist-info/METADATA,sha256=QYG8yvGAGGGW0yESTAYImxorjN1Js8wV3U-20MD2dw8,8114
102
+ prediction_market_agent_tooling-0.56.0.dev1861.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
103
+ prediction_market_agent_tooling-0.56.0.dev1861.dist-info/entry_points.txt,sha256=m8PukHbeH5g0IAAmOf_1Ahm-sGAMdhSSRQmwtpmi2s8,81
104
+ prediction_market_agent_tooling-0.56.0.dev1861.dist-info/RECORD,,