From 188e3a4ff0911ae31127523f642706af23dd12e3 Mon Sep 17 00:00:00 2001 From: trisongz <4735784+trisongz@users.noreply.github.com> Date: Mon, 15 Jan 2024 17:30:36 -0600 Subject: [PATCH] bump release --- lazyops/libs/persistence/backends/redis.py | 12 ++- lazyops/libs/persistence/main.py | 1 + .../libs/persistence/serializers/__init__.py | 8 +- lazyops/libs/persistence/serializers/base.py | 2 +- lazyops/types/models.py | 78 ++++++++++++++++++- lazyops/version.py | 2 +- 6 files changed, 97 insertions(+), 6 deletions(-) diff --git a/lazyops/libs/persistence/backends/redis.py b/lazyops/libs/persistence/backends/redis.py index ac8c907..4fe87d3 100644 --- a/lazyops/libs/persistence/backends/redis.py +++ b/lazyops/libs/persistence/backends/redis.py @@ -39,6 +39,13 @@ def __init__( """ Initializes the backend """ + _kdb_kwargs = {} + if kwargs: + for key in kwargs: + if key.startswith('redis_'): + _kdb_kwargs[key.replace('redis_', '')] = kwargs.pop(key) + elif key.startswith('keydb_'): + _kdb_kwargs[key.replace('keydb_', '')] = kwargs.pop(key) super().__init__( serializer=serializer, serializer_kwargs=serializer_kwargs, @@ -51,7 +58,10 @@ def __init__( if expiration is not None: self.expiration = expiration self.hset_enabled = (not hset_disabled and self.base_key is not None) if keyjoin is not None: self.keyjoin = keyjoin - self.cache: 'KeyDBSession' = get_keydb_session(name = 'persistence', **kwargs) + self.cache: 'KeyDBSession' = get_keydb_session( + name = self.name, + **_kdb_kwargs + ) def get_key(self, key: str) -> str: """ diff --git a/lazyops/libs/persistence/main.py b/lazyops/libs/persistence/main.py index 0505d8e..5b94b56 100644 --- a/lazyops/libs/persistence/main.py +++ b/lazyops/libs/persistence/main.py @@ -55,6 +55,7 @@ def __init__( self._kwargs['serializer'] = serializer self._kwargs['serializer_kwargs'] = serializer_kwargs self.base = self.base_class( + name = self.name, base_key = self.base_key, async_enabled = async_enabled, settings = self.settings, diff --git a/lazyops/libs/persistence/serializers/__init__.py b/lazyops/libs/persistence/serializers/__init__.py index 5f25bab..a1bf421 100644 --- a/lazyops/libs/persistence/serializers/__init__.py +++ b/lazyops/libs/persistence/serializers/__init__.py @@ -14,9 +14,13 @@ def get_serializer( Returns a Serializer """ serializer_type = serializer_type or "pickle" - if serializer_type == "json": + if serializer_type in {"json", "orjson", "ujson", "simdjson"}: + if serializer_type != "json" and "jsonlib" not in kwargs: + kwargs["jsonlib"] = serializer_type return JsonSerializer(**kwargs) - if serializer_type == "pickle": + if serializer_type in {"pickle", "dill", "cloudpickle"}: + if serializer_type != "pickle" and "picklelib" not in kwargs: + kwargs["picklelib"] = serializer_type return PickleSerializer(**kwargs) if serializer_type == "msgpack": return MsgPackSerializer(**kwargs) diff --git a/lazyops/libs/persistence/serializers/base.py b/lazyops/libs/persistence/serializers/base.py index f210a1a..67d8377 100644 --- a/lazyops/libs/persistence/serializers/base.py +++ b/lazyops/libs/persistence/serializers/base.py @@ -215,7 +215,7 @@ def loads(self, value: Union[str, bytes], **kwargs) -> ObjectValue: if self.raise_errors: raise e return None - async def aload(self, value: Union[str, bytes], **kwargs) -> ObjectValue: + async def aloads(self, value: Union[str, bytes], **kwargs) -> ObjectValue: """ Loads the value asynchronously """ diff --git a/lazyops/types/models.py b/lazyops/types/models.py index 5a7a151..33cd2da 100644 --- a/lazyops/types/models.py +++ b/lazyops/types/models.py @@ -1,7 +1,7 @@ import os import pathlib -from typing import Any, Type, Tuple, Dict, List, Union, Optional, Callable, TYPE_CHECKING +from typing import Any, Type, Tuple, Dict, List, Union, Optional, Callable, TypeVar, Generic, TYPE_CHECKING from lazyops.types.formatting import to_camel_case, to_snake_case, to_graphql_format from lazyops.types.classprops import classproperty, lazyproperty from lazyops.utils.serialization import Json @@ -513,6 +513,82 @@ def parse( return super().parse(url = url, scheme = scheme, adapter = adapter, **config) +ProxyObjT = TypeVar('ProxyObjT') + + +class ProxyObject(Generic[ProxyObjT]): + def __init__( + self, + obj_cls: Optional[Type[ProxyObjT]] = None, + obj_getter: Optional[Union[Callable, str]] = None, + obj_args: Optional[List[Any]] = None, + obj_kwargs: Optional[Dict[str, Any]] = None, + debug_enabled: Optional[bool] = False, + ): + """ + Proxy Object + + args: + obj_cls: the class of the object + obj_getter: the function to get the object + debug_enabled: if True, will raise an error if the object is not found + """ + # Intentionally underscore on the end to avoid conflicts with the settings + assert obj_cls or obj_getter, "Either `obj_cls` or `obj_getter` must be provided" + self.__obj_cls_ = obj_cls + self.__obj_getter_ = obj_getter + if self.__obj_getter_ and isinstance(self.__obj_getter_, str): + from lazyops.utils.helpers import lazy_import + self.__obj_getter_ = lazy_import(self.__obj_getter_) + self.__obj_ = None + self.__obj_args_ = obj_args or [] + self.__obj_kwargs_ = obj_kwargs or {} + self.__debug_enabled_ = debug_enabled + self.__last_attrs_: Dict[str, int] = {} + + @property + def _obj_(self) -> ProxyObjT: + """ + Returns the object + """ + if self.__obj_ is None: + if self.__obj_getter_: + self.__obj_ = self.__obj_getter_(*self.__obj_args_, **self.__obj_kwargs_) + elif self.__obj_cls_: + self.__obj_ = self.__obj_cls_(*self.__obj_args_, **self.__obj_kwargs_) + return self.__obj_ + + def __getattr__(self, name): + """ + Forward all unknown attributes to the proxy object + """ + if not self.__debug_enabled_: + return getattr(self._obj_, name) + + # Try to debug the attribute + if name not in self.__last_attrs_: + self.__last_attrs_[name] = 0 + self.__last_attrs_[name] += 1 + if self.__last_attrs_[name] > 5: + raise AttributeError(f"Proxy object has no attribute {name}") + + if hasattr(self._obj_, name): + self.__last_attrs_[name] = 0 + return getattr(self._obj_, name) + raise AttributeError(f"Settings object has no attribute {name}") + + if TYPE_CHECKING: + def __new__(cls, *args, **kwargs) -> ProxyObjT: + ... + + + # def __setattr__(self, name: str, value: Any) -> None: + # """ + # Forward all unknown attributes to the proxy object + # """ + # return setattr(self._obj_, name, value) + + __all__ = [ 'Field', diff --git a/lazyops/version.py b/lazyops/version.py index 83cfee3..658c89c 100644 --- a/lazyops/version.py +++ b/lazyops/version.py @@ -1 +1 @@ -VERSION = '0.2.64rc3' +VERSION = '0.2.65'