judgeval 0.0.11__py3-none-any.whl → 0.22.2__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.

Potentially problematic release.


This version of judgeval might be problematic. Click here for more details.

Files changed (171) hide show
  1. judgeval/__init__.py +177 -12
  2. judgeval/api/__init__.py +519 -0
  3. judgeval/api/api_types.py +407 -0
  4. judgeval/cli.py +79 -0
  5. judgeval/constants.py +76 -47
  6. judgeval/data/__init__.py +3 -3
  7. judgeval/data/evaluation_run.py +125 -0
  8. judgeval/data/example.py +15 -56
  9. judgeval/data/judgment_types.py +450 -0
  10. judgeval/data/result.py +29 -73
  11. judgeval/data/scorer_data.py +29 -62
  12. judgeval/data/scripts/fix_default_factory.py +23 -0
  13. judgeval/data/scripts/openapi_transform.py +123 -0
  14. judgeval/data/trace.py +121 -0
  15. judgeval/dataset/__init__.py +264 -0
  16. judgeval/env.py +52 -0
  17. judgeval/evaluation/__init__.py +344 -0
  18. judgeval/exceptions.py +27 -0
  19. judgeval/integrations/langgraph/__init__.py +13 -0
  20. judgeval/integrations/openlit/__init__.py +50 -0
  21. judgeval/judges/__init__.py +2 -3
  22. judgeval/judges/base_judge.py +2 -3
  23. judgeval/judges/litellm_judge.py +100 -20
  24. judgeval/judges/together_judge.py +101 -20
  25. judgeval/judges/utils.py +20 -24
  26. judgeval/logger.py +62 -0
  27. judgeval/prompt/__init__.py +330 -0
  28. judgeval/scorers/__init__.py +18 -25
  29. judgeval/scorers/agent_scorer.py +17 -0
  30. judgeval/scorers/api_scorer.py +45 -41
  31. judgeval/scorers/base_scorer.py +83 -38
  32. judgeval/scorers/example_scorer.py +17 -0
  33. judgeval/scorers/exceptions.py +1 -0
  34. judgeval/scorers/judgeval_scorers/__init__.py +0 -148
  35. judgeval/scorers/judgeval_scorers/api_scorers/__init__.py +19 -17
  36. judgeval/scorers/judgeval_scorers/api_scorers/answer_correctness.py +13 -19
  37. judgeval/scorers/judgeval_scorers/api_scorers/answer_relevancy.py +12 -19
  38. judgeval/scorers/judgeval_scorers/api_scorers/faithfulness.py +13 -19
  39. judgeval/scorers/judgeval_scorers/api_scorers/instruction_adherence.py +15 -0
  40. judgeval/scorers/judgeval_scorers/api_scorers/prompt_scorer.py +327 -0
  41. judgeval/scorers/score.py +77 -306
  42. judgeval/scorers/utils.py +4 -199
  43. judgeval/tracer/__init__.py +1122 -2
  44. judgeval/tracer/constants.py +1 -0
  45. judgeval/tracer/exporters/__init__.py +40 -0
  46. judgeval/tracer/exporters/s3.py +119 -0
  47. judgeval/tracer/exporters/store.py +59 -0
  48. judgeval/tracer/exporters/utils.py +32 -0
  49. judgeval/tracer/keys.py +63 -0
  50. judgeval/tracer/llm/__init__.py +7 -0
  51. judgeval/tracer/llm/config.py +78 -0
  52. judgeval/tracer/llm/constants.py +9 -0
  53. judgeval/tracer/llm/llm_anthropic/__init__.py +3 -0
  54. judgeval/tracer/llm/llm_anthropic/config.py +6 -0
  55. judgeval/tracer/llm/llm_anthropic/messages.py +452 -0
  56. judgeval/tracer/llm/llm_anthropic/messages_stream.py +322 -0
  57. judgeval/tracer/llm/llm_anthropic/wrapper.py +59 -0
  58. judgeval/tracer/llm/llm_google/__init__.py +3 -0
  59. judgeval/tracer/llm/llm_google/config.py +6 -0
  60. judgeval/tracer/llm/llm_google/generate_content.py +127 -0
  61. judgeval/tracer/llm/llm_google/wrapper.py +30 -0
  62. judgeval/tracer/llm/llm_openai/__init__.py +3 -0
  63. judgeval/tracer/llm/llm_openai/beta_chat_completions.py +216 -0
  64. judgeval/tracer/llm/llm_openai/chat_completions.py +501 -0
  65. judgeval/tracer/llm/llm_openai/config.py +6 -0
  66. judgeval/tracer/llm/llm_openai/responses.py +506 -0
  67. judgeval/tracer/llm/llm_openai/utils.py +42 -0
  68. judgeval/tracer/llm/llm_openai/wrapper.py +63 -0
  69. judgeval/tracer/llm/llm_together/__init__.py +3 -0
  70. judgeval/tracer/llm/llm_together/chat_completions.py +406 -0
  71. judgeval/tracer/llm/llm_together/config.py +6 -0
  72. judgeval/tracer/llm/llm_together/wrapper.py +52 -0
  73. judgeval/tracer/llm/providers.py +19 -0
  74. judgeval/tracer/managers.py +167 -0
  75. judgeval/tracer/processors/__init__.py +220 -0
  76. judgeval/tracer/utils.py +19 -0
  77. judgeval/trainer/__init__.py +14 -0
  78. judgeval/trainer/base_trainer.py +122 -0
  79. judgeval/trainer/config.py +128 -0
  80. judgeval/trainer/console.py +144 -0
  81. judgeval/trainer/fireworks_trainer.py +396 -0
  82. judgeval/trainer/trainable_model.py +243 -0
  83. judgeval/trainer/trainer.py +70 -0
  84. judgeval/utils/async_utils.py +39 -0
  85. judgeval/utils/decorators/__init__.py +0 -0
  86. judgeval/utils/decorators/dont_throw.py +37 -0
  87. judgeval/utils/decorators/use_once.py +13 -0
  88. judgeval/utils/file_utils.py +97 -0
  89. judgeval/utils/guards.py +36 -0
  90. judgeval/utils/meta.py +27 -0
  91. judgeval/utils/project.py +15 -0
  92. judgeval/utils/serialize.py +253 -0
  93. judgeval/utils/testing.py +70 -0
  94. judgeval/utils/url.py +10 -0
  95. judgeval/utils/version_check.py +28 -0
  96. judgeval/utils/wrappers/README.md +3 -0
  97. judgeval/utils/wrappers/__init__.py +15 -0
  98. judgeval/utils/wrappers/immutable_wrap_async.py +74 -0
  99. judgeval/utils/wrappers/immutable_wrap_async_iterator.py +84 -0
  100. judgeval/utils/wrappers/immutable_wrap_sync.py +66 -0
  101. judgeval/utils/wrappers/immutable_wrap_sync_iterator.py +84 -0
  102. judgeval/utils/wrappers/mutable_wrap_async.py +67 -0
  103. judgeval/utils/wrappers/mutable_wrap_sync.py +67 -0
  104. judgeval/utils/wrappers/py.typed +0 -0
  105. judgeval/utils/wrappers/utils.py +35 -0
  106. judgeval/version.py +5 -0
  107. judgeval/warnings.py +4 -0
  108. judgeval-0.22.2.dist-info/METADATA +265 -0
  109. judgeval-0.22.2.dist-info/RECORD +112 -0
  110. judgeval-0.22.2.dist-info/entry_points.txt +2 -0
  111. judgeval/clients.py +0 -39
  112. judgeval/common/__init__.py +0 -8
  113. judgeval/common/exceptions.py +0 -28
  114. judgeval/common/logger.py +0 -189
  115. judgeval/common/tracer.py +0 -798
  116. judgeval/common/utils.py +0 -763
  117. judgeval/data/api_example.py +0 -111
  118. judgeval/data/datasets/__init__.py +0 -5
  119. judgeval/data/datasets/dataset.py +0 -286
  120. judgeval/data/datasets/eval_dataset_client.py +0 -193
  121. judgeval/data/datasets/ground_truth.py +0 -54
  122. judgeval/data/datasets/utils.py +0 -74
  123. judgeval/evaluation_run.py +0 -132
  124. judgeval/judges/mixture_of_judges.py +0 -248
  125. judgeval/judgment_client.py +0 -354
  126. judgeval/run_evaluation.py +0 -439
  127. judgeval/scorers/judgeval_scorer.py +0 -140
  128. judgeval/scorers/judgeval_scorers/api_scorers/contextual_precision.py +0 -19
  129. judgeval/scorers/judgeval_scorers/api_scorers/contextual_recall.py +0 -19
  130. judgeval/scorers/judgeval_scorers/api_scorers/contextual_relevancy.py +0 -22
  131. judgeval/scorers/judgeval_scorers/api_scorers/hallucination.py +0 -19
  132. judgeval/scorers/judgeval_scorers/api_scorers/json_correctness.py +0 -32
  133. judgeval/scorers/judgeval_scorers/api_scorers/summarization.py +0 -20
  134. judgeval/scorers/judgeval_scorers/api_scorers/tool_correctness.py +0 -19
  135. judgeval/scorers/judgeval_scorers/classifiers/__init__.py +0 -3
  136. judgeval/scorers/judgeval_scorers/classifiers/text2sql/__init__.py +0 -3
  137. judgeval/scorers/judgeval_scorers/classifiers/text2sql/text2sql_scorer.py +0 -54
  138. judgeval/scorers/judgeval_scorers/local_implementations/__init__.py +0 -24
  139. judgeval/scorers/judgeval_scorers/local_implementations/answer_correctness/__init__.py +0 -4
  140. judgeval/scorers/judgeval_scorers/local_implementations/answer_correctness/answer_correctness_scorer.py +0 -277
  141. judgeval/scorers/judgeval_scorers/local_implementations/answer_correctness/prompts.py +0 -169
  142. judgeval/scorers/judgeval_scorers/local_implementations/answer_relevancy/__init__.py +0 -4
  143. judgeval/scorers/judgeval_scorers/local_implementations/answer_relevancy/answer_relevancy_scorer.py +0 -298
  144. judgeval/scorers/judgeval_scorers/local_implementations/answer_relevancy/prompts.py +0 -174
  145. judgeval/scorers/judgeval_scorers/local_implementations/contextual_precision/__init__.py +0 -3
  146. judgeval/scorers/judgeval_scorers/local_implementations/contextual_precision/contextual_precision_scorer.py +0 -264
  147. judgeval/scorers/judgeval_scorers/local_implementations/contextual_precision/prompts.py +0 -106
  148. judgeval/scorers/judgeval_scorers/local_implementations/contextual_recall/__init__.py +0 -3
  149. judgeval/scorers/judgeval_scorers/local_implementations/contextual_recall/contextual_recall_scorer.py +0 -254
  150. judgeval/scorers/judgeval_scorers/local_implementations/contextual_recall/prompts.py +0 -142
  151. judgeval/scorers/judgeval_scorers/local_implementations/contextual_relevancy/__init__.py +0 -3
  152. judgeval/scorers/judgeval_scorers/local_implementations/contextual_relevancy/contextual_relevancy_scorer.py +0 -245
  153. judgeval/scorers/judgeval_scorers/local_implementations/contextual_relevancy/prompts.py +0 -121
  154. judgeval/scorers/judgeval_scorers/local_implementations/faithfulness/__init__.py +0 -3
  155. judgeval/scorers/judgeval_scorers/local_implementations/faithfulness/faithfulness_scorer.py +0 -325
  156. judgeval/scorers/judgeval_scorers/local_implementations/faithfulness/prompts.py +0 -268
  157. judgeval/scorers/judgeval_scorers/local_implementations/hallucination/__init__.py +0 -3
  158. judgeval/scorers/judgeval_scorers/local_implementations/hallucination/hallucination_scorer.py +0 -263
  159. judgeval/scorers/judgeval_scorers/local_implementations/hallucination/prompts.py +0 -104
  160. judgeval/scorers/judgeval_scorers/local_implementations/json_correctness/__init__.py +0 -5
  161. judgeval/scorers/judgeval_scorers/local_implementations/json_correctness/json_correctness_scorer.py +0 -134
  162. judgeval/scorers/judgeval_scorers/local_implementations/summarization/__init__.py +0 -3
  163. judgeval/scorers/judgeval_scorers/local_implementations/summarization/prompts.py +0 -247
  164. judgeval/scorers/judgeval_scorers/local_implementations/summarization/summarization_scorer.py +0 -550
  165. judgeval/scorers/judgeval_scorers/local_implementations/tool_correctness/__init__.py +0 -3
  166. judgeval/scorers/judgeval_scorers/local_implementations/tool_correctness/tool_correctness_scorer.py +0 -157
  167. judgeval/scorers/prompt_scorer.py +0 -439
  168. judgeval-0.0.11.dist-info/METADATA +0 -36
  169. judgeval-0.0.11.dist-info/RECORD +0 -84
  170. {judgeval-0.0.11.dist-info → judgeval-0.22.2.dist-info}/WHEEL +0 -0
  171. {judgeval-0.0.11.dist-info → judgeval-0.22.2.dist-info}/licenses/LICENSE.md +0 -0
@@ -0,0 +1,28 @@
1
+ import importlib.metadata
2
+ import httpx
3
+ import threading
4
+ from judgeval.logger import judgeval_logger
5
+ from judgeval.utils.decorators.use_once import use_once
6
+
7
+
8
+ @use_once
9
+ def check_latest_version(package_name: str = "judgeval"):
10
+ def _check():
11
+ try:
12
+ current_version = importlib.metadata.version(package_name)
13
+ response = httpx.get(
14
+ f"https://pypi.org/pypi/{package_name}/json", timeout=2
15
+ )
16
+ latest_version = response.json()["info"]["version"]
17
+
18
+ if current_version != latest_version:
19
+ judgeval_logger.warning(
20
+ f"UPDATE AVAILABLE: You are using '{package_name}=={current_version}', "
21
+ f"but the latest version is '{latest_version}'. While this version is still supported, "
22
+ f"we recommend upgrading to avoid potential issues or missing features: "
23
+ f"`pip install --upgrade {package_name}`"
24
+ )
25
+ except Exception:
26
+ pass
27
+
28
+ threading.Thread(target=_check, daemon=True).start()
@@ -0,0 +1,3 @@
1
+ # Wrapper Utilities
2
+
3
+ Ensure 100% test coverage for all files in this folder
@@ -0,0 +1,15 @@
1
+ from .immutable_wrap_sync import immutable_wrap_sync
2
+ from .immutable_wrap_async import immutable_wrap_async
3
+ from .immutable_wrap_sync_iterator import immutable_wrap_sync_iterator
4
+ from .immutable_wrap_async_iterator import immutable_wrap_async_iterator
5
+ from .mutable_wrap_sync import mutable_wrap_sync
6
+ from .mutable_wrap_async import mutable_wrap_async
7
+
8
+ __all__ = [
9
+ "immutable_wrap_sync",
10
+ "immutable_wrap_async",
11
+ "immutable_wrap_sync_iterator",
12
+ "immutable_wrap_async_iterator",
13
+ "mutable_wrap_sync",
14
+ "mutable_wrap_async",
15
+ ]
@@ -0,0 +1,74 @@
1
+ from functools import wraps
2
+ from typing import (
3
+ Awaitable,
4
+ Callable,
5
+ TypeVar,
6
+ Any,
7
+ Dict,
8
+ ParamSpec,
9
+ Concatenate,
10
+ )
11
+
12
+ from judgeval.utils.decorators.dont_throw import dont_throw
13
+
14
+ P = ParamSpec("P")
15
+ R = TypeVar("R")
16
+ Ctx = Dict[str, Any]
17
+
18
+
19
+ def _void_pre_hook(ctx: Ctx, *args: Any, **kwargs: Any) -> None:
20
+ pass
21
+
22
+
23
+ def _void_post_hook(ctx: Ctx, result: Any) -> None:
24
+ pass
25
+
26
+
27
+ def _void_error_hook(ctx: Ctx, error: Exception) -> None:
28
+ pass
29
+
30
+
31
+ def _void_finally_hook(ctx: Ctx) -> None:
32
+ pass
33
+
34
+
35
+ def immutable_wrap_async(
36
+ func: Callable[P, Awaitable[R]],
37
+ /,
38
+ *,
39
+ pre_hook: Callable[Concatenate[Ctx, P], None] = _void_pre_hook,
40
+ post_hook: Callable[[Ctx, R], None] = _void_post_hook,
41
+ error_hook: Callable[[Ctx, Exception], None] = _void_error_hook,
42
+ finally_hook: Callable[[Ctx], None] = _void_finally_hook,
43
+ ) -> Callable[P, Awaitable[R]]:
44
+ """
45
+ Wraps an async function with lifecycle hooks.
46
+
47
+ - pre_hook: called before func with (ctx, *args, **kwargs) matching func's signature
48
+ - post_hook: called after successful func execution with (ctx, result)
49
+ - error_hook: called if func raises an exception with (ctx, error)
50
+ - finally_hook: called in finally block with (ctx)
51
+
52
+ The wrapped function's result is returned unchanged, and exceptions are re-raised.
53
+ """
54
+
55
+ pre_hook = dont_throw(pre_hook)
56
+ post_hook = dont_throw(post_hook)
57
+ error_hook = dont_throw(error_hook)
58
+ finally_hook = dont_throw(finally_hook)
59
+
60
+ @wraps(func)
61
+ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
62
+ ctx: Ctx = {}
63
+ pre_hook(ctx, *args, **kwargs)
64
+ try:
65
+ result = await func(*args, **kwargs)
66
+ post_hook(ctx, result)
67
+ return result
68
+ except Exception as e:
69
+ error_hook(ctx, e)
70
+ raise
71
+ finally:
72
+ finally_hook(ctx)
73
+
74
+ return wrapper
@@ -0,0 +1,84 @@
1
+ from functools import wraps
2
+ from typing import (
3
+ Callable,
4
+ TypeVar,
5
+ Any,
6
+ Dict,
7
+ Mapping,
8
+ ParamSpec,
9
+ AsyncIterator,
10
+ Concatenate,
11
+ )
12
+
13
+ from judgeval.utils.decorators.dont_throw import dont_throw
14
+
15
+ P = ParamSpec("P")
16
+ Y = TypeVar("Y")
17
+ Ctx = Dict[str, Any]
18
+ ImmCtx = Mapping[str, Any]
19
+
20
+
21
+ def _void_pre_hook(ctx: Ctx, *args: Any, **kwargs: Any) -> None:
22
+ pass
23
+
24
+
25
+ def _void_yield_hook(ctx: Ctx, value: Any) -> None:
26
+ pass
27
+
28
+
29
+ def _void_post_hook(ctx: Ctx) -> None:
30
+ pass
31
+
32
+
33
+ def _void_error_hook(ctx: Ctx, error: Exception) -> None:
34
+ pass
35
+
36
+
37
+ def _void_finally_hook(ctx: Ctx) -> None:
38
+ pass
39
+
40
+
41
+ def immutable_wrap_async_iterator(
42
+ func: Callable[P, AsyncIterator[Y]],
43
+ /,
44
+ *,
45
+ pre_hook: Callable[Concatenate[Ctx, P], None] = _void_pre_hook,
46
+ yield_hook: Callable[[Ctx, Y], None] = _void_yield_hook,
47
+ post_hook: Callable[[Ctx], None] = _void_post_hook,
48
+ error_hook: Callable[[Ctx, Exception], None] = _void_error_hook,
49
+ finally_hook: Callable[[Ctx], None] = _void_finally_hook,
50
+ ) -> Callable[P, AsyncIterator[Y]]:
51
+ """
52
+ Wraps an async iterator function with lifecycle hooks.
53
+
54
+ - pre_hook: called when iterator function is invoked with (ctx, *args, **kwargs) matching func's signature
55
+ - yield_hook: called after each yield with (ctx, yielded_value)
56
+ - post_hook: called when iterator completes successfully with (ctx)
57
+ - error_hook: called if iterator raises an exception with (ctx, error)
58
+ - finally_hook: called when iterator closes with (ctx)
59
+
60
+ The wrapped iterator yields values unchanged, and exceptions are re-raised.
61
+ """
62
+
63
+ pre_hook = dont_throw(pre_hook)
64
+ yield_hook = dont_throw(yield_hook)
65
+ post_hook = dont_throw(post_hook)
66
+ error_hook = dont_throw(error_hook)
67
+ finally_hook = dont_throw(finally_hook)
68
+
69
+ @wraps(func)
70
+ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> AsyncIterator[Y]:
71
+ ctx: Ctx = {}
72
+ pre_hook(ctx, *args, **kwargs)
73
+ try:
74
+ async for value in func(*args, **kwargs):
75
+ yield_hook(ctx, value)
76
+ yield value
77
+ post_hook(ctx)
78
+ except Exception as e:
79
+ error_hook(ctx, e)
80
+ raise
81
+ finally:
82
+ finally_hook(ctx)
83
+
84
+ return wrapper
@@ -0,0 +1,66 @@
1
+ from functools import wraps
2
+ from typing import Callable, TypeVar, Any, Dict, ParamSpec, Concatenate
3
+
4
+ from judgeval.utils.decorators.dont_throw import dont_throw
5
+
6
+ P = ParamSpec("P")
7
+ R = TypeVar("R")
8
+ Ctx = Dict[str, Any]
9
+
10
+
11
+ def _void_pre_hook(ctx: Ctx, *args: Any, **kwargs: Any) -> None:
12
+ pass
13
+
14
+
15
+ def _void_post_hook(ctx: Ctx, result: Any) -> None:
16
+ pass
17
+
18
+
19
+ def _void_error_hook(ctx: Ctx, error: Exception) -> None:
20
+ pass
21
+
22
+
23
+ def _void_finally_hook(ctx: Ctx) -> None:
24
+ pass
25
+
26
+
27
+ def immutable_wrap_sync(
28
+ func: Callable[P, R],
29
+ /,
30
+ *,
31
+ pre_hook: Callable[Concatenate[Ctx, P], None] = _void_pre_hook,
32
+ post_hook: Callable[[Ctx, R], None] = _void_post_hook,
33
+ error_hook: Callable[[Ctx, Exception], None] = _void_error_hook,
34
+ finally_hook: Callable[[Ctx], None] = _void_finally_hook,
35
+ ) -> Callable[P, R]:
36
+ """
37
+ Wraps a function with lifecycle hooks.
38
+
39
+ - pre_hook: called before func with (ctx, *args, **kwargs) matching func's signature
40
+ - post_hook: called after successful func execution with (ctx, result)
41
+ - error_hook: called if func raises an exception with (ctx, error)
42
+ - finally_hook: called in finally block with (ctx)
43
+
44
+ The wrapped function's result is returned unchanged, and exceptions are re-raised.
45
+ """
46
+
47
+ pre_hook = dont_throw(pre_hook)
48
+ post_hook = dont_throw(post_hook)
49
+ error_hook = dont_throw(error_hook)
50
+ finally_hook = dont_throw(finally_hook)
51
+
52
+ @wraps(func)
53
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
54
+ ctx: Ctx = {}
55
+ pre_hook(ctx, *args, **kwargs)
56
+ try:
57
+ result = func(*args, **kwargs)
58
+ post_hook(ctx, result)
59
+ return result
60
+ except Exception as e:
61
+ error_hook(ctx, e)
62
+ raise
63
+ finally:
64
+ finally_hook(ctx)
65
+
66
+ return wrapper
@@ -0,0 +1,84 @@
1
+ from functools import wraps
2
+ from typing import (
3
+ Callable,
4
+ TypeVar,
5
+ Any,
6
+ Dict,
7
+ Mapping,
8
+ ParamSpec,
9
+ Iterator,
10
+ Concatenate,
11
+ )
12
+
13
+ from judgeval.utils.decorators.dont_throw import dont_throw
14
+
15
+ P = ParamSpec("P")
16
+ Y = TypeVar("Y")
17
+ Ctx = Dict[str, Any]
18
+ ImmCtx = Mapping[str, Any]
19
+
20
+
21
+ def _void_pre_hook(ctx: Ctx, *args: Any, **kwargs: Any) -> None:
22
+ pass
23
+
24
+
25
+ def _void_yield_hook(ctx: Ctx, value: Any) -> None:
26
+ pass
27
+
28
+
29
+ def _void_post_hook(ctx: Ctx) -> None:
30
+ pass
31
+
32
+
33
+ def _void_error_hook(ctx: Ctx, error: Exception) -> None:
34
+ pass
35
+
36
+
37
+ def _void_finally_hook(ctx: Ctx) -> None:
38
+ pass
39
+
40
+
41
+ def immutable_wrap_sync_iterator(
42
+ func: Callable[P, Iterator[Y]],
43
+ /,
44
+ *,
45
+ pre_hook: Callable[Concatenate[Ctx, P], None] = _void_pre_hook,
46
+ yield_hook: Callable[[Ctx, Y], None] = _void_yield_hook,
47
+ post_hook: Callable[[Ctx], None] = _void_post_hook,
48
+ error_hook: Callable[[Ctx, Exception], None] = _void_error_hook,
49
+ finally_hook: Callable[[Ctx], None] = _void_finally_hook,
50
+ ) -> Callable[P, Iterator[Y]]:
51
+ """
52
+ Wraps an iterator function with lifecycle hooks.
53
+
54
+ - pre_hook: called when iterator function is invoked with (ctx, *args, **kwargs) matching func's signature
55
+ - yield_hook: called after each yield with (ctx, yielded_value)
56
+ - post_hook: called when iterator completes successfully with (ctx)
57
+ - error_hook: called if iterator raises an exception with (ctx, error)
58
+ - finally_hook: called when iterator closes with (ctx)
59
+
60
+ The wrapped iterator yields values unchanged, and exceptions are re-raised.
61
+ """
62
+
63
+ pre_hook = dont_throw(pre_hook)
64
+ yield_hook = dont_throw(yield_hook)
65
+ post_hook = dont_throw(post_hook)
66
+ error_hook = dont_throw(error_hook)
67
+ finally_hook = dont_throw(finally_hook)
68
+
69
+ @wraps(func)
70
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> Iterator[Y]:
71
+ ctx: Ctx = {}
72
+ pre_hook(ctx, *args, **kwargs)
73
+ try:
74
+ for value in func(*args, **kwargs):
75
+ yield_hook(ctx, value)
76
+ yield value
77
+ post_hook(ctx)
78
+ except Exception as e:
79
+ error_hook(ctx, e)
80
+ raise
81
+ finally:
82
+ finally_hook(ctx)
83
+
84
+ return wrapper
@@ -0,0 +1,67 @@
1
+ from functools import wraps
2
+ from typing import Awaitable, Callable, TypeVar, Any, Dict, ParamSpec, Concatenate
3
+
4
+ from judgeval.utils.decorators.dont_throw import dont_throw
5
+ from judgeval.utils.wrappers.utils import identity_on_throw
6
+
7
+ P = ParamSpec("P")
8
+ R = TypeVar("R")
9
+ Ctx = Dict[str, Any]
10
+
11
+
12
+ def mutable_wrap_async(
13
+ func: Callable[P, Awaitable[R]],
14
+ /,
15
+ *,
16
+ pre_hook: Callable[Concatenate[Ctx, P], None] | None = None,
17
+ mutate_args_hook: Callable[[Ctx, tuple[Any, ...]], tuple[Any, ...]] | None = None,
18
+ mutate_kwargs_hook: Callable[[Ctx, dict[str, Any]], dict[str, Any]] | None = None,
19
+ post_hook: Callable[[Ctx, R], None] | None = None,
20
+ mutate_hook: Callable[[Ctx, R], R] | None = None,
21
+ error_hook: Callable[[Ctx, Exception], None] | None = None,
22
+ finally_hook: Callable[[Ctx], None] | None = None,
23
+ ) -> Callable[P, Awaitable[R]]:
24
+ """
25
+ Wraps an async function with lifecycle hooks that can mutate args, kwargs, and result.
26
+
27
+ - pre_hook: called before func with (ctx, *args, **kwargs) matching func's signature
28
+ - mutate_args_hook: called after pre_hook with (ctx, args), returns potentially modified args
29
+ - mutate_kwargs_hook: called after pre_hook with (ctx, kwargs), returns potentially modified kwargs
30
+ - post_hook: called after successful func execution with (ctx, result)
31
+ - mutate_hook: called after post_hook with (ctx, result), returns potentially modified result
32
+ - error_hook: called if func raises an exception with (ctx, error)
33
+ - finally_hook: called in finally block with (ctx)
34
+
35
+ The mutate hooks can transform args/kwargs/result. Exceptions are re-raised.
36
+ """
37
+
38
+ safe_pre_hook = dont_throw(pre_hook) if pre_hook else (lambda ctx, *a, **kw: None)
39
+ safe_post_hook = dont_throw(post_hook) if post_hook else (lambda ctx, r: None)
40
+ safe_error_hook = dont_throw(error_hook) if error_hook else (lambda ctx, e: None)
41
+ safe_finally_hook = dont_throw(finally_hook) if finally_hook else (lambda ctx: None)
42
+
43
+ safe_mutate_args = identity_on_throw(mutate_args_hook) if mutate_args_hook else None
44
+ safe_mutate_kwargs = (
45
+ identity_on_throw(mutate_kwargs_hook) if mutate_kwargs_hook else None
46
+ )
47
+ safe_mutate_hook = identity_on_throw(mutate_hook) if mutate_hook else None
48
+
49
+ @wraps(func)
50
+ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
51
+ ctx: Ctx = {}
52
+ safe_pre_hook(ctx, *args, **kwargs)
53
+
54
+ final_args = safe_mutate_args(ctx, args) if safe_mutate_args else args
55
+ final_kwargs = safe_mutate_kwargs(ctx, kwargs) if safe_mutate_kwargs else kwargs
56
+
57
+ try:
58
+ result = await func(*final_args, **final_kwargs)
59
+ safe_post_hook(ctx, result)
60
+ return safe_mutate_hook(ctx, result) if safe_mutate_hook else result
61
+ except Exception as e:
62
+ safe_error_hook(ctx, e)
63
+ raise
64
+ finally:
65
+ safe_finally_hook(ctx)
66
+
67
+ return wrapper
@@ -0,0 +1,67 @@
1
+ from functools import wraps
2
+ from typing import Callable, TypeVar, Any, Dict, ParamSpec, Concatenate
3
+
4
+ from judgeval.utils.decorators.dont_throw import dont_throw
5
+ from judgeval.utils.wrappers.utils import identity_on_throw
6
+
7
+ P = ParamSpec("P")
8
+ R = TypeVar("R")
9
+ Ctx = Dict[str, Any]
10
+
11
+
12
+ def mutable_wrap_sync(
13
+ func: Callable[P, R],
14
+ /,
15
+ *,
16
+ pre_hook: Callable[Concatenate[Ctx, P], None] | None = None,
17
+ mutate_args_hook: Callable[[Ctx, tuple[Any, ...]], tuple[Any, ...]] | None = None,
18
+ mutate_kwargs_hook: Callable[[Ctx, dict[str, Any]], dict[str, Any]] | None = None,
19
+ post_hook: Callable[[Ctx, R], None] | None = None,
20
+ mutate_hook: Callable[[Ctx, R], R] | None = None,
21
+ error_hook: Callable[[Ctx, Exception], None] | None = None,
22
+ finally_hook: Callable[[Ctx], None] | None = None,
23
+ ) -> Callable[P, R]:
24
+ """
25
+ Wraps a function with lifecycle hooks that can mutate args, kwargs, and result.
26
+
27
+ - pre_hook: called before func with (ctx, *args, **kwargs) matching func's signature
28
+ - mutate_args_hook: called after pre_hook with (ctx, args), returns potentially modified args
29
+ - mutate_kwargs_hook: called after pre_hook with (ctx, kwargs), returns potentially modified kwargs
30
+ - post_hook: called after successful func execution with (ctx, result)
31
+ - mutate_hook: called after post_hook with (ctx, result), returns potentially modified result
32
+ - error_hook: called if func raises an exception with (ctx, error)
33
+ - finally_hook: called in finally block with (ctx)
34
+
35
+ The mutate hooks can transform args/kwargs/result. Exceptions are re-raised.
36
+ """
37
+
38
+ safe_pre_hook = dont_throw(pre_hook) if pre_hook else (lambda ctx, *a, **kw: None)
39
+ safe_post_hook = dont_throw(post_hook) if post_hook else (lambda ctx, r: None)
40
+ safe_error_hook = dont_throw(error_hook) if error_hook else (lambda ctx, e: None)
41
+ safe_finally_hook = dont_throw(finally_hook) if finally_hook else (lambda ctx: None)
42
+
43
+ safe_mutate_args = identity_on_throw(mutate_args_hook) if mutate_args_hook else None
44
+ safe_mutate_kwargs = (
45
+ identity_on_throw(mutate_kwargs_hook) if mutate_kwargs_hook else None
46
+ )
47
+ safe_mutate_hook = identity_on_throw(mutate_hook) if mutate_hook else None
48
+
49
+ @wraps(func)
50
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
51
+ ctx: Ctx = {}
52
+ safe_pre_hook(ctx, *args, **kwargs)
53
+
54
+ final_args = safe_mutate_args(ctx, args) if safe_mutate_args else args
55
+ final_kwargs = safe_mutate_kwargs(ctx, kwargs) if safe_mutate_kwargs else kwargs
56
+
57
+ try:
58
+ result = func(*final_args, **final_kwargs)
59
+ safe_post_hook(ctx, result)
60
+ return safe_mutate_hook(ctx, result) if safe_mutate_hook else result
61
+ except Exception as e:
62
+ safe_error_hook(ctx, e)
63
+ raise
64
+ finally:
65
+ safe_finally_hook(ctx)
66
+
67
+ return wrapper
File without changes
@@ -0,0 +1,35 @@
1
+ from typing import Callable, TypeVar, ParamSpec
2
+
3
+ from judgeval.logger import judgeval_logger
4
+
5
+ P = ParamSpec("P")
6
+ T = TypeVar("T")
7
+
8
+
9
+ def identity_on_throw(func: Callable[P, T]) -> Callable[P, T]:
10
+ """
11
+ Wraps a mutation function to preserve the last argument (identity) if it fails.
12
+
13
+ This is used for mutation hooks where we want to fall back to the original value
14
+ if the mutation fails, ensuring the wrapper is always safe and non-breaking.
15
+
16
+ Args:
17
+ func: A mutation function where the last positional argument is the value to mutate.
18
+ The function should return a potentially modified version of this value.
19
+
20
+ Returns:
21
+ A wrapped function that returns the last positional argument (original value) if mutation fails
22
+ """
23
+
24
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
25
+ try:
26
+ return func(*args, **kwargs)
27
+ except Exception as e:
28
+ judgeval_logger.debug(
29
+ f"[Caught] Mutation function {func.__name__} failed, using identity",
30
+ exc_info=e,
31
+ )
32
+ # The last positional argument is always the value to mutate
33
+ return args[-1] # type: ignore[return-value]
34
+
35
+ return wrapper
judgeval/version.py ADDED
@@ -0,0 +1,5 @@
1
+ __version__ = "0.22.2"
2
+
3
+
4
+ def get_version() -> str:
5
+ return __version__
judgeval/warnings.py ADDED
@@ -0,0 +1,4 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ class JudgmentWarning(Warning): ...