langfun 0.1.2.dev202501080804__py3-none-any.whl → 0.1.2.dev202501240804__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.
- langfun/core/__init__.py +1 -6
- langfun/core/coding/python/__init__.py +5 -11
- langfun/core/coding/python/correction.py +4 -7
- langfun/core/coding/python/correction_test.py +2 -3
- langfun/core/coding/python/execution.py +22 -211
- langfun/core/coding/python/execution_test.py +11 -90
- langfun/core/coding/python/generation.py +3 -2
- langfun/core/coding/python/generation_test.py +2 -2
- langfun/core/coding/python/parsing.py +108 -194
- langfun/core/coding/python/parsing_test.py +2 -105
- langfun/core/component.py +11 -273
- langfun/core/component_test.py +2 -29
- langfun/core/concurrent.py +187 -82
- langfun/core/concurrent_test.py +28 -19
- langfun/core/console.py +7 -3
- langfun/core/eval/base.py +2 -3
- langfun/core/eval/v2/evaluation.py +3 -1
- langfun/core/eval/v2/reporting.py +8 -4
- langfun/core/language_model.py +84 -8
- langfun/core/language_model_test.py +84 -29
- langfun/core/llms/__init__.py +46 -11
- langfun/core/llms/anthropic.py +1 -123
- langfun/core/llms/anthropic_test.py +0 -48
- langfun/core/llms/deepseek.py +117 -0
- langfun/core/llms/deepseek_test.py +61 -0
- langfun/core/llms/gemini.py +1 -1
- langfun/core/llms/groq.py +12 -99
- langfun/core/llms/groq_test.py +31 -137
- langfun/core/llms/llama_cpp.py +17 -54
- langfun/core/llms/llama_cpp_test.py +2 -34
- langfun/core/llms/openai.py +9 -147
- langfun/core/llms/openai_compatible.py +179 -0
- langfun/core/llms/openai_compatible_test.py +495 -0
- langfun/core/llms/openai_test.py +13 -423
- langfun/core/llms/rest_test.py +1 -1
- langfun/core/llms/vertexai.py +387 -18
- langfun/core/llms/vertexai_test.py +52 -0
- langfun/core/message_test.py +3 -3
- langfun/core/modalities/mime.py +8 -0
- langfun/core/modalities/mime_test.py +19 -4
- langfun/core/modality_test.py +0 -1
- langfun/core/structured/mapping.py +13 -13
- langfun/core/structured/mapping_test.py +2 -2
- langfun/core/structured/schema.py +16 -8
- langfun/core/structured/schema_generation.py +1 -1
- {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/METADATA +13 -2
- {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/RECORD +50 -52
- {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/WHEEL +1 -1
- langfun/core/coding/python/errors.py +0 -108
- langfun/core/coding/python/errors_test.py +0 -99
- langfun/core/coding/python/permissions.py +0 -90
- langfun/core/coding/python/permissions_test.py +0 -86
- langfun/core/text_formatting.py +0 -168
- langfun/core/text_formatting_test.py +0 -65
- {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/LICENSE +0 -0
- {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/top_level.txt +0 -0
langfun/core/__init__.py
CHANGED
@@ -72,16 +72,11 @@ from langfun.core.sampling import random_sample
|
|
72
72
|
|
73
73
|
# Concurrent execute a function with parallel inputs with inheriting current
|
74
74
|
# context's defaults and overrides.
|
75
|
+
from langfun.core.concurrent import RetryEntry
|
75
76
|
from langfun.core.concurrent import concurrent_execute
|
76
77
|
from langfun.core.concurrent import concurrent_map
|
77
|
-
from langfun.core.concurrent import with_context_access
|
78
78
|
from langfun.core.concurrent import with_retry
|
79
79
|
|
80
|
-
# Utility libraries for text formatting.
|
81
|
-
from langfun.core.text_formatting import colored
|
82
|
-
from langfun.core.text_formatting import colored_print as print # pylint: disable=redefined-builtin
|
83
|
-
from langfun.core.text_formatting import colored_template
|
84
|
-
|
85
80
|
# Interface for natural language formattable.
|
86
81
|
from langfun.core.natural_language import NaturalLanguageFormattable
|
87
82
|
|
@@ -16,19 +16,13 @@
|
|
16
16
|
# pylint: disable=g-bad-import-order
|
17
17
|
# pylint: disable=g-importing-member
|
18
18
|
|
19
|
-
from
|
20
|
-
|
21
|
-
from langfun.core.coding.python.
|
22
|
-
from langfun.core.coding.python.permissions import permission
|
23
|
-
from langfun.core.coding.python.permissions import get_permission
|
24
|
-
|
25
|
-
from langfun.core.coding.python.parsing import PythonCodeParser
|
26
|
-
|
19
|
+
# Expose from `lf.coding` as aliases for `pg.coding` for backward compatibility.
|
20
|
+
from langfun.core.coding.python.execution import CodeError
|
21
|
+
from langfun.core.coding.python.execution import CodePermission
|
27
22
|
from langfun.core.coding.python.execution import context
|
28
|
-
|
23
|
+
|
24
|
+
from langfun.core.coding.python.parsing import clean
|
29
25
|
from langfun.core.coding.python.execution import evaluate
|
30
|
-
from langfun.core.coding.python.execution import sandbox_call
|
31
|
-
from langfun.core.coding.python.execution import call
|
32
26
|
from langfun.core.coding.python.execution import run
|
33
27
|
|
34
28
|
from langfun.core.coding.python.generation import PythonCode
|
@@ -14,7 +14,6 @@
|
|
14
14
|
"""Python code error correction."""
|
15
15
|
from typing import Any
|
16
16
|
import langfun.core as lf
|
17
|
-
from langfun.core.coding.python import errors
|
18
17
|
from langfun.core.coding.python import execution
|
19
18
|
import pyglove as pg
|
20
19
|
|
@@ -125,7 +124,7 @@ def run_with_correction(
|
|
125
124
|
correction = querying.query(
|
126
125
|
CodeWithError(code=code, error=error), CorrectedCode, lm=lm, autofix=0
|
127
126
|
)
|
128
|
-
except
|
127
|
+
except pg.coding.CodeError:
|
129
128
|
break
|
130
129
|
|
131
130
|
code = correction.corrected_code
|
@@ -133,7 +132,7 @@ def run_with_correction(
|
|
133
132
|
if error is None:
|
134
133
|
return (result, code) if returns_code else result
|
135
134
|
|
136
|
-
raise
|
135
|
+
raise pg.coding.CodeError(
|
137
136
|
code,
|
138
137
|
RuntimeError(
|
139
138
|
f"Cannot correct code after {num_attempts} attempts. "
|
@@ -191,10 +190,8 @@ def correct(
|
|
191
190
|
|
192
191
|
def _error_feedback_str(error: Exception) -> str:
|
193
192
|
"""Returns the error str for feedback."""
|
194
|
-
if isinstance(error,
|
195
|
-
return
|
196
|
-
error.format(include_complete_code=False)
|
197
|
-
)
|
193
|
+
if isinstance(error, pg.coding.CodeError):
|
194
|
+
return pg.decolor(error.format(include_complete_code=False))
|
198
195
|
else:
|
199
196
|
return f"Encountered {error.__class__.__name__}: {error}"
|
200
197
|
|
@@ -17,7 +17,6 @@ import inspect
|
|
17
17
|
import unittest
|
18
18
|
|
19
19
|
from langfun.core.coding.python import correction
|
20
|
-
from langfun.core.coding.python import errors
|
21
20
|
from langfun.core.llms import fake
|
22
21
|
import pyglove as pg
|
23
22
|
|
@@ -82,7 +81,7 @@ class RunWithCorrectionTest(unittest.TestCase):
|
|
82
81
|
max_attempts=0,
|
83
82
|
)
|
84
83
|
self.assertEqual(result, 4)
|
85
|
-
with self.assertRaises(
|
84
|
+
with self.assertRaises(pg.coding.CodeError):
|
86
85
|
correction.run_with_correction(
|
87
86
|
inspect.cleandoc("""
|
88
87
|
x = 1,
|
@@ -125,7 +124,7 @@ class CorrectTest(unittest.TestCase):
|
|
125
124
|
|
126
125
|
def test_correct_reaching_limit(self):
|
127
126
|
with self.assertRaisesRegex(
|
128
|
-
|
127
|
+
pg.coding.CodeError, 'Cannot correct code after 1 attempts'
|
129
128
|
):
|
130
129
|
correction.correct(
|
131
130
|
inspect.cleandoc("""
|
@@ -13,50 +13,23 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
"""Python code execution."""
|
15
15
|
|
16
|
-
import
|
17
|
-
import contextlib
|
18
|
-
import io
|
19
|
-
import multiprocessing
|
20
|
-
from typing import Any, Callable
|
16
|
+
from typing import Any
|
21
17
|
|
22
|
-
from langfun.core.coding.python import errors
|
23
18
|
from langfun.core.coding.python import parsing
|
24
|
-
from langfun.core.coding.python import permissions
|
25
19
|
import pyglove as pg
|
26
20
|
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
RESULT_KEY = '__result__'
|
33
|
-
_TLS_CODE_RUN_CONTEXT = '__code_run_context__'
|
34
|
-
|
35
|
-
|
36
|
-
@contextlib.contextmanager
|
37
|
-
def context(**kwargs):
|
38
|
-
"""Context manager to inject symbols for code execution."""
|
39
|
-
ctx = get_context()
|
40
|
-
ctx.update(kwargs)
|
41
|
-
pg.object_utils.thread_local_push(_TLS_CODE_RUN_CONTEXT, ctx)
|
42
|
-
|
43
|
-
try:
|
44
|
-
yield ctx
|
45
|
-
finally:
|
46
|
-
pg.object_utils.thread_local_pop(_TLS_CODE_RUN_CONTEXT)
|
47
|
-
|
48
|
-
|
49
|
-
def get_context() -> dict[str, Any]:
|
50
|
-
"""Gets the current context for code execution."""
|
51
|
-
context_stack = pg.object_utils.thread_local_get(_TLS_CODE_RUN_CONTEXT, None)
|
52
|
-
return dict(context_stack[-1]) if context_stack else {}
|
22
|
+
context = pg.coding.context
|
23
|
+
CodeError = pg.coding.CodeError
|
24
|
+
CodePermission = pg.coding.CodePermission
|
25
|
+
permission = pg.coding.permission
|
53
26
|
|
54
27
|
|
55
28
|
def evaluate(
|
56
29
|
code: str,
|
57
30
|
*,
|
58
31
|
global_vars: dict[str, Any] | None = None,
|
59
|
-
permission:
|
32
|
+
permission: CodePermission | None = None, # pylint: disable=redefined-outer-name
|
60
33
|
returns_stdout: bool = False,
|
61
34
|
outputs_intermediate: bool = False,
|
62
35
|
) -> Any | dict[str, Any]:
|
@@ -84,186 +57,20 @@ def evaluate(
|
|
84
57
|
run. The value for the last line can be accessed by key '__result__'. Or the
|
85
58
|
stdout as a str.
|
86
59
|
"""
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
code, code_block = parsing.PythonCodeParser().parse(code, permission)
|
95
|
-
global_vars, orig_global_vars = ctx, ctx.copy()
|
96
|
-
|
97
|
-
# No code.
|
98
|
-
if not code_block.body:
|
99
|
-
return {} if outputs_intermediate else None
|
100
|
-
|
101
|
-
stdout = io.StringIO()
|
102
|
-
with contextlib.redirect_stdout(stdout):
|
103
|
-
if hasattr(code_block.body[-1], 'value'):
|
104
|
-
last_expr = code_block.body.pop() # pytype: disable=attribute-error
|
105
|
-
result_vars = [RESULT_KEY]
|
106
|
-
|
107
|
-
if isinstance(last_expr, ast.Assign):
|
108
|
-
for name_node in last_expr.targets:
|
109
|
-
result_vars.append(name_node.id)
|
110
|
-
|
111
|
-
last_expr = ast.Expression(last_expr.value) # pytype: disable=attribute-error
|
112
|
-
|
113
|
-
try:
|
114
|
-
# Execute the lines before the last expression.
|
115
|
-
# NOTE(daiyip): Only a `globals` dict is specified here, which will also
|
116
|
-
# be used to output intermediate values by `exec`. We do not specify a
|
117
|
-
# separate `locals` dict here, for - "If exec gets two separate objects
|
118
|
-
# as globals and locals, the code will be executed as if it were
|
119
|
-
# embedded in a class definition." - as the Python document explains.
|
120
|
-
# The outcome is that new functions defined in the code block could not
|
121
|
-
# be called by other newly defined functions.
|
122
|
-
# Refer to https://stackoverflow.com/questions/
|
123
|
-
# 73940751/why-cant-i-call-a-function-from-another-function-using-exec
|
124
|
-
# for more details.
|
125
|
-
exec(compile(code_block, '', mode='exec'), global_vars) # pylint: disable=exec-used
|
126
|
-
|
127
|
-
# Evaluate the last expression.
|
128
|
-
result = eval( # pylint: disable=eval-used
|
129
|
-
compile(last_expr, '', mode='eval'), global_vars
|
130
|
-
)
|
131
|
-
except Exception as e:
|
132
|
-
raise errors.CodeError(code, e) from e
|
133
|
-
|
134
|
-
for result_var in result_vars:
|
135
|
-
global_vars[result_var] = result
|
136
|
-
else:
|
137
|
-
try:
|
138
|
-
exec(compile(code_block, '', mode='exec'), global_vars) # pylint: disable=exec-used
|
139
|
-
except Exception as e:
|
140
|
-
raise errors.CodeError(code, e) from e
|
141
|
-
global_vars[RESULT_KEY] = list(global_vars.values())[-1]
|
142
|
-
|
143
|
-
if returns_stdout:
|
144
|
-
return stdout.getvalue()
|
145
|
-
if outputs_intermediate:
|
146
|
-
outputs = {}
|
147
|
-
for k, v in global_vars.items():
|
148
|
-
if k == '__builtins__':
|
149
|
-
continue
|
150
|
-
if k not in orig_global_vars or v is not orig_global_vars[k]:
|
151
|
-
outputs[k] = v
|
152
|
-
# Add stdout to outputs.
|
153
|
-
outputs[STDOUT_KEY] = stdout.getvalue()
|
154
|
-
return outputs
|
155
|
-
return global_vars[RESULT_KEY]
|
156
|
-
|
157
|
-
|
158
|
-
def sandbox_call(
|
159
|
-
func: Callable[..., Any],
|
160
|
-
*args,
|
161
|
-
timeout: float | None = None,
|
162
|
-
**kwargs) -> Any:
|
163
|
-
"""Calls a function with sandboxing.
|
164
|
-
|
165
|
-
Args:
|
166
|
-
func: Function to call.
|
167
|
-
*args: Positional arguments for `func`
|
168
|
-
timeout: Execution timeout in seconds. If None, wait `func` to complete.
|
169
|
-
**kwargs: Keyword arguments for `func`.
|
170
|
-
|
171
|
-
Returns:
|
172
|
-
Return value from `func`.
|
173
|
-
|
174
|
-
Raises:
|
175
|
-
TimeoutError: If the execution time exceeds the timeout.
|
176
|
-
Exception: Exception raised from `func`.
|
177
|
-
"""
|
178
|
-
def _call(q, *args, **kwargs):
|
179
|
-
# NOTE(daiyip): if `q` is closed by the main process when `q.put` is called
|
180
|
-
# on a subprocess, ValueError will be raised. This is okay since the main
|
181
|
-
# process is no longer waiting for the result, and the subprocess could
|
182
|
-
# recycled with non-zero error code, which does not affect the main
|
183
|
-
# process.
|
184
|
-
def _run():
|
185
|
-
r = func(*args, **kwargs)
|
186
|
-
try:
|
187
|
-
return pg.to_json_str(r)
|
188
|
-
except Exception as e:
|
189
|
-
raise errors.SerializationError(
|
190
|
-
f'Cannot serialize sandbox result: {r}', e
|
191
|
-
) from e
|
192
|
-
|
193
|
-
try:
|
194
|
-
q.put(_run())
|
195
|
-
except Exception as e: # pylint: disable=broad-exception-caught
|
196
|
-
q.put(e)
|
197
|
-
|
198
|
-
q = multiprocessing.Queue()
|
199
|
-
try:
|
200
|
-
p = multiprocessing.Process(
|
201
|
-
target=_call, args=tuple([q] + list(args)), kwargs=kwargs)
|
202
|
-
p.start()
|
203
|
-
p.join(timeout=timeout)
|
204
|
-
if p.is_alive():
|
205
|
-
# We use `kill` instead of `terminate` to release process resources
|
206
|
-
# right away.
|
207
|
-
p.kill()
|
208
|
-
raise TimeoutError(f'Execution time exceed {timeout} seconds.')
|
209
|
-
x = q.get()
|
210
|
-
if isinstance(x, Exception):
|
211
|
-
raise x
|
212
|
-
try:
|
213
|
-
return pg.from_json_str(x)
|
214
|
-
except Exception as e:
|
215
|
-
raise errors.SerializationError(
|
216
|
-
'Cannot deserialize the output from sandbox.', e
|
217
|
-
) from e
|
218
|
-
finally:
|
219
|
-
q.close()
|
220
|
-
|
221
|
-
|
222
|
-
def call(
|
223
|
-
func: Callable[..., Any],
|
224
|
-
*args,
|
225
|
-
sandbox: bool | None = None,
|
226
|
-
timeout: float | None = None,
|
227
|
-
**kwargs
|
228
|
-
) -> Any:
|
229
|
-
"""Calls a function with sandbox support.
|
230
|
-
|
231
|
-
Args:
|
232
|
-
func: Function to call.
|
233
|
-
*args: Postional args that will be passed to `func`.
|
234
|
-
sandbox: If True, run code in sandbox; If False, run code in current
|
235
|
-
process. If None, run in sandbox first, if the output could not be
|
236
|
-
serialized and pass to current process, run the code again in current
|
237
|
-
process.
|
238
|
-
timeout: Execution timeout in seconds. If None, wait the code the complete.
|
239
|
-
**kwargs: Keyword args that will be passed to `func`.
|
240
|
-
|
241
|
-
Returns:
|
242
|
-
The return value of `func`.
|
243
|
-
|
244
|
-
Raises:
|
245
|
-
TimeoutError: If the execution time exceeds the timeout.
|
246
|
-
Exception: Exception that are raised from `func`.
|
247
|
-
"""
|
248
|
-
if sandbox is None:
|
249
|
-
try:
|
250
|
-
return sandbox_call(func, *args, timeout=timeout, **kwargs)
|
251
|
-
# NOTE(daiyip): output could be serialized across processes, giving it
|
252
|
-
# already finishes on sandbox, so it should be much safer to run under
|
253
|
-
# current process.
|
254
|
-
except errors.SerializationError:
|
255
|
-
return func(*args, **kwargs)
|
256
|
-
elif sandbox:
|
257
|
-
return sandbox_call(func, *args, timeout=timeout, **kwargs)
|
258
|
-
else:
|
259
|
-
return func(*args, **kwargs)
|
60
|
+
return pg.coding.evaluate(
|
61
|
+
parsing.clean(code),
|
62
|
+
global_vars=global_vars,
|
63
|
+
permission=permission,
|
64
|
+
returns_stdout=returns_stdout,
|
65
|
+
outputs_intermediate=outputs_intermediate,
|
66
|
+
)
|
260
67
|
|
261
68
|
|
262
69
|
def run(
|
263
70
|
code: str,
|
264
71
|
*,
|
265
72
|
global_vars: dict[str, Any] | None = None,
|
266
|
-
permission:
|
73
|
+
permission: CodePermission | None = None, # pylint: disable=redefined-outer-name
|
267
74
|
returns_stdout: bool = False,
|
268
75
|
outputs_intermediate: bool = False,
|
269
76
|
sandbox: bool | None = None,
|
@@ -301,8 +108,12 @@ def run(
|
|
301
108
|
TimeoutError: If the execution time exceeds the timeout.
|
302
109
|
Exception: Exception that are raised from the code.
|
303
110
|
"""
|
304
|
-
return
|
305
|
-
|
306
|
-
|
307
|
-
|
111
|
+
return pg.coding.run(
|
112
|
+
parsing.clean(code),
|
113
|
+
global_vars=global_vars,
|
114
|
+
permission=permission,
|
115
|
+
returns_stdout=returns_stdout,
|
116
|
+
outputs_intermediate=outputs_intermediate,
|
117
|
+
sandbox=sandbox,
|
118
|
+
timeout=timeout,
|
308
119
|
)
|
@@ -14,11 +14,8 @@
|
|
14
14
|
"""Tests for Python code execution."""
|
15
15
|
|
16
16
|
import inspect
|
17
|
-
import time
|
18
17
|
import unittest
|
19
|
-
from langfun.core.coding.python import errors
|
20
18
|
from langfun.core.coding.python import execution
|
21
|
-
from langfun.core.coding.python import permissions
|
22
19
|
import pyglove as pg
|
23
20
|
|
24
21
|
|
@@ -63,14 +60,14 @@ class EvaluateTest(unittest.TestCase):
|
|
63
60
|
),
|
64
61
|
3,
|
65
62
|
)
|
66
|
-
with self.assertRaisesRegex(
|
63
|
+
with self.assertRaisesRegex(execution.CodeError, 'ValueError'):
|
67
64
|
execution.evaluate(
|
68
65
|
"""
|
69
66
|
def foo():
|
70
67
|
raise ValueError("intentional error")
|
71
68
|
foo()
|
72
69
|
""",
|
73
|
-
permission=
|
70
|
+
permission=execution.CodePermission.ALL
|
74
71
|
)
|
75
72
|
|
76
73
|
def test_class_def(self):
|
@@ -82,7 +79,7 @@ class EvaluateTest(unittest.TestCase):
|
|
82
79
|
def __call__(self):
|
83
80
|
return self.x + self.y
|
84
81
|
""",
|
85
|
-
permission=
|
82
|
+
permission=execution.CodePermission.ALL,
|
86
83
|
global_vars=dict(pg=pg),
|
87
84
|
outputs_intermediate=True,
|
88
85
|
)
|
@@ -100,7 +97,7 @@ class EvaluateTest(unittest.TestCase):
|
|
100
97
|
def bar(z):
|
101
98
|
return z + foo(z, z)
|
102
99
|
""",
|
103
|
-
permission=
|
100
|
+
permission=execution.CodePermission.ALL,
|
104
101
|
outputs_intermediate=True,
|
105
102
|
)
|
106
103
|
self.assertEqual(
|
@@ -125,7 +122,7 @@ class EvaluateTest(unittest.TestCase):
|
|
125
122
|
)
|
126
123
|
ret = execution.evaluate(
|
127
124
|
code,
|
128
|
-
permission=
|
125
|
+
permission=execution.CodePermission.ALL,
|
129
126
|
outputs_intermediate=True,
|
130
127
|
)
|
131
128
|
self.assertEqual(
|
@@ -134,7 +131,7 @@ class EvaluateTest(unittest.TestCase):
|
|
134
131
|
self.assertEqual(ret['__result__'], 3)
|
135
132
|
ret = execution.evaluate(
|
136
133
|
code,
|
137
|
-
permission=
|
134
|
+
permission=execution.CodePermission.ALL,
|
138
135
|
returns_stdout=True,
|
139
136
|
)
|
140
137
|
self.assertEqual(ret, 'z is 1\n')
|
@@ -153,7 +150,7 @@ class EvaluateTest(unittest.TestCase):
|
|
153
150
|
k = A(1, 2)
|
154
151
|
k(foo(3, 4))
|
155
152
|
""",
|
156
|
-
permission=
|
153
|
+
permission=execution.CodePermission.ALL,
|
157
154
|
global_vars=dict(pg=pg),
|
158
155
|
outputs_intermediate=True,
|
159
156
|
)
|
@@ -167,18 +164,18 @@ class EvaluateTest(unittest.TestCase):
|
|
167
164
|
|
168
165
|
def test_run_with_error(self):
|
169
166
|
with self.assertRaisesRegex(
|
170
|
-
|
167
|
+
execution.CodeError, 'NameError: name .* is not defined'
|
171
168
|
):
|
172
169
|
execution.evaluate(
|
173
170
|
"""
|
174
171
|
x = 1
|
175
172
|
y = x + z
|
176
173
|
""",
|
177
|
-
permission=
|
174
|
+
permission=execution.CodePermission.ALL,
|
178
175
|
)
|
179
|
-
with self.assertRaisesRegex(
|
176
|
+
with self.assertRaisesRegex(execution.CodeError, 'ValueError'):
|
180
177
|
execution.evaluate(
|
181
|
-
'raise ValueError()', permission=
|
178
|
+
'raise ValueError()', permission=execution.CodePermission.ALL
|
182
179
|
)
|
183
180
|
|
184
181
|
|
@@ -187,82 +184,6 @@ class Foo(pg.Object):
|
|
187
184
|
y: int
|
188
185
|
|
189
186
|
|
190
|
-
class SandboxCallTest(unittest.TestCase):
|
191
|
-
|
192
|
-
def test_basics(self):
|
193
|
-
def f(x, y):
|
194
|
-
return x + y
|
195
|
-
self.assertEqual(execution.sandbox_call(f, 1, y=2), 3)
|
196
|
-
|
197
|
-
def test_complex_type(self):
|
198
|
-
def f(x, y):
|
199
|
-
return Foo(x, y)
|
200
|
-
|
201
|
-
self.assertEqual(execution.sandbox_call(f, 1, 2), Foo(1, 2))
|
202
|
-
|
203
|
-
def test_timeout(self):
|
204
|
-
def f(x):
|
205
|
-
time.sleep(x)
|
206
|
-
|
207
|
-
self.assertIsNone(execution.sandbox_call(f, 0, timeout=1))
|
208
|
-
with self.assertRaises(TimeoutError):
|
209
|
-
execution.sandbox_call(f, 2, timeout=1)
|
210
|
-
|
211
|
-
def test_raise(self):
|
212
|
-
def f(x):
|
213
|
-
if x == 0:
|
214
|
-
raise ValueError()
|
215
|
-
|
216
|
-
self.assertIsNone(execution.sandbox_call(f, 1))
|
217
|
-
with self.assertRaises(ValueError):
|
218
|
-
execution.sandbox_call(f, 0)
|
219
|
-
|
220
|
-
|
221
|
-
class CallTest(unittest.TestCase):
|
222
|
-
|
223
|
-
def test_call_without_sandboxing(self):
|
224
|
-
def foo(x, y):
|
225
|
-
return x + y
|
226
|
-
|
227
|
-
self.assertEqual(
|
228
|
-
execution.call(foo, 1, y=2, sandbox=False),
|
229
|
-
3
|
230
|
-
)
|
231
|
-
|
232
|
-
def test_call_with_sandboxing(self):
|
233
|
-
def foo(x, y):
|
234
|
-
return x + y
|
235
|
-
|
236
|
-
self.assertEqual(
|
237
|
-
execution.call(foo, 1, y=2, sandbox=True),
|
238
|
-
3
|
239
|
-
)
|
240
|
-
|
241
|
-
def make_cls():
|
242
|
-
class A(pg.Object):
|
243
|
-
x: str
|
244
|
-
return A
|
245
|
-
|
246
|
-
with self.assertRaises(errors.SerializationError):
|
247
|
-
execution.call(make_cls, sandbox=True)
|
248
|
-
|
249
|
-
def test_call_with_automatic_sandboxing(self):
|
250
|
-
def foo(x, y):
|
251
|
-
return x + y
|
252
|
-
|
253
|
-
self.assertEqual(
|
254
|
-
execution.call(foo, 1, y=2),
|
255
|
-
3
|
256
|
-
)
|
257
|
-
|
258
|
-
def make_cls():
|
259
|
-
class A(pg.Object):
|
260
|
-
x: str
|
261
|
-
return A
|
262
|
-
|
263
|
-
self.assertTrue(inspect.isclass(execution.call(make_cls)))
|
264
|
-
|
265
|
-
|
266
187
|
class RunTest(unittest.TestCase):
|
267
188
|
|
268
189
|
def test_run_without_sandboxing(self):
|
@@ -227,5 +227,6 @@ class PythonFunction(pg.Object):
|
|
227
227
|
TimeoutError: If `sandbox` is True and timeout has reached.
|
228
228
|
Exception: Any errors that the source code has raised.
|
229
229
|
"""
|
230
|
-
return
|
231
|
-
self.implementation, *args, sandbox=sandbox, timeout=timeout, **kwargs
|
230
|
+
return pg.coding.maybe_sandbox_call(
|
231
|
+
self.implementation, *args, sandbox=sandbox, timeout=timeout, **kwargs
|
232
|
+
)
|
@@ -16,7 +16,7 @@
|
|
16
16
|
import inspect
|
17
17
|
import unittest
|
18
18
|
from langfun.core.coding.python import generation
|
19
|
-
|
19
|
+
import pyglove as pg
|
20
20
|
|
21
21
|
|
22
22
|
class PythonCodeTest(unittest.TestCase):
|
@@ -58,7 +58,7 @@ class PythonCodeTest(unittest.TestCase):
|
|
58
58
|
)
|
59
59
|
|
60
60
|
def test_call_class_def(self):
|
61
|
-
with
|
61
|
+
with pg.coding.permission(pg.coding.CodePermission.CLASS_DEFINITION):
|
62
62
|
v = generation.PythonCode("""
|
63
63
|
class A:
|
64
64
|
pass
|