speedy-utils 1.1.24__tar.gz → 1.1.26__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 (77) hide show
  1. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/PKG-INFO +1 -1
  2. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/bumpversion.sh +1 -1
  3. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/pyproject.toml +1 -1
  4. speedy_utils-1.1.26/simple_test_imemoize.py +64 -0
  5. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/__init__.py +3 -1
  6. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/utils_cache.py +142 -1
  7. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/.github/copilot-instructions.md +0 -0
  8. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/.github/workflows/publish.yml +0 -0
  9. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/.gitignore +0 -0
  10. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/.pre-commit-config.yaml +0 -0
  11. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/IMPROVEMENTS.md +0 -0
  12. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/README.md +0 -0
  13. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/examples/temperature_range_example.py +0 -0
  14. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/examples_improved_error_tracing.py +0 -0
  15. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/notebooks/llm_utils/llm_as_a_judge.ipynb +0 -0
  16. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/notebooks/test_multi_thread.ipynb +0 -0
  17. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/ruff.toml +0 -0
  18. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/scripts/deploy.sh +0 -0
  19. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/setup.cfg +0 -0
  20. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/__init__.py +0 -0
  21. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/chat_format/__init__.py +0 -0
  22. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/chat_format/display.py +0 -0
  23. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/chat_format/transform.py +0 -0
  24. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/chat_format/utils.py +0 -0
  25. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/group_messages.py +0 -0
  26. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/__init__.py +0 -0
  27. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/async_lm/__init__.py +0 -0
  28. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/async_lm/_utils.py +0 -0
  29. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/async_lm/async_llm_task.py +0 -0
  30. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/async_lm/async_lm.py +0 -0
  31. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/async_lm/async_lm_base.py +0 -0
  32. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/async_lm/lm_specific.py +0 -0
  33. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/base_prompt_builder.py +0 -0
  34. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/llm.py +0 -0
  35. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/llm_signature.py +0 -0
  36. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/lm_base.py +0 -0
  37. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/mixins.py +0 -0
  38. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/openai_memoize.py +0 -0
  39. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/signature.py +0 -0
  40. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/lm/utils.py +0 -0
  41. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/scripts/README.md +0 -0
  42. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/scripts/vllm_load_balancer.py +0 -0
  43. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/scripts/vllm_serve.py +0 -0
  44. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/vector_cache/__init__.py +0 -0
  45. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/vector_cache/cli.py +0 -0
  46. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/vector_cache/core.py +0 -0
  47. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/vector_cache/types.py +0 -0
  48. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/llm_utils/vector_cache/utils.py +0 -0
  49. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/all.py +0 -0
  50. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/__init__.py +0 -0
  51. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/clock.py +0 -0
  52. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/function_decorator.py +0 -0
  53. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/logger.py +0 -0
  54. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/notebook_utils.py +0 -0
  55. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/patcher.py +0 -0
  56. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/report_manager.py +0 -0
  57. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/utils_io.py +0 -0
  58. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/utils_misc.py +0 -0
  59. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/common/utils_print.py +0 -0
  60. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/multi_worker/__init__.py +0 -0
  61. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/multi_worker/process.py +0 -0
  62. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/multi_worker/thread.py +0 -0
  63. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/scripts/__init__.py +0 -0
  64. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/scripts/mpython.py +0 -0
  65. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/src/speedy_utils/scripts/openapi_client_codegen.py +0 -0
  66. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/llm_utils/test_llm_mixins.py +0 -0
  67. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/sample_objects.py +0 -0
  68. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test.py +0 -0
  69. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test_logger.py +0 -0
  70. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test_logger_format.py +0 -0
  71. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test_memoize_typing.py +0 -0
  72. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test_mpython.py +0 -0
  73. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test_multithread_error_trace.py +0 -0
  74. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test_process.py +0 -0
  75. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test_process_update.py +0 -0
  76. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/tests/test_thread.py +0 -0
  77. {speedy_utils-1.1.24 → speedy_utils-1.1.26}/uv.lock +0 -0
@@ -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
@@ -1,7 +1,7 @@
1
1
  #!/bin/zsh
2
2
  # Bump patch version using poetry, commit, and push
3
3
  set -e
4
-
4
+ uv pip install poetry
5
5
  echo 'Current version:'
6
6
  poetry version
7
7
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "speedy-utils"
3
- version = "1.1.24"
3
+ version = "1.1.26"
4
4
  description = "Fast and easy-to-use package for data science"
5
5
  authors = [{ name = "AnhVTH", email = "anhvth.226@gmail.com" }]
6
6
  readme = "README.md"
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Simple test for imemoize without heavy dependencies
4
+ """
5
+
6
+ import sys
7
+ import time
8
+ import os.path as osp
9
+ sys.path.insert(0, osp.join(osp.dirname(__file__), 'src'))
10
+
11
+ # Test basic imports first
12
+ print("Testing imports...")
13
+
14
+ try:
15
+ from speedy_utils.common.utils_cache import imemoize, identify, get_source
16
+ print("✓ Successfully imported imemoize from utils_cache")
17
+ except Exception as e:
18
+ print(f"✗ Failed to import: {e}")
19
+ sys.exit(1)
20
+
21
+ @imemoize
22
+ def simple_computation(x):
23
+ """Simple computation for testing"""
24
+ print(f"Computing simple_computation({x})")
25
+ time.sleep(0.05) # Small delay to verify caching
26
+ return x * x
27
+
28
+ def test_basic():
29
+ print("\n=== Testing basic imemoize functionality ===")
30
+
31
+ # Test first call
32
+ print("First call:")
33
+ start = time.time()
34
+ result1 = simple_computation(5)
35
+ end = time.time()
36
+ print(f"Result: {result1}, Time: {end - start:.3f}s")
37
+
38
+ # Test second call (should be cached)
39
+ print("Second call (should be cached):")
40
+ start = time.time()
41
+ result2 = simple_computation(5)
42
+ end = time.time()
43
+ print(f"Result: {result2}, Time: {end - start:.3f}s")
44
+
45
+ assert result1 == result2 == 25
46
+ print("✓ Basic caching works!")
47
+
48
+ def test_function_source_hashing():
49
+ print("\n=== Testing function source code detection ===")
50
+
51
+ # Test that get_source works
52
+ source = get_source(simple_computation)
53
+ print(f"Function source hash length: {len(source)}")
54
+
55
+ # Test identity
56
+ identity = identify((source, (5,), {}))
57
+ print(f"Cache key identity: {identity[:50]}...")
58
+
59
+ print("✓ Function source detection works!")
60
+
61
+ if __name__ == "__main__":
62
+ test_basic()
63
+ test_function_source_hashing()
64
+ print("\n🎉 Simple tests passed!")
@@ -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"]
File without changes
File without changes
File without changes
File without changes
File without changes