Skip to content

Commit cc84166

Browse files
Fix async await syntax for dython
1 parent 6fa9ccf commit cc84166

7 files changed

Lines changed: 137 additions & 79 deletions

File tree

README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ This project is still being worked on and is not ready for public release.
7373
count: int = 0
7474

7575
while True:
76-
sleep(1.0)
76+
await sleep(1.0)
7777
count = count + 1
7878

7979

@@ -160,7 +160,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
160160

161161
- **if / elif / else**: conditional branching, e.g. `if x > 0: ... elif x == 0: ... else: ...`
162162

163-
- **while**: loop while a condition holds, including infinite loops, e.g. `while True: sleep(1.0)`
163+
- **while**: loop while a condition holds, including infinite loops, e.g. `while True: await sleep(1.0)`
164164

165165
- **for**: iterate over a list, or use `enumerate` for index and value, e.g. `for i, num in enumerate(numbers): ...`
166166

@@ -176,7 +176,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
176176
@flow
177177
async def handle():
178178
data: bytes | DSError
179-
data = http_listen("POST", "/numbers")
179+
data = await http_listen("POST", "/numbers")
180180
if not isinstance(data, bytes):
181181
return data
182182
```
@@ -188,7 +188,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
188188

189189
@flow
190190
async def delay():
191-
sleep(1.0)
191+
await sleep(1.0)
192192
```
193193

194194
- **http_listen**: suspend until an HTTP request hits the given route, returning its body
@@ -199,7 +199,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
199199
@flow
200200
async def listener():
201201
data: bytes | DSError
202-
data = http_listen("POST", "/numbers")
202+
data = await http_listen("POST", "/numbers")
203203
```
204204

205205
- **http_request**: make a durable outbound HTTP call
@@ -210,7 +210,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
210210
@flow
211211
async def fetch():
212212
resp: bytes | DSError
213-
resp = http_request("GET", "http://localhost:8000/health", {}, b"")
213+
resp = await http_request("GET", "http://localhost:8000/health", {}, b"")
214214
```
215215

216216
- **json_marshal and json_unmarshal**: encode to and decode from JSON bytes, decode takes the target type as a generic param
@@ -221,9 +221,9 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
221221
@flow
222222
async def codec(data: bytes):
223223
nums: list[int] | DSError
224-
nums = json_unmarshal[list[int]](data)
224+
nums = await json_unmarshal[list[int]](data)
225225
raw: bytes | DSError
226-
raw = json_marshal([1, 2, 3])
226+
raw = await json_marshal([1, 2, 3])
227227
```
228228

229229
- **pure function**: `@pure` marked deterministic functions that don't have any side effects, run inline without a checkpoint, e.g. `status = get_status(resp)` where:
@@ -236,7 +236,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
236236
return resp.Status
237237
```
238238

239-
- **impure function**: `@impure` marked side-effect functions whose result is run once and checkpointed, e.g. `insert_event(name)` where:
239+
- **impure function**: `@impure` marked side-effect functions whose result is run once and checkpointed, e.g. `await insert_event(name)` where:
240240

241241
```python
242242
import psycopg2
@@ -254,7 +254,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
254254

255255
@flow
256256
async def record(name: str):
257-
insert_event(name)
257+
await insert_event(name)
258258
```
259259

260260
- **Flow call**: call another `@flow` function directly, it runs durably and returns its value
@@ -269,7 +269,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
269269

270270
@flow
271271
async def caller():
272-
total: int = adder(3, 5)
272+
total: int = await adder(3, 5)
273273
```
274274

275275
- **create_task**: spawn a child flow that runs concurrently
@@ -279,7 +279,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
279279

280280
@flow
281281
async def child(n: int):
282-
sleep(1.0)
282+
await sleep(1.0)
283283

284284

285285
@flow
@@ -311,7 +311,7 @@ You can think of a `@flow` function as a durable goroutine that can survive appl
311311

312312
@flow
313313
async def task(wg: dpslio.WaitGroup):
314-
sleep(1.0)
314+
await sleep(1.0)
315315
await wg.done()
316316

317317

pkg/runtimes/dython/deepslate/imports.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
class DeepslateAnnotated[**P, R]:
1818
def __init__(
1919
self,
20-
func: Callable[P, R],
20+
func: Callable[P, Any],
2121
metadata: FuncMetadata,
2222
impl: Callable[..., Any],
2323
) -> None:
@@ -48,14 +48,21 @@ def pure[**P, R](func: Callable[P, R]) -> DeepslateAnnotated[P, R]:
4848
return _mark_pure(func)
4949

5050

51-
def impure[**P, R](func: Callable[P, R]) -> DeepslateAnnotated[P, R]:
51+
def impure[**P, R](
52+
func: Callable[P, R],
53+
) -> DeepslateAnnotated[P, collections.abc.Coroutine[Any, Any, R]]:
5254
return _mark_impure(func)
5355

5456

5557
def block[**P, R](
5658
impl_fn: Callable[..., Any],
57-
) -> Callable[[Callable[P, R]], DeepslateAnnotated[P, R]]:
58-
def decorator(stub_func: Callable[P, R]) -> DeepslateAnnotated[P, R]:
59+
) -> Callable[
60+
[Callable[P, R]],
61+
DeepslateAnnotated[P, collections.abc.Coroutine[Any, Any, R]],
62+
]:
63+
def decorator(
64+
stub_func: Callable[P, R],
65+
) -> DeepslateAnnotated[P, collections.abc.Coroutine[Any, Any, R]]:
5966
return _mark_block(impl_fn, stub_func)
6067

6168
return decorator
@@ -70,13 +77,15 @@ def _mark_pure[**P, R](func: Callable[P, R]) -> DeepslateAnnotated[P, R]:
7077
return DeepslateAnnotated(func, _non_block_func_metadata(func, FuncType.PURE), func)
7178

7279

73-
def _mark_impure[**P, R](func: Callable[P, R]) -> DeepslateAnnotated[P, R]:
80+
def _mark_impure[**P, R](
81+
func: Callable[P, R],
82+
) -> DeepslateAnnotated[P, collections.abc.Coroutine[Any, Any, R]]:
7483
return DeepslateAnnotated(func, _non_block_func_metadata(func, FuncType.IMPURE), func)
7584

7685

7786
def _mark_block[**P, R](
7887
impl_func: Callable[..., Any], stub_func: Callable[P, R]
79-
) -> DeepslateAnnotated[P, R]:
88+
) -> DeepslateAnnotated[P, collections.abc.Coroutine[Any, Any, R]]:
8089
return DeepslateAnnotated(
8190
stub_func, _block_func_metadata(impl_func, stub_func), impl=impl_func
8291
)

pkg/runtimes/dython/deepslate/tests/test_worker.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ async def counter():
3232
numbers: list[int]
3333
3434
while True:
35-
request_data = http_listen("POST", "/numbers")
35+
request_data = await http_listen("POST", "/numbers")
3636
if not isinstance(request_data, bytes):
3737
return request_data
3838
39-
numbers = json_unmarshal[list[int]](request_data)
39+
numbers = await json_unmarshal[list[int]](request_data)
4040
4141
for idx, num in enumerate(numbers):
4242
if num % 2 == 0:
@@ -84,9 +84,9 @@ async def counter():
8484
async def sleep_test():
8585
counter: int = 0
8686
counter = 1
87-
sleep(1.0)
87+
await sleep(1.0)
8888
counter = 2
89-
sleep(1.0)
89+
await sleep(1.0)
9090
counter = 3
9191
"""
9292
},
@@ -131,11 +131,11 @@ async def http_request_test():
131131
status: str = ""
132132
url: str = "http://localhost:18769/health"
133133
134-
response_data = http_request("GET", url, {}, b"")
134+
response_data = await http_request("GET", url, {}, b"")
135135
if not isinstance(response_data, bytes):
136136
return response_data
137137
138-
resp = json_unmarshal[HealthResponse](response_data)
138+
resp = await json_unmarshal[HealthResponse](response_data)
139139
status = get_status(resp)
140140
""",
141141
},
@@ -177,7 +177,7 @@ def get_health_status(url: str) -> str:
177177
@flow
178178
async def impure_http_request_test():
179179
status: str = ""
180-
status = get_health_status("http://localhost:18769/health")
180+
status = await get_health_status("http://localhost:18769/health")
181181
""",
182182
},
183183
steps=[
@@ -210,15 +210,15 @@ async def echo_request_test():
210210
value: int = 0
211211
url: str = "http://localhost:18769/echo"
212212
213-
body = json_marshal(42)
213+
body = await json_marshal(42)
214214
if not isinstance(body, bytes):
215215
return body
216216
217-
response_data = http_request("POST", url, {}, body)
217+
response_data = await http_request("POST", url, {}, body)
218218
if not isinstance(response_data, bytes):
219219
return response_data
220220
221-
value = json_unmarshal[int](response_data)
221+
value = await json_unmarshal[int](response_data)
222222
""",
223223
},
224224
steps=[
@@ -266,7 +266,7 @@ def noop() -> None:
266266
@flow
267267
async def impure_void_test():
268268
x: int = 1
269-
noop()
269+
await noop()
270270
x = 2
271271
""",
272272
},
@@ -296,7 +296,7 @@ async def impure_void_test():
296296
@flow
297297
async def child_flow():
298298
request_data: bytes | DSError
299-
request_data = http_listen("POST", "/child")
299+
request_data = await http_listen("POST", "/child")
300300
if not isinstance(request_data, bytes):
301301
return request_data
302302
""",
@@ -337,7 +337,7 @@ async def parent_flow():
337337
@flow
338338
async def child_wg_flow_a(wg: dpslio.WaitGroup):
339339
request_data: bytes | DSError
340-
request_data = http_listen("POST", "/child_wg_a")
340+
request_data = await http_listen("POST", "/child_wg_a")
341341
if not isinstance(request_data, bytes):
342342
return request_data
343343
await wg.done()
@@ -350,7 +350,7 @@ async def child_wg_flow_a(wg: dpslio.WaitGroup):
350350
@flow
351351
async def child_wg_flow_b(wg: dpslio.WaitGroup):
352352
request_data: bytes | DSError
353-
request_data = http_listen("POST", "/child_wg_b")
353+
request_data = await http_listen("POST", "/child_wg_b")
354354
if not isinstance(request_data, bytes):
355355
return request_data
356356
await wg.done()
@@ -421,9 +421,9 @@ def format_route(value: int) -> str:
421421
@flow
422422
async def child_chan_flow(ch: dpslio.Queue[int], wg: dpslio.WaitGroup):
423423
value: int = await ch.get()
424-
route: str = format_route(value)
424+
route: str = await format_route(value)
425425
request_data: bytes | DSError
426-
request_data = http_listen("GET", route)
426+
request_data = await http_listen("GET", route)
427427
if not isinstance(request_data, bytes):
428428
return request_data
429429
await wg.done()
@@ -485,7 +485,7 @@ async def chan_parent_flow() -> None:
485485
486486
@flow
487487
async def sel_child_flow(ch: dpslio.Queue[int], v: int, d: float, wg: dpslio.WaitGroup):
488-
sleep(d)
488+
await sleep(d)
489489
await ch.put(v)
490490
await wg.done()
491491
""",
@@ -535,7 +535,7 @@ async def select_parent_flow() -> None:
535535
async def child_mutex_flow(mu: dpslio.Lock, ch: dpslio.Queue[int]):
536536
await mu.acquire()
537537
request_data: bytes | DSError
538-
request_data = http_listen("POST", "/mutex_child")
538+
request_data = await http_listen("POST", "/mutex_child")
539539
if not isinstance(request_data, bytes):
540540
return request_data
541541
await ch.put(1)
@@ -601,7 +601,7 @@ async def adder(a: int, b: int) -> int:
601601
602602
@flow
603603
async def caller_flow():
604-
sum_val: int = adder(3, 5)
604+
sum_val: int = await adder(3, 5)
605605
""",
606606
},
607607
steps=[
@@ -623,7 +623,7 @@ async def caller_flow():
623623
@flow
624624
async def noop(a: int, b: int) -> None:
625625
result: int = a + b
626-
sleep(1.0)
626+
await sleep(1.0)
627627
""",
628628
"caller_flow.py": """\
629629
from deepslate import flow
@@ -633,7 +633,7 @@ async def noop(a: int, b: int) -> None:
633633
@flow
634634
async def caller_flow():
635635
finished: int = 0
636-
noop(3, 5)
636+
await noop(3, 5)
637637
finished = 1
638638
""",
639639
},
@@ -684,7 +684,7 @@ async def select_default_flow() -> None:
684684
685685
@flow
686686
async def sel_child_flow(ch: dpslio.Queue[int], v: int, d: float, wg: dpslio.WaitGroup):
687-
sleep(d)
687+
await sleep(d)
688688
await ch.put(v)
689689
await wg.done()
690690
""",
@@ -733,10 +733,10 @@ async def select_second_parent_flow() -> None:
733733
async def suspend_child(url: str) -> bytes:
734734
resp: bytes | DSError = b""
735735
while True:
736-
resp = http_request("GET", url, {}, b"")
736+
resp = await http_request("GET", url, {}, b"")
737737
if isinstance(resp, bytes):
738738
return resp
739-
sleep(2.0)
739+
await sleep(2.0)
740740
""",
741741
"join_caller.py": """\
742742
from deepslate import flow
@@ -746,7 +746,7 @@ async def suspend_child(url: str) -> bytes:
746746
@flow
747747
async def join_caller() -> None:
748748
url: str = "http://localhost:18769/health"
749-
raw: bytes = suspend_child(url)
749+
raw: bytes = await suspend_child(url)
750750
""",
751751
},
752752
steps=[

pkg/transpilers/dython/constructors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func funcCallImpure(
174174
retVarName string,
175175
line int,
176176
) string {
177-
callStr := funcCallPure(funcName, args, typeParam)
177+
callStr := funcCallBlock(funcName, args, typeParam)
178178

179179
var stmt string
180180
if retVarName != "" {

pkg/transpilers/dython/testutil_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,14 @@ func runTranspilerErrorTest(t *testing.T, tt transpileErrorTestCase) {
206206
}
207207

208208
func addPreludeImportOutput(code string) string {
209-
return "from deepslate.prelude import *\nfrom deepslate import dpslio\n" +
209+
return "from deepslate.prelude import *\n" +
210+
"from deepslate import dpslio, pure, impure\n" +
210211
code + testStubs()
211212
}
212213

213214
func addPreludeImportInput(code string) string {
214-
return "from deepslate.prelude import *\nfrom deepslate import dpslio\n\n\n" +
215+
return "from deepslate.prelude import *\n" +
216+
"from deepslate import dpslio, pure, impure\n\n\n" +
215217
testStubs() +
216218
"async def child_a() -> None:\n pass\n\n\n" +
217219
"async def child_b() -> None:\n pass\n\n\n" +
@@ -220,10 +222,10 @@ func addPreludeImportInput(code string) string {
220222

221223
func testStubs() string {
222224
return "" +
223-
"def pure_add(a: int, b: int) -> int:\n return a + b\n\n\n" +
224-
"def impure_log(msg: str) -> None:\n pass\n\n\n" +
225-
"def impure_read(path: str) -> str:\n return path\n\n\n" +
226-
"def child_ret() -> int:\n return 0\n\n\n"
225+
"@pure\ndef pure_add(a: int, b: int) -> int:\n return a + b\n\n\n" +
226+
"@impure\ndef impure_log(msg: str) -> None:\n pass\n\n\n" +
227+
"@impure\ndef impure_read(path: str) -> str:\n return path\n\n\n" +
228+
"async def child_ret() -> int:\n return 0\n\n\n"
227229
}
228230

229231
func mockImportMetadata(

0 commit comments

Comments
 (0)