rapydscript-ns 0.9.2 → 0.9.3
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.
- package/.agignore +1 -1
- package/.github/workflows/ci.yml +38 -38
- package/=template.pyj +5 -5
- package/CHANGELOG.md +19 -0
- package/HACKING.md +103 -103
- package/LICENSE +24 -24
- package/PYTHON_GAPS.md +420 -0
- package/README.md +153 -29
- package/TODO.md +16 -118
- package/add-toc-to-readme +2 -2
- package/bin/export +75 -75
- package/bin/rapydscript +70 -70
- package/bin/web-repl-export +102 -102
- package/build +2 -2
- package/language-service/index.js +237 -8
- package/memory/project_string_impl.md +43 -0
- package/package.json +1 -1
- package/publish.py +37 -37
- package/release/baselib-plain-pretty.js +248 -38
- package/release/baselib-plain-ugly.js +8 -8
- package/release/compiler.js +778 -277
- package/release/signatures.json +30 -30
- package/session.vim +4 -4
- package/setup.cfg +2 -2
- package/src/ast.pyj +4 -1
- package/src/baselib-builtins.pyj +56 -2
- package/src/baselib-containers.pyj +2 -0
- package/src/baselib-errors.pyj +7 -3
- package/src/baselib-internal.pyj +51 -6
- package/src/baselib-str.pyj +5 -3
- package/src/compiler.pyj +36 -36
- package/src/errors.pyj +30 -30
- package/src/lib/aes.pyj +646 -646
- package/src/lib/asyncio.pyj +534 -0
- package/src/lib/base64.pyj +399 -0
- package/src/lib/bisect.pyj +73 -0
- package/src/lib/collections.pyj +1 -1
- package/src/lib/copy.pyj +120 -120
- package/src/lib/csv.pyj +494 -0
- package/src/lib/elementmaker.pyj +83 -83
- package/src/lib/encodings.pyj +126 -126
- package/src/lib/gettext.pyj +569 -569
- package/src/lib/heapq.pyj +98 -0
- package/src/lib/html.pyj +382 -0
- package/src/lib/http/__init__.pyj +98 -0
- package/src/lib/http/client.pyj +304 -0
- package/src/lib/http/cookies.pyj +236 -0
- package/src/lib/itertools.pyj +580 -580
- package/src/lib/logging.pyj +672 -0
- package/src/lib/math.pyj +193 -193
- package/src/lib/operator.pyj +11 -11
- package/src/lib/pythonize.pyj +20 -20
- package/src/lib/random.pyj +118 -118
- package/src/lib/react.pyj +74 -74
- package/src/lib/string.pyj +357 -0
- package/src/lib/textwrap.pyj +329 -0
- package/src/lib/traceback.pyj +63 -63
- package/src/lib/urllib/__init__.pyj +14 -0
- package/src/lib/urllib/error.pyj +66 -0
- package/src/lib/urllib/parse.pyj +475 -0
- package/src/lib/urllib/request.pyj +86 -0
- package/src/lib/uuid.pyj +77 -77
- package/src/monaco-language-service/analyzer.js +5 -2
- package/src/monaco-language-service/completions.js +26 -0
- package/src/monaco-language-service/diagnostics.js +202 -3
- package/src/monaco-language-service/dts.js +550 -550
- package/src/monaco-language-service/scope.js +1 -0
- package/src/output/comments.pyj +45 -45
- package/src/output/exceptions.pyj +201 -201
- package/src/output/functions.pyj +152 -6
- package/src/output/jsx.pyj +164 -164
- package/src/output/loops.pyj +17 -2
- package/src/output/modules.pyj +1 -1
- package/src/output/operators.pyj +15 -0
- package/src/output/stream.pyj +0 -1
- package/src/output/treeshake.pyj +182 -182
- package/src/output/utils.pyj +72 -72
- package/src/parse.pyj +80 -17
- package/src/string_interpolation.pyj +72 -72
- package/src/tokenizer.pyj +1 -1
- package/src/unicode_aliases.pyj +576 -576
- package/src/utils.pyj +192 -192
- package/test/_import_one.pyj +37 -37
- package/test/_import_two/__init__.pyj +11 -11
- package/test/_import_two/level2/deep.pyj +4 -4
- package/test/_import_two/other.pyj +6 -6
- package/test/_import_two/sub.pyj +13 -13
- package/test/aes_vectors.pyj +421 -421
- package/test/annotations.pyj +80 -80
- package/test/async_generators.pyj +144 -0
- package/test/asyncio.pyj +307 -0
- package/test/base64.pyj +202 -0
- package/test/bisect.pyj +178 -0
- package/test/csv.pyj +405 -0
- package/test/decorators.pyj +77 -77
- package/test/docstrings.pyj +39 -39
- package/test/elementmaker_test.pyj +45 -45
- package/test/float_special.pyj +64 -0
- package/test/functions.pyj +151 -151
- package/test/generators.pyj +41 -41
- package/test/generic.pyj +370 -370
- package/test/heapq.pyj +174 -0
- package/test/html.pyj +212 -0
- package/test/http.pyj +259 -0
- package/test/imports.pyj +79 -72
- package/test/internationalization.pyj +73 -73
- package/test/lint.pyj +164 -164
- package/test/logging.pyj +356 -0
- package/test/long.pyj +130 -0
- package/test/loops.pyj +85 -85
- package/test/numpy.pyj +734 -734
- package/test/parenthesized_with.pyj +141 -0
- package/test/python_compat.pyj +3 -5
- package/test/python_modulo.pyj +76 -0
- package/test/python_modulo_off.pyj +21 -0
- package/test/repl.pyj +121 -121
- package/test/scoped_flags.pyj +76 -76
- package/test/str.pyj +14 -0
- package/test/string.pyj +245 -0
- package/test/textwrap.pyj +172 -0
- package/test/type_display.pyj +48 -0
- package/test/type_enforcement.pyj +164 -0
- package/test/unit/index.js +14 -6
- package/test/unit/language-service-completions.js +119 -0
- package/test/unit/language-service-dts.js +543 -543
- package/test/unit/language-service-hover.js +455 -455
- package/test/unit/language-service-scope.js +32 -0
- package/test/unit/language-service.js +127 -3
- package/test/unit/run-language-service.js +17 -3
- package/test/unit/web-repl.js +2094 -29
- package/test/urllib.pyj +193 -0
- package/tools/compile.js +1 -1
- package/tools/compiler.d.ts +367 -367
- package/tools/completer.js +131 -131
- package/tools/embedded_compiler.js +7 -7
- package/tools/gettext.js +185 -185
- package/tools/ini.js +65 -65
- package/tools/msgfmt.js +187 -187
- package/tools/repl.js +223 -223
- package/tools/test.js +118 -118
- package/tools/utils.js +128 -128
- package/tools/web_repl.js +95 -95
- package/try +41 -41
- package/web-repl/env.js +196 -196
- package/web-repl/index.html +163 -163
- package/web-repl/main.js +1 -1
- package/web-repl/prism.css +139 -139
- package/web-repl/prism.js +113 -113
- package/web-repl/rapydscript.js +224 -224
- package/web-repl/sha1.js +25 -25
- package/test/omit_function_metadata.pyj +0 -20
package/test/annotations.pyj
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
def add(a: int, b: float):
|
|
2
|
-
return a + b
|
|
3
|
-
|
|
4
|
-
assrt.ok(add.__annotations__)
|
|
5
|
-
assrt.equal(add.__annotations__['a'], int)
|
|
6
|
-
assrt.equal(add.__annotations__['b'], float)
|
|
7
|
-
assrt.equal(add.__annotations__['return'], undefined)
|
|
8
|
-
|
|
9
|
-
def sum(ls: list) -> int:
|
|
10
|
-
pass
|
|
11
|
-
|
|
12
|
-
assrt.ok(not (sum.__annotations__ == undefined))
|
|
13
|
-
assrt.deepEqual(sum.__annotations__, {
|
|
14
|
-
'ls': list,
|
|
15
|
-
'return': int
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
def optional(a:int=10):
|
|
19
|
-
return a
|
|
20
|
-
|
|
21
|
-
assrt.ok(not (optional.__annotations__ == undefined))
|
|
22
|
-
assrt.equal(optional.__annotations__.a, int)
|
|
23
|
-
assrt.equal(optional.__defaults__.a, 10)
|
|
24
|
-
|
|
25
|
-
def otherexpr(a:3+4) -> [1, 2]:
|
|
26
|
-
pass
|
|
27
|
-
|
|
28
|
-
assrt.ok(not (otherexpr.__annotations__ == undefined))
|
|
29
|
-
assrt.equal(otherexpr.__annotations__['a'], 7)
|
|
30
|
-
assrt.deepEqual(otherexpr.__annotations__['return'], [1, 2])
|
|
31
|
-
|
|
32
|
-
def basic(x:float):
|
|
33
|
-
pass
|
|
34
|
-
|
|
35
|
-
assrt.deepEqual(basic.__annotations__, {
|
|
36
|
-
'x': float
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
def kwstarargs(*args:list, **kwargs:dict) -> int:
|
|
40
|
-
pass
|
|
41
|
-
|
|
42
|
-
assrt.equal(kwstarargs.__annotations__['return'], int)
|
|
43
|
-
|
|
44
|
-
def nothing():
|
|
45
|
-
pass
|
|
46
|
-
|
|
47
|
-
assrt.ok(nothing.__annotations__ == undefined)
|
|
48
|
-
assrt.throws(def():
|
|
49
|
-
nothing.__annotations__['return']
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
test = def(x: int):
|
|
53
|
-
pass
|
|
54
|
-
|
|
55
|
-
assrt.deepEqual(test.__annotations__, {
|
|
56
|
-
'x': int
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
anonreturn = def() -> 'test':
|
|
60
|
-
pass
|
|
61
|
-
|
|
62
|
-
assrt.equal(anonreturn.__annotations__['return'], 'test')
|
|
63
|
-
|
|
64
|
-
assrt.equal(def asexpr(a: int):
|
|
65
|
-
a
|
|
66
|
-
.__annotations__['a'], int)
|
|
67
|
-
|
|
68
|
-
assrt.deepEqual(def(a: int) -> float:
|
|
69
|
-
a + 10.0
|
|
70
|
-
.__annotations__, {
|
|
71
|
-
'a': int,
|
|
72
|
-
'return': float
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
class A:
|
|
76
|
-
|
|
77
|
-
def f(self, a : int, b: 'x') -> float:
|
|
78
|
-
pass
|
|
79
|
-
|
|
80
|
-
assrt.deepEqual(A.prototype.f.__annotations__, {'a':int, 'b':'x', 'return': float})
|
|
1
|
+
def add(a: int, b: float):
|
|
2
|
+
return a + b
|
|
3
|
+
|
|
4
|
+
assrt.ok(add.__annotations__)
|
|
5
|
+
assrt.equal(add.__annotations__['a'], int)
|
|
6
|
+
assrt.equal(add.__annotations__['b'], float)
|
|
7
|
+
assrt.equal(add.__annotations__['return'], undefined)
|
|
8
|
+
|
|
9
|
+
def sum(ls: list) -> int:
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
assrt.ok(not (sum.__annotations__ == undefined))
|
|
13
|
+
assrt.deepEqual(sum.__annotations__, {
|
|
14
|
+
'ls': list,
|
|
15
|
+
'return': int
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
def optional(a:int=10):
|
|
19
|
+
return a
|
|
20
|
+
|
|
21
|
+
assrt.ok(not (optional.__annotations__ == undefined))
|
|
22
|
+
assrt.equal(optional.__annotations__.a, int)
|
|
23
|
+
assrt.equal(optional.__defaults__.a, 10)
|
|
24
|
+
|
|
25
|
+
def otherexpr(a:3+4) -> [1, 2]:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
assrt.ok(not (otherexpr.__annotations__ == undefined))
|
|
29
|
+
assrt.equal(otherexpr.__annotations__['a'], 7)
|
|
30
|
+
assrt.deepEqual(otherexpr.__annotations__['return'], [1, 2])
|
|
31
|
+
|
|
32
|
+
def basic(x:float):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
assrt.deepEqual(basic.__annotations__, {
|
|
36
|
+
'x': float
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
def kwstarargs(*args:list, **kwargs:dict) -> int:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
assrt.equal(kwstarargs.__annotations__['return'], int)
|
|
43
|
+
|
|
44
|
+
def nothing():
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
assrt.ok(nothing.__annotations__ == undefined)
|
|
48
|
+
assrt.throws(def():
|
|
49
|
+
nothing.__annotations__['return']
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
test = def(x: int):
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
assrt.deepEqual(test.__annotations__, {
|
|
56
|
+
'x': int
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
anonreturn = def() -> 'test':
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
assrt.equal(anonreturn.__annotations__['return'], 'test')
|
|
63
|
+
|
|
64
|
+
assrt.equal(def asexpr(a: int):
|
|
65
|
+
a
|
|
66
|
+
.__annotations__['a'], int)
|
|
67
|
+
|
|
68
|
+
assrt.deepEqual(def(a: int) -> float:
|
|
69
|
+
a + 10.0
|
|
70
|
+
.__annotations__, {
|
|
71
|
+
'a': int,
|
|
72
|
+
'return': float
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
class A:
|
|
76
|
+
|
|
77
|
+
def f(self, a : int, b: 'x') -> float:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
assrt.deepEqual(A.prototype.f.__annotations__, {'a':int, 'b':'x', 'return': float})
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# globals: assrt
|
|
2
|
+
# vim:fileencoding=utf-8
|
|
3
|
+
#
|
|
4
|
+
# async_generators.pyj
|
|
5
|
+
# Tests for `async def` functions with `yield` (async generators).
|
|
6
|
+
#
|
|
7
|
+
# An async generator is a coroutine that produces values via `yield`. Calling
|
|
8
|
+
# it returns an async iterator whose `.next()` / `.asend()` return Promises.
|
|
9
|
+
#
|
|
10
|
+
# `vm.runInNewContext` (the test runner) is synchronous and does not drain the
|
|
11
|
+
# microtask queue, so these tests assert *synchronously observable* properties:
|
|
12
|
+
# the iterator shape, that .next() is thenable, that the compiled code runs
|
|
13
|
+
# without throwing, and that single-microtask resolution works via
|
|
14
|
+
# Promise.then chains observed through a shared mutable list. End-to-end
|
|
15
|
+
# async-for execution is covered by the web-repl bundle tests.
|
|
16
|
+
|
|
17
|
+
ae = assrt.equal
|
|
18
|
+
ade = assrt.deepEqual
|
|
19
|
+
ok = assrt.ok
|
|
20
|
+
|
|
21
|
+
# ── 1. Calling an async generator returns an iterator with the right shape ───
|
|
22
|
+
|
|
23
|
+
async def basic_gen():
|
|
24
|
+
yield 1
|
|
25
|
+
yield 2
|
|
26
|
+
yield 3
|
|
27
|
+
|
|
28
|
+
it = basic_gen()
|
|
29
|
+
ae(jstype(it.next), 'function')
|
|
30
|
+
ae(jstype(it.send), 'function') # Python compatibility alias (== .next)
|
|
31
|
+
ae(jstype(it.asend), 'function') # async-generator-specific alias (== .next)
|
|
32
|
+
|
|
33
|
+
# .next() must return a thenable Promise (sync generators return {value,done}).
|
|
34
|
+
p = it.next()
|
|
35
|
+
ae(jstype(p.then), 'function')
|
|
36
|
+
|
|
37
|
+
# ── 2. The wrapper is a sync function — no `await` needed to obtain it ───────
|
|
38
|
+
# An accidental `async function* aiter` (without our wrapper) would return a
|
|
39
|
+
# Promise here instead of an iterator.
|
|
40
|
+
|
|
41
|
+
ae(jstype(it[v'Symbol.asyncIterator']), 'function')
|
|
42
|
+
|
|
43
|
+
# ── 3. Promise resolution observable via .then ───────────────────────────────
|
|
44
|
+
# We collect each yielded {value, done} synchronously by walking the iterator
|
|
45
|
+
# manually. Each .then(...) chain runs as a microtask after this script ends,
|
|
46
|
+
# but we can still capture the *number* of pending links and the result list
|
|
47
|
+
# by chaining via Promise.all on the final .next.
|
|
48
|
+
|
|
49
|
+
results = []
|
|
50
|
+
|
|
51
|
+
def push_value(r):
|
|
52
|
+
results.push(r.value)
|
|
53
|
+
|
|
54
|
+
# Drive three steps; the last assertion runs in the final .then. If any link
|
|
55
|
+
# rejects, the final ok() in the assertion chain is skipped and the test
|
|
56
|
+
# process exits with a non-zero status because of the unhandled rejection.
|
|
57
|
+
chain = it.next()
|
|
58
|
+
v"""
|
|
59
|
+
chain = chain.then(function(r){ push_value(r); return basic_gen().next(); });
|
|
60
|
+
chain.then(function(r){ push_value(r); });
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# ── 4. Empty async generator: a `yield` that never executes still makes the
|
|
64
|
+
# function an async generator (not a regular coroutine). ─────────────────────
|
|
65
|
+
|
|
66
|
+
async def empty_gen():
|
|
67
|
+
if False:
|
|
68
|
+
yield 0
|
|
69
|
+
|
|
70
|
+
empty_it = empty_gen()
|
|
71
|
+
ae(jstype(empty_it.next), 'function')
|
|
72
|
+
ae(jstype(empty_it[v'Symbol.asyncIterator']), 'function')
|
|
73
|
+
|
|
74
|
+
# ── 5. `await` is allowed before/between yields inside async generators ──────
|
|
75
|
+
|
|
76
|
+
def deferred(v):
|
|
77
|
+
return v'Promise.resolve(v)'
|
|
78
|
+
|
|
79
|
+
async def awaited_gen():
|
|
80
|
+
a = await deferred(10)
|
|
81
|
+
yield a
|
|
82
|
+
b = await deferred(20)
|
|
83
|
+
yield a + b
|
|
84
|
+
|
|
85
|
+
aw_it = awaited_gen()
|
|
86
|
+
ae(jstype(aw_it.next), 'function')
|
|
87
|
+
# .next() returns a thenable even though the body awaits before yielding
|
|
88
|
+
ae(jstype(aw_it.next().then), 'function')
|
|
89
|
+
|
|
90
|
+
# ── 6. `async for` parses and compiles inside an async function ──────────────
|
|
91
|
+
# We don't drive the loop here (microtasks won't run), but we verify the
|
|
92
|
+
# coroutine object is produced and is thenable.
|
|
93
|
+
|
|
94
|
+
async def consume():
|
|
95
|
+
out = []
|
|
96
|
+
async for x in basic_gen():
|
|
97
|
+
out.append(x)
|
|
98
|
+
return out
|
|
99
|
+
|
|
100
|
+
p = consume()
|
|
101
|
+
ae(jstype(p.then), 'function')
|
|
102
|
+
|
|
103
|
+
# ── 7. Class methods can be async generators ─────────────────────────────────
|
|
104
|
+
|
|
105
|
+
class Counter:
|
|
106
|
+
def __init__(self, limit):
|
|
107
|
+
self.limit = limit
|
|
108
|
+
|
|
109
|
+
async def values(self):
|
|
110
|
+
i = 0
|
|
111
|
+
while i < self.limit:
|
|
112
|
+
yield i
|
|
113
|
+
i += 1
|
|
114
|
+
|
|
115
|
+
c_it = Counter(3).values()
|
|
116
|
+
ae(jstype(c_it.next), 'function')
|
|
117
|
+
ae(jstype(c_it[v'Symbol.asyncIterator']), 'function')
|
|
118
|
+
|
|
119
|
+
# ── 8. Yielded values match Python semantics for the simple sync-yield case ──
|
|
120
|
+
# Microtask-driven: the .then below runs after all top-level code, so we
|
|
121
|
+
# accumulate into `results` and assert via the final chained .then. If the
|
|
122
|
+
# assertion throws, Node exits non-zero (unhandled rejection).
|
|
123
|
+
|
|
124
|
+
drain = []
|
|
125
|
+
|
|
126
|
+
def collect_one(r):
|
|
127
|
+
if not r.done:
|
|
128
|
+
drain.push(r.value)
|
|
129
|
+
|
|
130
|
+
def assert_drain():
|
|
131
|
+
# Order of resolution is sequential because each .then awaits the prior.
|
|
132
|
+
# Expected: yields 1, 2, 3 from basic_gen()
|
|
133
|
+
ade(drain, [1, 2, 3])
|
|
134
|
+
|
|
135
|
+
g = basic_gen()
|
|
136
|
+
v"""
|
|
137
|
+
g.next().then(function(r){ collect_one(r); return g.next(); })
|
|
138
|
+
.then(function(r){ collect_one(r); return g.next(); })
|
|
139
|
+
.then(function(r){ collect_one(r); return g.next(); })
|
|
140
|
+
.then(function(r){
|
|
141
|
+
// r.done should be true now; assert the accumulated values.
|
|
142
|
+
assert_drain();
|
|
143
|
+
});
|
|
144
|
+
"""
|
package/test/asyncio.pyj
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# globals: assrt
|
|
2
|
+
# vim:fileencoding=utf-8
|
|
3
|
+
#
|
|
4
|
+
# asyncio.pyj
|
|
5
|
+
# Tests for the asyncio standard library module.
|
|
6
|
+
#
|
|
7
|
+
# Most tests verify synchronous-observable behaviour (exceptions, queue state,
|
|
8
|
+
# lock/event/semaphore flags, iscoroutine/iscoroutinefunction) because the
|
|
9
|
+
# vm.runInNewContext test runner is synchronous. Async coroutine execution
|
|
10
|
+
# is tested by verifying that async functions compile correctly and return
|
|
11
|
+
# thenable Promises.
|
|
12
|
+
|
|
13
|
+
from asyncio import (
|
|
14
|
+
sleep, gather, create_task, ensure_future, run,
|
|
15
|
+
shield, wait_for, iscoroutine, iscoroutinefunction,
|
|
16
|
+
current_task, all_tasks, get_event_loop, get_running_loop, new_event_loop,
|
|
17
|
+
CancelledError, TimeoutError, InvalidStateError, RuntimeError,
|
|
18
|
+
QueueEmpty, QueueFull,
|
|
19
|
+
Lock, Event, Semaphore, BoundedSemaphore,
|
|
20
|
+
Queue, LifoQueue, PriorityQueue
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
ae = assrt.equal
|
|
24
|
+
ade = assrt.deepEqual
|
|
25
|
+
ok = assrt.ok
|
|
26
|
+
|
|
27
|
+
# ── 1. Exception classes ─────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
raise CancelledError('cancelled')
|
|
31
|
+
ok(False)
|
|
32
|
+
except CancelledError as e:
|
|
33
|
+
ae(e.message, 'cancelled')
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
raise TimeoutError('timed out')
|
|
37
|
+
ok(False)
|
|
38
|
+
except TimeoutError as e:
|
|
39
|
+
ae(e.message, 'timed out')
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
raise InvalidStateError('bad state')
|
|
43
|
+
ok(False)
|
|
44
|
+
except InvalidStateError as e:
|
|
45
|
+
ae(e.message, 'bad state')
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
raise QueueEmpty('empty')
|
|
49
|
+
ok(False)
|
|
50
|
+
except QueueEmpty as e:
|
|
51
|
+
ae(e.message, 'empty')
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
raise QueueFull('full')
|
|
55
|
+
ok(False)
|
|
56
|
+
except QueueFull as e:
|
|
57
|
+
ae(e.message, 'full')
|
|
58
|
+
|
|
59
|
+
# ── 2. sleep / gather return Promises ────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
ok(iscoroutine(sleep(0)))
|
|
62
|
+
ok(iscoroutine(sleep(0.1)))
|
|
63
|
+
ok(iscoroutine(gather()))
|
|
64
|
+
ok(iscoroutine(gather(Promise.resolve(1), Promise.resolve(2))))
|
|
65
|
+
|
|
66
|
+
# ── 3. create_task / ensure_future / run / shield pass through Promises ──────
|
|
67
|
+
|
|
68
|
+
p = Promise.resolve(42)
|
|
69
|
+
ok(iscoroutine(create_task(p)))
|
|
70
|
+
ok(iscoroutine(ensure_future(p)))
|
|
71
|
+
ok(iscoroutine(run(p)))
|
|
72
|
+
ok(iscoroutine(shield(p)))
|
|
73
|
+
|
|
74
|
+
# ── 4. iscoroutine / iscoroutinefunction ─────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
ok(not iscoroutine(42))
|
|
77
|
+
ok(not iscoroutine(None))
|
|
78
|
+
ok(not iscoroutine('string'))
|
|
79
|
+
ok(not iscoroutine([]))
|
|
80
|
+
|
|
81
|
+
async def _async_fn():
|
|
82
|
+
return 1
|
|
83
|
+
|
|
84
|
+
ok(iscoroutinefunction(_async_fn))
|
|
85
|
+
|
|
86
|
+
def _sync_fn():
|
|
87
|
+
return 1
|
|
88
|
+
|
|
89
|
+
ok(not iscoroutinefunction(_sync_fn))
|
|
90
|
+
ok(not iscoroutinefunction(42))
|
|
91
|
+
ok(not iscoroutinefunction(None))
|
|
92
|
+
|
|
93
|
+
# Async functions return Promises
|
|
94
|
+
p2 = _async_fn()
|
|
95
|
+
ok(iscoroutine(p2))
|
|
96
|
+
|
|
97
|
+
# ── 5. current_task / all_tasks ───────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
ok(current_task() is None)
|
|
100
|
+
ok(len(all_tasks()) == 0)
|
|
101
|
+
|
|
102
|
+
# ── 6. Event loop stubs ───────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
loop = get_event_loop()
|
|
105
|
+
ok(loop is not None)
|
|
106
|
+
ok(loop is get_running_loop())
|
|
107
|
+
|
|
108
|
+
loop2 = new_event_loop()
|
|
109
|
+
ok(loop2 is not None)
|
|
110
|
+
ok(not loop2.is_closed())
|
|
111
|
+
ok(loop2.is_running())
|
|
112
|
+
|
|
113
|
+
p3 = Promise.resolve(99)
|
|
114
|
+
ok(iscoroutine(loop.run_until_complete(p3)))
|
|
115
|
+
ok(iscoroutine(loop.create_task(p3)))
|
|
116
|
+
|
|
117
|
+
# ── 7. Lock — synchronous state ──────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
lock = Lock()
|
|
120
|
+
ok(not lock.locked())
|
|
121
|
+
|
|
122
|
+
# acquire() returns a Promise (since it's async def)
|
|
123
|
+
acq = lock.acquire()
|
|
124
|
+
ok(iscoroutine(acq))
|
|
125
|
+
|
|
126
|
+
# After acquiring asynchronously lock should become locked.
|
|
127
|
+
# We can test the synchronous fast-path by observing the side-effect in a
|
|
128
|
+
# chained then (fire-and-forget style; the VM won't await it but we verify
|
|
129
|
+
# the structure is correct):
|
|
130
|
+
lock2 = Lock()
|
|
131
|
+
ok(not lock2.locked())
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
lock2.release()
|
|
135
|
+
ok(False)
|
|
136
|
+
except RuntimeError:
|
|
137
|
+
ok(True)
|
|
138
|
+
|
|
139
|
+
# ── 8. Event — synchronous set/clear/is_set ──────────────────────────────────
|
|
140
|
+
|
|
141
|
+
ev = Event()
|
|
142
|
+
ok(not ev.is_set())
|
|
143
|
+
|
|
144
|
+
ev.set()
|
|
145
|
+
ok(ev.is_set())
|
|
146
|
+
|
|
147
|
+
ev.clear()
|
|
148
|
+
ok(not ev.is_set())
|
|
149
|
+
|
|
150
|
+
# wait() returns a Promise
|
|
151
|
+
ok(iscoroutine(ev.wait()))
|
|
152
|
+
|
|
153
|
+
# If event is already set, wait() still returns a thenable
|
|
154
|
+
ev.set()
|
|
155
|
+
ok(iscoroutine(ev.wait()))
|
|
156
|
+
|
|
157
|
+
# ── 9. Semaphore — synchronous state ─────────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
sem = Semaphore(2)
|
|
160
|
+
ok(not sem.locked())
|
|
161
|
+
|
|
162
|
+
sem.release()
|
|
163
|
+
ok(not sem.locked())
|
|
164
|
+
|
|
165
|
+
sem.release()
|
|
166
|
+
ok(not sem.locked())
|
|
167
|
+
|
|
168
|
+
# acquire() returns a Promise
|
|
169
|
+
ok(iscoroutine(sem.acquire()))
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
Semaphore(-1)
|
|
173
|
+
ok(False)
|
|
174
|
+
except ValueError:
|
|
175
|
+
ok(True)
|
|
176
|
+
|
|
177
|
+
# ── 10. BoundedSemaphore ─────────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
# BoundedSemaphore(n) starts at value=n (same as bound).
|
|
180
|
+
# Releasing without a prior acquire immediately exceeds the bound.
|
|
181
|
+
bsem = BoundedSemaphore(1)
|
|
182
|
+
ok(not bsem.locked())
|
|
183
|
+
try:
|
|
184
|
+
bsem.release()
|
|
185
|
+
ok(False)
|
|
186
|
+
except ValueError:
|
|
187
|
+
ok(True)
|
|
188
|
+
|
|
189
|
+
# BoundedSemaphore(0) is always locked and cannot be released at all.
|
|
190
|
+
bsem0 = BoundedSemaphore(0)
|
|
191
|
+
ok(bsem0.locked())
|
|
192
|
+
try:
|
|
193
|
+
bsem0.release()
|
|
194
|
+
ok(False)
|
|
195
|
+
except ValueError:
|
|
196
|
+
ok(True)
|
|
197
|
+
|
|
198
|
+
# ── 11. Queue — synchronous put_nowait / get_nowait ──────────────────────────
|
|
199
|
+
|
|
200
|
+
q = Queue()
|
|
201
|
+
ok(q.empty())
|
|
202
|
+
ok(q.qsize() == 0)
|
|
203
|
+
ok(not q.full())
|
|
204
|
+
|
|
205
|
+
q.put_nowait('a')
|
|
206
|
+
q.put_nowait('b')
|
|
207
|
+
q.put_nowait('c')
|
|
208
|
+
ok(q.qsize() == 3)
|
|
209
|
+
ok(not q.empty())
|
|
210
|
+
|
|
211
|
+
ae(q.get_nowait(), 'a')
|
|
212
|
+
q.task_done()
|
|
213
|
+
ae(q.get_nowait(), 'b')
|
|
214
|
+
q.task_done()
|
|
215
|
+
ae(q.get_nowait(), 'c')
|
|
216
|
+
q.task_done()
|
|
217
|
+
ok(q.empty())
|
|
218
|
+
|
|
219
|
+
# QueueFull with bounded queue
|
|
220
|
+
q2 = Queue(2)
|
|
221
|
+
ok(not q2.full())
|
|
222
|
+
q2.put_nowait(1)
|
|
223
|
+
q2.put_nowait(2)
|
|
224
|
+
ok(q2.full())
|
|
225
|
+
try:
|
|
226
|
+
q2.put_nowait(3)
|
|
227
|
+
ok(False)
|
|
228
|
+
except QueueFull:
|
|
229
|
+
ok(True)
|
|
230
|
+
|
|
231
|
+
# QueueEmpty
|
|
232
|
+
q3 = Queue()
|
|
233
|
+
try:
|
|
234
|
+
q3.get_nowait()
|
|
235
|
+
ok(False)
|
|
236
|
+
except QueueEmpty:
|
|
237
|
+
ok(True)
|
|
238
|
+
|
|
239
|
+
# task_done() overflow check
|
|
240
|
+
q4 = Queue()
|
|
241
|
+
q4.put_nowait('x')
|
|
242
|
+
ae(q4.get_nowait(), 'x')
|
|
243
|
+
q4.task_done()
|
|
244
|
+
try:
|
|
245
|
+
q4.task_done()
|
|
246
|
+
ok(False)
|
|
247
|
+
except ValueError:
|
|
248
|
+
ok(True)
|
|
249
|
+
|
|
250
|
+
# put() and get() return Promises (async methods) — test on fresh queues
|
|
251
|
+
q5 = Queue()
|
|
252
|
+
put_p = q5.put('async-item') # no waiters, goes to internal queue
|
|
253
|
+
ok(iscoroutine(put_p))
|
|
254
|
+
ae(q5.get_nowait(), 'async-item')
|
|
255
|
+
q5.task_done()
|
|
256
|
+
|
|
257
|
+
q6 = Queue()
|
|
258
|
+
get_p = q6.get() # empty queue → adds a getter waiter
|
|
259
|
+
ok(iscoroutine(get_p))
|
|
260
|
+
|
|
261
|
+
# join() returns a Promise
|
|
262
|
+
q7 = Queue()
|
|
263
|
+
ok(iscoroutine(q7.join()))
|
|
264
|
+
|
|
265
|
+
# ── 12. LifoQueue — last-in first-out ordering ───────────────────────────────
|
|
266
|
+
|
|
267
|
+
lq = LifoQueue()
|
|
268
|
+
lq.put_nowait(1)
|
|
269
|
+
lq.put_nowait(2)
|
|
270
|
+
lq.put_nowait(3)
|
|
271
|
+
ae(lq.get_nowait(), 3)
|
|
272
|
+
ae(lq.get_nowait(), 2)
|
|
273
|
+
ae(lq.get_nowait(), 1)
|
|
274
|
+
|
|
275
|
+
# ── 13. PriorityQueue — lowest value dequeued first ──────────────────────────
|
|
276
|
+
|
|
277
|
+
pq = PriorityQueue()
|
|
278
|
+
pq.put_nowait(30)
|
|
279
|
+
pq.put_nowait(10)
|
|
280
|
+
pq.put_nowait(20)
|
|
281
|
+
ae(pq.get_nowait(), 10)
|
|
282
|
+
ae(pq.get_nowait(), 20)
|
|
283
|
+
ae(pq.get_nowait(), 30)
|
|
284
|
+
|
|
285
|
+
# ── 14. async def / await compiles correctly ─────────────────────────────────
|
|
286
|
+
|
|
287
|
+
async def _add_async(a, b):
|
|
288
|
+
return a + b
|
|
289
|
+
|
|
290
|
+
ok(iscoroutinefunction(_add_async))
|
|
291
|
+
p4 = _add_async(3, 4)
|
|
292
|
+
ok(iscoroutine(p4))
|
|
293
|
+
|
|
294
|
+
async def _chain():
|
|
295
|
+
x = await Promise.resolve(10)
|
|
296
|
+
y = await Promise.resolve(20)
|
|
297
|
+
return x + y
|
|
298
|
+
|
|
299
|
+
p5 = _chain()
|
|
300
|
+
ok(iscoroutine(p5))
|
|
301
|
+
|
|
302
|
+
async def _gather_test():
|
|
303
|
+
results = await gather(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3))
|
|
304
|
+
return results
|
|
305
|
+
|
|
306
|
+
p6 = _gather_test()
|
|
307
|
+
ok(iscoroutine(p6))
|