rakam-eval-sdk 0.1.16__py3-none-any.whl → 0.1.16rc1__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.
- rakam_eval_sdk/cli.py +109 -7
- rakam_eval_sdk/decorators.py +44 -0
- rakam_eval_sdk/utils/decorator_utils.py +69 -0
- {rakam_eval_sdk-0.1.16.dist-info → rakam_eval_sdk-0.1.16rc1.dist-info}/METADATA +2 -1
- rakam_eval_sdk-0.1.16rc1.dist-info/RECORD +10 -0
- rakam_eval_sdk-0.1.16rc1.dist-info/entry_points.txt +3 -0
- rakam_eval_sdk-0.1.16.dist-info/RECORD +0 -8
- rakam_eval_sdk-0.1.16.dist-info/entry_points.txt +0 -3
- {rakam_eval_sdk-0.1.16.dist-info → rakam_eval_sdk-0.1.16rc1.dist-info}/WHEEL +0 -0
rakam_eval_sdk/cli.py
CHANGED
|
@@ -1,17 +1,119 @@
|
|
|
1
1
|
# cli.py
|
|
2
|
-
import typer
|
|
3
2
|
from pathlib import Path
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from rakam_eval_sdk.utils.decorator_utils import find_decorated_functions, load_module_from_path
|
|
7
|
+
from rakam_eval_sdk.decorators import eval_run
|
|
8
|
+
app = typer.Typer(help="CLI tools for evaluation utilities")
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
@app.command()
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
def find_eval_run_by_name(
|
|
13
|
+
directory: Path = typer.Argument(
|
|
14
|
+
Path("./eval"),
|
|
15
|
+
exists=True,
|
|
16
|
+
file_okay=False,
|
|
17
|
+
dir_okay=True,
|
|
18
|
+
help="Directory to scan (default: ./eval)",
|
|
19
|
+
),
|
|
20
|
+
recursive: bool = typer.Option(
|
|
21
|
+
False,
|
|
22
|
+
"--recursive",
|
|
23
|
+
"-r",
|
|
24
|
+
help="Recursively search for Python files",
|
|
25
|
+
),
|
|
26
|
+
):
|
|
27
|
+
"""
|
|
28
|
+
Find functions decorated with @track.
|
|
29
|
+
"""
|
|
30
|
+
TARGET_DECORATOR = eval_run.__name__
|
|
31
|
+
files = (
|
|
32
|
+
directory.rglob("*.py")
|
|
33
|
+
if recursive
|
|
34
|
+
else directory.glob("*.py")
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
found = False
|
|
38
|
+
|
|
39
|
+
for file in sorted(files):
|
|
40
|
+
functions = find_decorated_functions(file, TARGET_DECORATOR)
|
|
41
|
+
for fn in functions:
|
|
42
|
+
found = True
|
|
43
|
+
typer.echo(f"{file}:{fn}")
|
|
44
|
+
|
|
45
|
+
if not found:
|
|
46
|
+
typer.echo(f"No @{TARGET_DECORATOR} functions found.")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@app.command("run")
|
|
50
|
+
def run_eval_runs(
|
|
51
|
+
directory: Path = typer.Argument(
|
|
52
|
+
Path("./eval"),
|
|
53
|
+
exists=True,
|
|
54
|
+
file_okay=False,
|
|
55
|
+
dir_okay=True,
|
|
56
|
+
help="Directory to scan (default: ./eval)",
|
|
57
|
+
),
|
|
58
|
+
recursive: bool = typer.Option(
|
|
59
|
+
False,
|
|
60
|
+
"-r",
|
|
61
|
+
"--recursive",
|
|
62
|
+
help="Recursively search for Python files",
|
|
63
|
+
),
|
|
64
|
+
dry_run: bool = typer.Option(
|
|
65
|
+
False,
|
|
66
|
+
"--dry-run",
|
|
67
|
+
help="Only list functions without executing them",
|
|
68
|
+
),
|
|
69
|
+
):
|
|
70
|
+
"""
|
|
71
|
+
Find and execute all functions decorated with @eval_run.
|
|
72
|
+
"""
|
|
73
|
+
files = (
|
|
74
|
+
directory.rglob("*.py")
|
|
75
|
+
if recursive
|
|
76
|
+
else directory.glob("*.py")
|
|
77
|
+
)
|
|
78
|
+
TARGET_DECORATOR = eval_run.__name__
|
|
79
|
+
|
|
80
|
+
executed_any = False
|
|
81
|
+
|
|
82
|
+
for file in sorted(files):
|
|
83
|
+
functions = find_decorated_functions(file, TARGET_DECORATOR)
|
|
84
|
+
if not functions:
|
|
85
|
+
continue
|
|
86
|
+
|
|
87
|
+
typer.echo(f"\n📄 {file}")
|
|
88
|
+
|
|
89
|
+
module = None
|
|
90
|
+
if not dry_run:
|
|
91
|
+
try:
|
|
92
|
+
module = load_module_from_path(file)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
typer.echo(f" ❌ Failed to import module: {e}")
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
for fn_name in functions:
|
|
98
|
+
typer.echo(f" ▶ {fn_name}")
|
|
99
|
+
|
|
100
|
+
if dry_run:
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
func = getattr(module, fn_name)
|
|
105
|
+
func() # <-- actual execution
|
|
106
|
+
executed_any = True
|
|
107
|
+
except Exception as e:
|
|
108
|
+
typer.echo(f" ❌ Execution failed: {e}")
|
|
109
|
+
|
|
110
|
+
if not executed_any and not dry_run:
|
|
111
|
+
typer.echo("\nNo @eval_run functions executed.")
|
|
14
112
|
|
|
15
113
|
|
|
16
114
|
def main():
|
|
17
115
|
app()
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
if __name__ == "__main__":
|
|
119
|
+
main()
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
import time
|
|
3
|
+
import os
|
|
4
|
+
import psutil
|
|
5
|
+
import functools
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def eval_run(*dargs, **dkwargs):
|
|
9
|
+
def wrapper(func):
|
|
10
|
+
@functools.wraps(func)
|
|
11
|
+
def inner(*args, **kwargs):
|
|
12
|
+
process = psutil.Process(os.getpid())
|
|
13
|
+
|
|
14
|
+
# Start metrics
|
|
15
|
+
start_time = time.perf_counter()
|
|
16
|
+
start_cpu = process.cpu_times()
|
|
17
|
+
start_mem = process.memory_info().rss
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
result = func(*args, **kwargs)
|
|
21
|
+
return result
|
|
22
|
+
finally:
|
|
23
|
+
# End metrics
|
|
24
|
+
end_time = time.perf_counter()
|
|
25
|
+
end_cpu = process.cpu_times()
|
|
26
|
+
end_mem = process.memory_info().rss
|
|
27
|
+
|
|
28
|
+
elapsed = end_time - start_time
|
|
29
|
+
cpu_used = (
|
|
30
|
+
(end_cpu.user + end_cpu.system)
|
|
31
|
+
- (start_cpu.user + start_cpu.system)
|
|
32
|
+
)
|
|
33
|
+
mem_diff_mb = (end_mem - start_mem) / (1024 * 1024)
|
|
34
|
+
|
|
35
|
+
print(
|
|
36
|
+
f"[eval_run] {func.__module__}.{func.__name__} | "
|
|
37
|
+
f"time={elapsed:.4f}s | "
|
|
38
|
+
f"cpu={cpu_used:.4f}s | "
|
|
39
|
+
f"mem_delta={mem_diff_mb:.2f}MB"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return inner
|
|
43
|
+
|
|
44
|
+
return wrapper
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
import importlib
|
|
3
|
+
import importlib.util
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from types import ModuleType
|
|
7
|
+
from typing import Callable, Iterable, List, Tuple
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DecoratedFunctionVisitor(ast.NodeVisitor):
|
|
11
|
+
def __init__(self, decorator_name: str):
|
|
12
|
+
self.decorator_name = decorator_name
|
|
13
|
+
self.results: List[str] = []
|
|
14
|
+
|
|
15
|
+
def visit_FunctionDef(self, node: ast.FunctionDef):
|
|
16
|
+
for deco in node.decorator_list:
|
|
17
|
+
if self._matches(deco):
|
|
18
|
+
self.results.append(node.name)
|
|
19
|
+
self.generic_visit(node)
|
|
20
|
+
|
|
21
|
+
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef):
|
|
22
|
+
for deco in node.decorator_list:
|
|
23
|
+
if self._matches(deco):
|
|
24
|
+
self.results.append(node.name)
|
|
25
|
+
self.generic_visit(node)
|
|
26
|
+
|
|
27
|
+
def _matches(self, deco: ast.expr) -> bool:
|
|
28
|
+
# @deco
|
|
29
|
+
if isinstance(deco, ast.Name):
|
|
30
|
+
return deco.id == self.decorator_name
|
|
31
|
+
|
|
32
|
+
# @module.deco
|
|
33
|
+
if isinstance(deco, ast.Attribute):
|
|
34
|
+
return deco.attr == self.decorator_name
|
|
35
|
+
|
|
36
|
+
# @deco(...)
|
|
37
|
+
if isinstance(deco, ast.Call):
|
|
38
|
+
return self._matches(deco.func)
|
|
39
|
+
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def find_decorated_functions(
|
|
44
|
+
file_path: Path,
|
|
45
|
+
decorator_name: str,
|
|
46
|
+
) -> List[str]:
|
|
47
|
+
tree = ast.parse(file_path.read_text(encoding="utf-8"))
|
|
48
|
+
visitor = DecoratedFunctionVisitor(decorator_name)
|
|
49
|
+
visitor.visit(tree)
|
|
50
|
+
return visitor.results
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def load_module_from_path(file_path: Path) -> ModuleType:
|
|
54
|
+
spec = importlib.util.spec_from_file_location(file_path.stem, file_path)
|
|
55
|
+
if spec is None or spec.loader is None:
|
|
56
|
+
raise ImportError(f"Cannot import {file_path}")
|
|
57
|
+
module = importlib.util.module_from_spec(spec)
|
|
58
|
+
spec.loader.exec_module(module)
|
|
59
|
+
return module
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_function(module: ModuleType, function_name: str) -> Callable:
|
|
66
|
+
func = getattr(module, function_name, None)
|
|
67
|
+
if func is None:
|
|
68
|
+
raise AttributeError(f"{function_name} not found in {module.__name__}")
|
|
69
|
+
return func
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: rakam-eval-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16rc1
|
|
4
4
|
Summary: Evaluation Framework SDK
|
|
5
5
|
Author: Mohamed Bachar Touil
|
|
6
6
|
License: MIT
|
|
7
|
+
Requires-Dist: psutil>=7.2.1
|
|
7
8
|
Requires-Dist: pydantic>=2.10.6
|
|
8
9
|
Requires-Dist: requests
|
|
9
10
|
Requires-Dist: typer>=0.20.1
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
rakam_eval_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
rakam_eval_sdk/cli.py,sha256=9BHZte3cS1LWL0_dOVEtws9xIhdw0yORW93Dm1uDxDw,2876
|
|
3
|
+
rakam_eval_sdk/client.py,sha256=q-Y11maLVKaEnq4OSyFCqrP3JgFS1xpyp9-bZhFssIA,7123
|
|
4
|
+
rakam_eval_sdk/decorators.py,sha256=ZEcZb2KUsPrtx-Guc7tYN9MVCMxIQ83yhiJxKE1fjdw,1262
|
|
5
|
+
rakam_eval_sdk/schema.py,sha256=MQfF0SEHf2wzeXJNTsMs-yDbN0vZJQbN_crfpPXsTk8,3467
|
|
6
|
+
rakam_eval_sdk/utils/decorator_utils.py,sha256=hCC4F7v3KjGSDt2NUXfDsbBTMPzlG6wMzZVdR_wWn14,2048
|
|
7
|
+
rakam_eval_sdk-0.1.16rc1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
8
|
+
rakam_eval_sdk-0.1.16rc1.dist-info/entry_points.txt,sha256=tNhwmM_UGELb3h0zOfgCrtTheUkP-k8jGv0rTOfRSps,56
|
|
9
|
+
rakam_eval_sdk-0.1.16rc1.dist-info/METADATA,sha256=DRKzVNNF426R3ipnpG8Xr5LXKLTY4Ar9WdPIxe6hjzI,5991
|
|
10
|
+
rakam_eval_sdk-0.1.16rc1.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
rakam_eval_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
rakam_eval_sdk/cli.py,sha256=dn1KXh-_VLpIvLFHnpHPfAL33ICoAJ9Y2iCOikkJcxY,277
|
|
3
|
-
rakam_eval_sdk/client.py,sha256=q-Y11maLVKaEnq4OSyFCqrP3JgFS1xpyp9-bZhFssIA,7123
|
|
4
|
-
rakam_eval_sdk/schema.py,sha256=MQfF0SEHf2wzeXJNTsMs-yDbN0vZJQbN_crfpPXsTk8,3467
|
|
5
|
-
rakam_eval_sdk-0.1.16.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
6
|
-
rakam_eval_sdk-0.1.16.dist-info/entry_points.txt,sha256=NzE2wDRB4Kt-TblkjSD37abcfP4B5STBOyygEhGTLdU,51
|
|
7
|
-
rakam_eval_sdk-0.1.16.dist-info/METADATA,sha256=s7N_RsRR87-6aQhNmCnuDeMDrL6ZOm0vr7iR2cS5FwU,5959
|
|
8
|
-
rakam_eval_sdk-0.1.16.dist-info/RECORD,,
|
|
File without changes
|