Skip to content

Commit 5cc103d

Browse files
Copilotpwwang
andcommitted
Improve integration tests with exec-based AST fallback behavior testing
Co-authored-by: pwwang <[email protected]>
1 parent cfba7c4 commit 5cc103d

File tree

1 file changed

+119
-38
lines changed

1 file changed

+119
-38
lines changed

tests/test_verb_env_integration.py

Lines changed: 119 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,133 @@
11
"""Integration test to demonstrate the environment variable feature"""
22
import os
3-
import sys
4-
import subprocess
5-
import tempfile
3+
import pytest
64

75

8-
def test_env_var_integration():
9-
"""Integration test showing environment variables in action"""
10-
# Create a simple test script that uses datar
11-
test_script = """
12-
import os
13-
from pipda import register_verb
14-
from datar.core.verb_env import get_verb_ast_fallback
6+
def test_verb_ast_fallback_piping():
7+
"""Test that DATAR_*_AST_FALLBACK works with piping mode"""
8+
from pipda import register_verb
9+
from datar.core.verb_env import get_verb_ast_fallback
10+
11+
# Set environment variable for piping mode
12+
os.environ['DATAR_PLUS_AST_FALLBACK'] = 'piping'
13+
14+
try:
15+
# Register a simple verb
16+
@register_verb(ast_fallback=get_verb_ast_fallback("plus"))
17+
def plus(x, y):
18+
return x + y
19+
20+
# Test with exec to disable source code detection at runtime
21+
# In piping mode, piping call should work
22+
result = {}
23+
exec("result['val'] = 1 >> plus(1)", {"plus": plus, "result": result})
24+
assert result['val'] == 2
25+
26+
# Normal call in piping mode returns a placeholder when AST is not available
27+
result = {}
28+
exec("result['val'] = plus(1, 1)", {"plus": plus, "result": result})
29+
# The result is a placeholder object, not the actual computation
30+
assert str(result['val']) == 'plus(., 1, 1)'
31+
32+
finally:
33+
del os.environ['DATAR_PLUS_AST_FALLBACK']
34+
35+
36+
def test_verb_ast_fallback_normal():
37+
"""Test that DATAR_*_AST_FALLBACK works with normal mode"""
38+
from pipda import register_verb
39+
from datar.core.verb_env import get_verb_ast_fallback
40+
41+
# Set environment variable for normal mode
42+
os.environ['DATAR_MINUS_AST_FALLBACK'] = 'normal'
43+
44+
try:
45+
# Register a simple verb
46+
@register_verb(ast_fallback=get_verb_ast_fallback("minus"))
47+
def minus(x, y):
48+
return x - y
49+
50+
# Test with exec to disable source code detection at runtime
51+
# In normal mode, normal call should work
52+
result = {}
53+
exec("result['val'] = minus(5, 3)", {"minus": minus, "result": result})
54+
assert result['val'] == 2
55+
56+
# Piping call in normal mode raises TypeError when AST is not available
57+
result = {}
58+
with pytest.raises(TypeError):
59+
exec("result['val'] = 5 >> minus(3)", {"minus": minus, "result": result})
1560

16-
# Set environment variable before importing verbs
17-
os.environ['DATAR_TEST_VERB_AST_FALLBACK'] = 'piping'
61+
finally:
62+
del os.environ['DATAR_MINUS_AST_FALLBACK']
1863

19-
@register_verb(ast_fallback=get_verb_ast_fallback("test_verb"))
20-
def test_verb(data):
21-
return data
2264

23-
# Verify the verb is registered
24-
assert callable(test_verb)
25-
print("SUCCESS: Environment variable integration test passed")
26-
"""
65+
def test_verb_ast_fallback_global():
66+
"""Test that DATAR_VERB_AST_FALLBACK works as global fallback"""
67+
from pipda import register_verb
68+
from datar.core.verb_env import get_verb_ast_fallback
2769

28-
# Write to a temporary file
29-
with tempfile.NamedTemporaryFile(
30-
mode='w', suffix='.py', delete=False
31-
) as f:
32-
temp_path = f.name
33-
f.write(test_script)
70+
# Set global environment variable
71+
os.environ['DATAR_VERB_AST_FALLBACK'] = 'piping'
3472

3573
try:
36-
# Run the script
37-
result = subprocess.run(
38-
[sys.executable, temp_path],
39-
capture_output=True,
40-
text=True
41-
)
42-
43-
# Check the result
44-
assert result.returncode == 0
45-
assert "SUCCESS" in result.stdout
74+
# Register verbs without specific env var
75+
@register_verb(ast_fallback=get_verb_ast_fallback("multiply"))
76+
def multiply(x, y):
77+
return x * y
78+
79+
@register_verb(ast_fallback=get_verb_ast_fallback("divide"))
80+
def divide(x, y):
81+
return x / y
82+
83+
# Both should use global piping mode
84+
result = {}
85+
exec("result['mul'] = 6 >> multiply(2)", {"multiply": multiply, "result": result})
86+
assert result['mul'] == 12
87+
88+
exec("result['div'] = 10 >> divide(2)", {"divide": divide, "result": result})
89+
assert result['div'] == 5
90+
91+
finally:
92+
del os.environ['DATAR_VERB_AST_FALLBACK']
93+
94+
95+
def test_verb_ast_fallback_precedence():
96+
"""Test that per-verb env var takes precedence over global"""
97+
from pipda import register_verb
98+
from datar.core.verb_env import get_verb_ast_fallback
99+
100+
# Set global to piping and specific verb to normal
101+
os.environ['DATAR_VERB_AST_FALLBACK'] = 'piping'
102+
os.environ['DATAR_MODULO_AST_FALLBACK'] = 'normal'
103+
104+
try:
105+
# Register verbs
106+
@register_verb(ast_fallback=get_verb_ast_fallback("power"))
107+
def power(x, y):
108+
return x ** y
109+
110+
@register_verb(ast_fallback=get_verb_ast_fallback("modulo"))
111+
def modulo(x, y):
112+
return x % y
113+
114+
# power should use global piping mode
115+
result = {}
116+
exec("result['pow'] = 2 >> power(3)", {"power": power, "result": result})
117+
assert result['pow'] == 8
118+
119+
# modulo should use specific normal mode
120+
exec("result['mod'] = modulo(10, 3)", {"modulo": modulo, "result": result})
121+
assert result['mod'] == 1
122+
46123
finally:
47-
# Clean up the temporary file
48-
os.unlink(temp_path)
124+
del os.environ['DATAR_VERB_AST_FALLBACK']
125+
del os.environ['DATAR_MODULO_AST_FALLBACK']
49126

50127

51128
if __name__ == "__main__":
52-
test_env_var_integration()
129+
test_verb_ast_fallback_piping()
130+
test_verb_ast_fallback_normal()
131+
test_verb_ast_fallback_global()
132+
test_verb_ast_fallback_precedence()
133+
print("All integration tests passed!")

0 commit comments

Comments
 (0)