From 730be04ebdcf873fad4ef2f012d602f4a366a089 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Thu, 7 Nov 2024 11:27:35 +0100 Subject: [PATCH 01/10] Single shared engine instance --- prediction_market_agent_tooling/config.py | 2 +- .../tools/caches/db_cache.py | 30 +++++++++++-------- pyproject.toml | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/prediction_market_agent_tooling/config.py b/prediction_market_agent_tooling/config.py index 9a9efdd6..6330dce3 100644 --- a/prediction_market_agent_tooling/config.py +++ b/prediction_market_agent_tooling/config.py @@ -53,7 +53,7 @@ class APIKeys(BaseSettings): SQLALCHEMY_DB_URL: t.Optional[SecretStr] = None - ENABLE_CACHE: bool = True + ENABLE_CACHE: bool = False CACHE_DIR: str = "./.cache" @property diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index 500b686c..28f6e525 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -15,7 +15,7 @@ ) from pydantic import BaseModel -from sqlalchemy import Column +from sqlalchemy import Column, Engine from sqlalchemy.dialects.postgresql import JSONB from sqlmodel import Field, Session, SQLModel, create_engine, desc, select @@ -40,6 +40,9 @@ class FunctionCache(SQLModel, table=True): created_at: DatetimeUTC = Field(default_factory=utcnow, index=True) +DB_CACHE_ENGINE: None | Engine = None + + @overload def db_cache( func: None = None, @@ -97,15 +100,16 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: if not api_keys.ENABLE_CACHE: return func(*args, **kwargs) - engine = create_engine( - api_keys.sqlalchemy_db_url.get_secret_value(), - # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. - json_serializer=json_serializer, - json_deserializer=json_deserializer, - ) - - # Create table if it doesn't exist - SQLModel.metadata.create_all(engine) + global DB_CACHE_ENGINE + if DB_CACHE_ENGINE is None: + DB_CACHE_ENGINE = create_engine( + api_keys.sqlalchemy_db_url.get_secret_value(), + # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. + json_serializer=json_serializer, + json_deserializer=json_deserializer, + ) + # Create table if it doesn't exist + SQLModel.metadata.create_all(DB_CACHE_ENGINE) # Convert *args and **kwargs to a single dictionary, where we have names for arguments passed as args as well. signature = inspect.signature(func) @@ -151,7 +155,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: if return_type is not None and contains_pydantic_model(return_type): is_pydantic_model = True - with Session(engine) as session: + with Session(DB_CACHE_ENGINE) as session: # Try to get cached result statement = ( select(FunctionCache) @@ -195,7 +199,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: ) # If postgres access was specified, save it. - if engine is not None and (cache_none or computed_result is not None): + if cache_none or computed_result is not None: cache_entry = FunctionCache( function_name=function_name, full_function_name=full_function_name, @@ -204,7 +208,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: result=computed_result, created_at=utcnow(), ) - with Session(engine) as session: + with Session(DB_CACHE_ENGINE) as session: logger.info(f"Saving {cache_entry} into database.") session.add(cache_entry) session.commit() diff --git a/pyproject.toml b/pyproject.toml index 83197c3a..e608b8c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "prediction-market-agent-tooling" -version = "0.56.1" +version = "0.56.2" description = "Tools to benchmark, deploy and monitor prediction market agents." authors = ["Gnosis"] readme = "README.md" From d45edebe5e46d1ff52e9c7cc50b354e7c0943667 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sat, 9 Nov 2024 15:11:22 +0700 Subject: [PATCH 02/10] fixes --- .../tools/caches/db_cache.py | 32 +++++++++---------- .../tools/pickle_utils.py | 31 ++++++++++++++++++ pyproject.toml | 2 +- tests/tools/test_db_cache.py | 10 ++++++ 4 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 prediction_market_agent_tooling/tools/pickle_utils.py diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index 28f6e525..11b99da8 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -15,13 +15,14 @@ ) from pydantic import BaseModel -from sqlalchemy import Column, Engine +from sqlalchemy import Column from sqlalchemy.dialects.postgresql import JSONB from sqlmodel import Field, Session, SQLModel, create_engine, desc, select from prediction_market_agent_tooling.config import APIKeys from prediction_market_agent_tooling.loggers import logger from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC +from prediction_market_agent_tooling.tools.pickle_utils import InitialiseNonPickable from prediction_market_agent_tooling.tools.utils import utcnow FunctionT = TypeVar("FunctionT", bound=Callable[..., Any]) @@ -40,9 +41,6 @@ class FunctionCache(SQLModel, table=True): created_at: DatetimeUTC = Field(default_factory=utcnow, index=True) -DB_CACHE_ENGINE: None | Engine = None - - @overload def db_cache( func: None = None, @@ -93,6 +91,17 @@ def decorator(func: FunctionT) -> FunctionT: return decorator api_keys = api_keys if api_keys is not None else APIKeys() + wrapped_engine = InitialiseNonPickable( + lambda: create_engine( + api_keys.sqlalchemy_db_url.get_secret_value(), + # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. + json_serializer=json_serializer, + json_deserializer=json_deserializer, + ) + ) + + if api_keys.ENABLE_CACHE: + SQLModel.metadata.create_all(wrapped_engine.get_value()) @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: @@ -100,16 +109,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: if not api_keys.ENABLE_CACHE: return func(*args, **kwargs) - global DB_CACHE_ENGINE - if DB_CACHE_ENGINE is None: - DB_CACHE_ENGINE = create_engine( - api_keys.sqlalchemy_db_url.get_secret_value(), - # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. - json_serializer=json_serializer, - json_deserializer=json_deserializer, - ) - # Create table if it doesn't exist - SQLModel.metadata.create_all(DB_CACHE_ENGINE) + engine = wrapped_engine.get_value() # Convert *args and **kwargs to a single dictionary, where we have names for arguments passed as args as well. signature = inspect.signature(func) @@ -155,7 +155,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: if return_type is not None and contains_pydantic_model(return_type): is_pydantic_model = True - with Session(DB_CACHE_ENGINE) as session: + with Session(engine) as session: # Try to get cached result statement = ( select(FunctionCache) @@ -208,7 +208,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: result=computed_result, created_at=utcnow(), ) - with Session(DB_CACHE_ENGINE) as session: + with Session(engine) as session: logger.info(f"Saving {cache_entry} into database.") session.add(cache_entry) session.commit() diff --git a/prediction_market_agent_tooling/tools/pickle_utils.py b/prediction_market_agent_tooling/tools/pickle_utils.py new file mode 100644 index 00000000..1ec968c5 --- /dev/null +++ b/prediction_market_agent_tooling/tools/pickle_utils.py @@ -0,0 +1,31 @@ +import typing as t + +InitialisedValue = t.TypeVar("InitialisedValue") + + +class InitialiseNonPickable(t.Generic[InitialisedValue]): + """ + Use this class to wrap values that you want to be shared within a thread, + but they are re-initialised for a new processes. + + Initialiser for the value still needs to be pickable. + """ + + def __init__(self, initialiser: t.Callable[[], InitialisedValue]) -> None: + self.value: InitialisedValue | None = None + self.initialiser = initialiser + + def __getstate__(self) -> dict[str, t.Any]: + # During pickling, always return `value` as just None, which is pickable and this class will re-initialise it in `get_value` when called. + return {"value": None, "initialiser": self.initialiser} + + def __setstate__(self, d: dict[str, t.Any]) -> None: + self.value = d["value"] + self.initialiser = d["initialiser"] + + def get_value(self) -> InitialisedValue: + """Use this function to get the wrapped value, which will be initialised if necessary.""" + if self.value is None: + self.value = self.initialiser() + + return self.value diff --git a/pyproject.toml b/pyproject.toml index e608b8c9..c3f96165 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "prediction-market-agent-tooling" -version = "0.56.2" +version = "0.56.3" description = "Tools to benchmark, deploy and monitor prediction market agents." authors = ["Gnosis"] readme = "README.md" diff --git a/tests/tools/test_db_cache.py b/tests/tools/test_db_cache.py index 29b38684..fbd3d050 100644 --- a/tests/tools/test_db_cache.py +++ b/tests/tools/test_db_cache.py @@ -5,6 +5,7 @@ from prediction_market_agent_tooling.config import APIKeys from prediction_market_agent_tooling.tools.caches.db_cache import db_cache from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC +from prediction_market_agent_tooling.tools.parallelism import par_map def test_postgres_cache_bools( @@ -318,3 +319,12 @@ def integers(a: int, b: str, c: float) -> None: assert ( call_count == 2 ), "The function should only be called twice due to caching with ignored keys/types" + + +def test_db_cache_with_parallelism(keys_with_sqlalchemy_db_url: APIKeys) -> None: + @db_cache(api_keys=keys_with_sqlalchemy_db_url) + def twice(x: int) -> int: + return x * 2 + + results = par_map([1, 2, 3, 1, 2, 3], twice) + assert results == [2, 4, 6, 2, 4, 6] From 48a5ae6e53258717dfafbf42dcd59db5860bdccf Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sat, 9 Nov 2024 15:17:22 +0700 Subject: [PATCH 03/10] revert accidental bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c3f96165..e608b8c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "prediction-market-agent-tooling" -version = "0.56.3" +version = "0.56.2" description = "Tools to benchmark, deploy and monitor prediction market agents." authors = ["Gnosis"] readme = "README.md" From 2e6ba9314018c6f9d6a8ba750e059aae2eb7d3cb Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sat, 9 Nov 2024 15:28:20 +0700 Subject: [PATCH 04/10] fix pickle in github ci --- prediction_market_agent_tooling/tools/caches/db_cache.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index 11b99da8..e8b56269 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -2,7 +2,7 @@ import inspect import json from datetime import date, timedelta -from functools import wraps +from functools import partial, wraps from typing import ( Any, Callable, @@ -92,7 +92,8 @@ def decorator(func: FunctionT) -> FunctionT: api_keys = api_keys if api_keys is not None else APIKeys() wrapped_engine = InitialiseNonPickable( - lambda: create_engine( + partial( + create_engine, api_keys.sqlalchemy_db_url.get_secret_value(), # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. json_serializer=json_serializer, From c9e85448a344671bf78d46eab7bff876cc426090 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sat, 9 Nov 2024 16:13:22 +0700 Subject: [PATCH 05/10] fiiiix --- .../tools/caches/db_cache.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index e8b56269..1a4fa5f7 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -2,7 +2,7 @@ import inspect import json from datetime import date, timedelta -from functools import partial, wraps +from functools import wraps from typing import ( Any, Callable, @@ -15,7 +15,7 @@ ) from pydantic import BaseModel -from sqlalchemy import Column +from sqlalchemy import Column, Engine from sqlalchemy.dialects.postgresql import JSONB from sqlmodel import Field, Session, SQLModel, create_engine, desc, select @@ -91,15 +91,16 @@ def decorator(func: FunctionT) -> FunctionT: return decorator api_keys = api_keys if api_keys is not None else APIKeys() - wrapped_engine = InitialiseNonPickable( - partial( - create_engine, + + def engine_initialiser() -> Engine: + return create_engine( api_keys.sqlalchemy_db_url.get_secret_value(), # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. json_serializer=json_serializer, json_deserializer=json_deserializer, ) - ) + + wrapped_engine = InitialiseNonPickable(engine_initialiser) if api_keys.ENABLE_CACHE: SQLModel.metadata.create_all(wrapped_engine.get_value()) From 1c9b8aa3973ac9a569fc6300863650a3e617812b Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sun, 10 Nov 2024 09:23:09 +0700 Subject: [PATCH 06/10] fix loguru --- .../tools/caches/db_cache.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index 1a4fa5f7..74423556 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -1,6 +1,7 @@ import hashlib import inspect import json +import logging from datetime import date, timedelta from functools import wraps from typing import ( @@ -15,12 +16,11 @@ ) from pydantic import BaseModel -from sqlalchemy import Column, Engine +from sqlalchemy import Column from sqlalchemy.dialects.postgresql import JSONB from sqlmodel import Field, Session, SQLModel, create_engine, desc, select from prediction_market_agent_tooling.config import APIKeys -from prediction_market_agent_tooling.loggers import logger from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC from prediction_market_agent_tooling.tools.pickle_utils import InitialiseNonPickable from prediction_market_agent_tooling.tools.utils import utcnow @@ -90,17 +90,16 @@ def decorator(func: FunctionT) -> FunctionT: return decorator + logger = logging # For some reason, `loguru` doesn't work in multiprocessing if it's used in in-function-defined functions, so force-patch for just standard logging here. api_keys = api_keys if api_keys is not None else APIKeys() - - def engine_initialiser() -> Engine: - return create_engine( + wrapped_engine = InitialiseNonPickable( + lambda: create_engine( api_keys.sqlalchemy_db_url.get_secret_value(), # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. json_serializer=json_serializer, json_deserializer=json_deserializer, ) - - wrapped_engine = InitialiseNonPickable(engine_initialiser) + ) if api_keys.ENABLE_CACHE: SQLModel.metadata.create_all(wrapped_engine.get_value()) From 56c9b767455183d9b3c4409cbd5d4abd65ecaf41 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sun, 10 Nov 2024 17:48:43 +0700 Subject: [PATCH 07/10] revert --- prediction_market_agent_tooling/tools/caches/db_cache.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index 74423556..11b99da8 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -1,7 +1,6 @@ import hashlib import inspect import json -import logging from datetime import date, timedelta from functools import wraps from typing import ( @@ -21,6 +20,7 @@ from sqlmodel import Field, Session, SQLModel, create_engine, desc, select from prediction_market_agent_tooling.config import APIKeys +from prediction_market_agent_tooling.loggers import logger from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC from prediction_market_agent_tooling.tools.pickle_utils import InitialiseNonPickable from prediction_market_agent_tooling.tools.utils import utcnow @@ -90,7 +90,6 @@ def decorator(func: FunctionT) -> FunctionT: return decorator - logger = logging # For some reason, `loguru` doesn't work in multiprocessing if it's used in in-function-defined functions, so force-patch for just standard logging here. api_keys = api_keys if api_keys is not None else APIKeys() wrapped_engine = InitialiseNonPickable( lambda: create_engine( From 00ecc96d68a0b39a690a72b26b335b81a8c52b4d Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sun, 10 Nov 2024 21:31:17 +0700 Subject: [PATCH 08/10] ah --- .../tools/caches/db_cache.py | 21 +++++-------- .../tools/pickle_utils.py | 31 ------------------- .../relevant_news_cache.py | 9 ++++-- tests/tools/test_db_cache.py | 10 ------ 4 files changed, 14 insertions(+), 57 deletions(-) delete mode 100644 prediction_market_agent_tooling/tools/pickle_utils.py diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index 11b99da8..0ea60e7b 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -22,7 +22,6 @@ from prediction_market_agent_tooling.config import APIKeys from prediction_market_agent_tooling.loggers import logger from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC -from prediction_market_agent_tooling.tools.pickle_utils import InitialiseNonPickable from prediction_market_agent_tooling.tools.utils import utcnow FunctionT = TypeVar("FunctionT", bound=Callable[..., Any]) @@ -91,17 +90,6 @@ def decorator(func: FunctionT) -> FunctionT: return decorator api_keys = api_keys if api_keys is not None else APIKeys() - wrapped_engine = InitialiseNonPickable( - lambda: create_engine( - api_keys.sqlalchemy_db_url.get_secret_value(), - # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. - json_serializer=json_serializer, - json_deserializer=json_deserializer, - ) - ) - - if api_keys.ENABLE_CACHE: - SQLModel.metadata.create_all(wrapped_engine.get_value()) @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: @@ -109,7 +97,14 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: if not api_keys.ENABLE_CACHE: return func(*args, **kwargs) - engine = wrapped_engine.get_value() + engine = create_engine( + api_keys.sqlalchemy_db_url.get_secret_value(), + # Use custom json serializer and deserializer, because otherwise, for example `datetime` serialization would fail. + json_serializer=json_serializer, + json_deserializer=json_deserializer, + pool_size=1, + ) + SQLModel.metadata.create_all(engine) # Convert *args and **kwargs to a single dictionary, where we have names for arguments passed as args as well. signature = inspect.signature(func) diff --git a/prediction_market_agent_tooling/tools/pickle_utils.py b/prediction_market_agent_tooling/tools/pickle_utils.py deleted file mode 100644 index 1ec968c5..00000000 --- a/prediction_market_agent_tooling/tools/pickle_utils.py +++ /dev/null @@ -1,31 +0,0 @@ -import typing as t - -InitialisedValue = t.TypeVar("InitialisedValue") - - -class InitialiseNonPickable(t.Generic[InitialisedValue]): - """ - Use this class to wrap values that you want to be shared within a thread, - but they are re-initialised for a new processes. - - Initialiser for the value still needs to be pickable. - """ - - def __init__(self, initialiser: t.Callable[[], InitialisedValue]) -> None: - self.value: InitialisedValue | None = None - self.initialiser = initialiser - - def __getstate__(self) -> dict[str, t.Any]: - # During pickling, always return `value` as just None, which is pickable and this class will re-initialise it in `get_value` when called. - return {"value": None, "initialiser": self.initialiser} - - def __setstate__(self, d: dict[str, t.Any]) -> None: - self.value = d["value"] - self.initialiser = d["initialiser"] - - def get_value(self) -> InitialisedValue: - """Use this function to get the wrapped value, which will be initialised if necessary.""" - if self.value is None: - self.value = self.initialiser() - - return self.value diff --git a/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_cache.py b/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_cache.py index d1257ec5..8fc280cc 100644 --- a/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_cache.py +++ b/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_cache.py @@ -25,9 +25,12 @@ class RelevantNewsCacheModel(SQLModel, table=True): class RelevantNewsResponseCache: def __init__(self, sqlalchemy_db_url: str | None = None): self.engine = create_engine( - sqlalchemy_db_url - if sqlalchemy_db_url - else APIKeys().sqlalchemy_db_url.get_secret_value() + ( + sqlalchemy_db_url + if sqlalchemy_db_url + else APIKeys().sqlalchemy_db_url.get_secret_value() + ), + pool_size=1, ) self._initialize_db() diff --git a/tests/tools/test_db_cache.py b/tests/tools/test_db_cache.py index fbd3d050..29b38684 100644 --- a/tests/tools/test_db_cache.py +++ b/tests/tools/test_db_cache.py @@ -5,7 +5,6 @@ from prediction_market_agent_tooling.config import APIKeys from prediction_market_agent_tooling.tools.caches.db_cache import db_cache from prediction_market_agent_tooling.tools.datetime_utc import DatetimeUTC -from prediction_market_agent_tooling.tools.parallelism import par_map def test_postgres_cache_bools( @@ -319,12 +318,3 @@ def integers(a: int, b: str, c: float) -> None: assert ( call_count == 2 ), "The function should only be called twice due to caching with ignored keys/types" - - -def test_db_cache_with_parallelism(keys_with_sqlalchemy_db_url: APIKeys) -> None: - @db_cache(api_keys=keys_with_sqlalchemy_db_url) - def twice(x: int) -> int: - return x * 2 - - results = par_map([1, 2, 3, 1, 2, 3], twice) - assert results == [2, 4, 6, 2, 4, 6] From a7fa2d0e21ad45f87d3eb7db51cabf32c720d399 Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sun, 10 Nov 2024 21:32:45 +0700 Subject: [PATCH 09/10] ah2 --- prediction_market_agent_tooling/tools/caches/db_cache.py | 1 + 1 file changed, 1 insertion(+) diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index 0ea60e7b..fc8edf05 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -208,6 +208,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: session.add(cache_entry) session.commit() + engine.dispose() return computed_result return cast(FunctionT, wrapper) From 15477b27e6aedbcd84df4f48741ba8c178c5901a Mon Sep 17 00:00:00 2001 From: Peter Jung Date: Sun, 10 Nov 2024 21:34:03 +0700 Subject: [PATCH 10/10] revert --- prediction_market_agent_tooling/tools/caches/db_cache.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prediction_market_agent_tooling/tools/caches/db_cache.py b/prediction_market_agent_tooling/tools/caches/db_cache.py index fc8edf05..4da6ffb8 100644 --- a/prediction_market_agent_tooling/tools/caches/db_cache.py +++ b/prediction_market_agent_tooling/tools/caches/db_cache.py @@ -104,6 +104,8 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: json_deserializer=json_deserializer, pool_size=1, ) + + # Create table if it doesn't exist SQLModel.metadata.create_all(engine) # Convert *args and **kwargs to a single dictionary, where we have names for arguments passed as args as well.