speedy-utils 1.1.24__py3-none-any.whl → 1.1.26__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.
speedy_utils/__init__.py CHANGED
@@ -16,6 +16,7 @@
16
16
  # • timef(func) -> Callable - Function execution time decorator
17
17
  # • retry_runtime(sleep_seconds: int, max_retry: int, exceptions) -> Callable
18
18
  # • memoize(func) -> Callable - Function result caching decorator
19
+ # • imemoize(func) -> Callable - In-memory caching decorator (global persistent)
19
20
  # • identify(obj: Any) -> str - Generate unique object identifier
20
21
  # • identify_uuid(obj: Any) -> str - Generate UUID-based object identifier
21
22
  # • load_by_ext(fname: Union[str, list[str]]) -> Any - Auto-detect file format loader
@@ -125,7 +126,7 @@ from .common.notebook_utils import (
125
126
  )
126
127
 
127
128
  # Cache utilities
128
- from .common.utils_cache import identify, identify_uuid, memoize
129
+ from .common.utils_cache import identify, identify_uuid, imemoize, memoize
129
130
 
130
131
  # IO utilities
131
132
  from .common.utils_io import (
@@ -224,6 +225,7 @@ __all__ = [
224
225
  "retry_runtime",
225
226
  # Cache utilities
226
227
  "memoize",
228
+ "imemoize",
227
229
  "identify",
228
230
  "identify_uuid",
229
231
  # IO utilities
@@ -44,6 +44,9 @@ _MEM_CACHES: "weakref.WeakKeyDictionary[Callable[..., Any], cachetools.LRUCache]
44
44
  weakref.WeakKeyDictionary()
45
45
  )
46
46
 
47
+ # Global memory cache for imemoize (persists across IPython reloads)
48
+ _GLOBAL_MEMORY_CACHE: dict[str, Any] = {}
49
+
47
50
  # Backward-compat global symbol (internal only; not exported)
48
51
  LRU_MEM_CACHE = cachetools.LRUCache(maxsize=256)
49
52
 
@@ -680,4 +683,142 @@ def memoize(
680
683
  return decorator(_func)
681
684
 
682
685
 
683
- __all__ = ["memoize", "identify"]
686
+ # --------------------------------------------------------------------------------------
687
+ # In-memory memoize with global persistent cache
688
+ # --------------------------------------------------------------------------------------
689
+
690
+
691
+ @overload
692
+ def imemoize(
693
+ _func: Callable[P, R],
694
+ *,
695
+ keys: Optional[list[str]] = ...,
696
+ key: Optional[Callable[..., Any]] = ...,
697
+ ignore_self: bool = ...,
698
+ ) -> Callable[P, R]: ...
699
+
700
+
701
+ @overload
702
+ def imemoize(
703
+ _func: Callable[P, Awaitable[R]],
704
+ *,
705
+ keys: Optional[list[str]] = ...,
706
+ key: Optional[Callable[..., Any]] = ...,
707
+ ignore_self: bool = ...,
708
+ ) -> Callable[P, Awaitable[R]]: ...
709
+
710
+
711
+ @overload
712
+ def imemoize(
713
+ _func: None = ...,
714
+ *,
715
+ keys: Optional[list[str]] = ...,
716
+ key: Optional[Callable[..., Any]] = ...,
717
+ ignore_self: bool = ...,
718
+ ) -> Callable[[Callable[P, R]], Callable[P, R]]: ...
719
+
720
+
721
+ @overload
722
+ def imemoize( # type: ignore
723
+ _func: None = ...,
724
+ *,
725
+ keys: Optional[list[str]] = ...,
726
+ key: Optional[Callable[..., Any]] = ...,
727
+ ignore_self: bool = ...,
728
+ ) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]: ...
729
+
730
+
731
+ def imemoize(
732
+ _func: Optional[Callable[P, Any]] = None,
733
+ *,
734
+ keys: Optional[list[str]] = None,
735
+ key: Optional[Callable[..., Any]] = None,
736
+ ignore_self: bool = True,
737
+ ):
738
+ """
739
+ In-memory memoization decorator with global persistent cache.
740
+
741
+ Unlike regular memoize, this uses a global memory cache that persists
742
+ across IPython %load executions. The cache key is based on the function's
743
+ source code combined with runtime arguments, making it suitable for
744
+ notebook environments where functions may be reloaded.
745
+
746
+ Args:
747
+ keys: list of argument names to include in key (optional).
748
+ key: custom callable (*args, **kwargs) -> hashable for keying (optional).
749
+ ignore_self: ignore 'self' when building cache key for bound methods.
750
+
751
+ Example:
752
+ @imemoize
753
+ def expensive_computation(x):
754
+ import time
755
+ time.sleep(2)
756
+ return x * x
757
+
758
+ # First call computes and caches
759
+ result1 = expensive_computation(5)
760
+
761
+ # Second call retrieves from memory cache
762
+ result2 = expensive_computation(5)
763
+
764
+ # Even after %load file.py in IPython, the cache persists
765
+ """
766
+
767
+ def decorator(func: Callable[P, Any]) -> Callable[P, Any]:
768
+ is_async = inspect.iscoroutinefunction(func)
769
+
770
+ if is_async:
771
+ @functools.wraps(func)
772
+ async def async_wrapper(*args: P.args, **kwargs: P.kwargs) -> Any:
773
+ # Compute cache key based on function source + args
774
+ func_source, sub_dir, key_id = _compute_cache_components(
775
+ func, args, kwargs, ignore_self, keys, key
776
+ )
777
+ cache_key = identify((func_source, sub_dir, key_id))
778
+
779
+ # Check global memory cache
780
+ with mem_lock:
781
+ if cache_key in _GLOBAL_MEMORY_CACHE:
782
+ return _GLOBAL_MEMORY_CACHE[cache_key]
783
+
784
+ # Compute result and store in cache
785
+ result = await func(*args, **kwargs)
786
+
787
+ with mem_lock:
788
+ _GLOBAL_MEMORY_CACHE[cache_key] = result
789
+
790
+ return result
791
+
792
+ return async_wrapper
793
+ else:
794
+ @functools.wraps(func)
795
+ def sync_wrapper(*args: P.args, **kwargs: P.kwargs) -> Any:
796
+ # Compute cache key based on function source + args
797
+ func_source, sub_dir, key_id = _compute_cache_components(
798
+ func, args, kwargs, ignore_self, keys, key
799
+ )
800
+ cache_key = identify((func_source, sub_dir, key_id))
801
+
802
+ # Check global memory cache
803
+ with mem_lock:
804
+ if cache_key in _GLOBAL_MEMORY_CACHE:
805
+ return _GLOBAL_MEMORY_CACHE[cache_key]
806
+
807
+ # Compute result and store in cache
808
+ result = func(*args, **kwargs)
809
+
810
+ with mem_lock:
811
+ _GLOBAL_MEMORY_CACHE[cache_key] = result
812
+
813
+ return result
814
+
815
+ return sync_wrapper
816
+
817
+ # Support both @imemoize and @imemoize(...)
818
+ if _func is None:
819
+ return decorator
820
+ else:
821
+ return decorator(_func)
822
+
823
+
824
+ __all__ = ["memoize", "imemoize", "identify"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: speedy-utils
3
- Version: 1.1.24
3
+ Version: 1.1.26
4
4
  Summary: Fast and easy-to-use package for data science
5
5
  Project-URL: Homepage, https://github.com/anhvth/speedy
6
6
  Project-URL: Repository, https://github.com/anhvth/speedy
@@ -27,7 +27,7 @@ llm_utils/vector_cache/cli.py,sha256=DMXTj8nZ2_LRjprbYPb4uzq04qZtOfBbmblmaqDcCuM
27
27
  llm_utils/vector_cache/core.py,sha256=J8ocRX9sBfzboQkf5vFF2cx0SK-nftmKWJUa91WUBy8,31134
28
28
  llm_utils/vector_cache/types.py,sha256=ru8qmUZ8_lNd3_oYpjCMtpXTsqmwsSBe56Z4hTWm3xI,435
29
29
  llm_utils/vector_cache/utils.py,sha256=dwbbXlRrARrpmS4YqSlYQqrTURg0UWe8XvaAWcX05MM,1458
30
- speedy_utils/__init__.py,sha256=LFV2La5TaYkXbe5xVQ9xiDqsjcjcF0QUyg58jI8UMfI,6081
30
+ speedy_utils/__init__.py,sha256=wPz1MNAicV7skqqZloUFt5QrJcAhxtPQ4jFXk2lz6YA,6190
31
31
  speedy_utils/all.py,sha256=gXXRlBLvU8AON7XqO6iFQ8LCIQEIcP_2CDumd_U1ppI,5171
32
32
  speedy_utils/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  speedy_utils/common/clock.py,sha256=3n4FkCW0dz46O8By09V5Pve1DSMgpLDRbWEVRryryeQ,7423
@@ -36,7 +36,7 @@ speedy_utils/common/logger.py,sha256=a2iZx0eWyfi2-2X_H2QmfuA3tfR7_XSM7Nd0GdUnUOs
36
36
  speedy_utils/common/notebook_utils.py,sha256=-97kehJ_Gg3TzDLubsLIYJcykqX1NXhbvBO6nniZSYM,2063
37
37
  speedy_utils/common/patcher.py,sha256=VCmdxyTF87qroggQkQklRPhAOPJbeBqhcJoTsLcDxNw,2303
38
38
  speedy_utils/common/report_manager.py,sha256=eBiw5KY6bWUhwki3B4lK5o8bFsp7L5x28X9GCI-Sd1w,3899
39
- speedy_utils/common/utils_cache.py,sha256=NCwILnhsK86sDPkkriDTCyuM-qUKFxYOo1Piww1ED0g,22381
39
+ speedy_utils/common/utils_cache.py,sha256=h3JbIi0V5pTaFNJDjfwORSN63bc0SrRq_dm8KZJiL94,27023
40
40
  speedy_utils/common/utils_io.py,sha256=E7mbxB_OpLvNWoFM2Qpxi1jaD8VwF-tvNOpGbf7swuU,14849
41
41
  speedy_utils/common/utils_misc.py,sha256=yYlyP0eXQuapY1dn5O8-UDePPq5bb6FxKFjb1kfZy5o,2354
42
42
  speedy_utils/common/utils_print.py,sha256=syRrnSFtguxrV-elx6DDVcSGu4Qy7D_xVNZhPwbUY4A,4864
@@ -46,7 +46,7 @@ speedy_utils/multi_worker/thread.py,sha256=bRjxUHkBjbXHQ2KSsf-Zao28zbSId-8mqMFHw
46
46
  speedy_utils/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  speedy_utils/scripts/mpython.py,sha256=IvywP7Y0_V6tWfMP-4MjPvN5_KfxWF21xaLJsCIayCk,3821
48
48
  speedy_utils/scripts/openapi_client_codegen.py,sha256=f2125S_q0PILgH5dyzoKRz7pIvNEjCkzpi4Q4pPFRZE,9683
49
- speedy_utils-1.1.24.dist-info/METADATA,sha256=3KOAmdRLEkW8wXkjAIZwvurxWeTKGcNyRg-oHhDRpBA,8028
50
- speedy_utils-1.1.24.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
- speedy_utils-1.1.24.dist-info/entry_points.txt,sha256=1rrFMfqvaMUE9hvwGiD6vnVh98kmgy0TARBj-v0Lfhs,244
52
- speedy_utils-1.1.24.dist-info/RECORD,,
49
+ speedy_utils-1.1.26.dist-info/METADATA,sha256=j0mnIF3a8jD-WBaZgrXmIlWnzdhci8ncem57-oZt8cw,8028
50
+ speedy_utils-1.1.26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
+ speedy_utils-1.1.26.dist-info/entry_points.txt,sha256=1rrFMfqvaMUE9hvwGiD6vnVh98kmgy0TARBj-v0Lfhs,244
52
+ speedy_utils-1.1.26.dist-info/RECORD,,