rapydscript-ns 0.9.2 → 0.9.4
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/CHANGELOG.md +28 -0
- package/PYTHON_GAPS.md +352 -0
- package/README.md +176 -32
- package/TODO.md +1 -128
- package/bin/rapydscript +70 -70
- package/language-service/index.js +242 -11
- package/memory/project_string_impl.md +43 -0
- package/package.json +1 -1
- 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/src/ast.pyj +10 -1
- package/src/baselib-builtins.pyj +56 -2
- package/src/baselib-containers.pyj +25 -1
- package/src/baselib-errors.pyj +7 -3
- package/src/baselib-internal.pyj +51 -6
- package/src/baselib-str.pyj +18 -5
- 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 +228 -4
- package/src/lib/csv.pyj +494 -0
- 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/logging.pyj +672 -0
- package/src/lib/pprint.pyj +455 -0
- package/src/lib/pythonize.pyj +20 -20
- package/src/lib/statistics.pyj +0 -0
- package/src/lib/string.pyj +357 -0
- package/src/lib/textwrap.pyj +329 -0
- 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/monaco-language-service/analyzer.js +5 -2
- package/src/monaco-language-service/completions.js +26 -0
- package/src/monaco-language-service/diagnostics.js +203 -4
- package/src/monaco-language-service/scope.js +1 -0
- package/src/output/codegen.pyj +4 -1
- package/src/output/functions.pyj +152 -6
- 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/parse.pyj +108 -24
- package/src/tokenizer.pyj +19 -3
- package/test/async_generators.pyj +144 -0
- package/test/asyncio.pyj +307 -0
- package/test/base64.pyj +202 -0
- package/test/baselib.pyj +23 -0
- package/test/bisect.pyj +178 -0
- package/test/chainmap.pyj +185 -0
- package/test/csv.pyj +405 -0
- package/test/float_special.pyj +64 -0
- 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/logging.pyj +356 -0
- package/test/long.pyj +130 -0
- package/test/parenthesized_with.pyj +141 -0
- package/test/pprint.pyj +232 -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/statistics.pyj +224 -0
- 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 +94 -6
- package/test/unit/language-service-completions.js +121 -0
- package/test/unit/language-service-scope.js +32 -0
- package/test/unit/language-service.js +190 -5
- package/test/unit/run-language-service.js +17 -3
- package/test/unit/web-repl.js +2401 -13
- package/test/urllib.pyj +193 -0
- package/tools/compile.js +1 -1
- package/tools/embedded_compiler.js +7 -7
- package/tools/export.js +4 -2
- package/web-repl/main.js +1 -1
- package/web-repl/rapydscript.js +7 -5
- package/test/omit_function_metadata.pyj +0 -20
package/test/csv.pyj
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
# globals: assrt
|
|
2
|
+
# vim:fileencoding=utf-8
|
|
3
|
+
#
|
|
4
|
+
# csv.pyj
|
|
5
|
+
# Tests for the csv standard library module.
|
|
6
|
+
|
|
7
|
+
from csv import reader, writer, DictReader, DictWriter
|
|
8
|
+
from csv import Dialect, excel, excel_tab, unix_dialect
|
|
9
|
+
from csv import register_dialect, unregister_dialect, get_dialect, list_dialects
|
|
10
|
+
from csv import field_size_limit, Error
|
|
11
|
+
from csv import QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE
|
|
12
|
+
from io import StringIO
|
|
13
|
+
|
|
14
|
+
ae = assrt.equal
|
|
15
|
+
ade = assrt.deepEqual
|
|
16
|
+
ok = assrt.ok
|
|
17
|
+
|
|
18
|
+
# ── 1. Constants ──────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
ae(QUOTE_MINIMAL, 0)
|
|
21
|
+
ae(QUOTE_ALL, 1)
|
|
22
|
+
ae(QUOTE_NONNUMERIC, 2)
|
|
23
|
+
ae(QUOTE_NONE, 3)
|
|
24
|
+
|
|
25
|
+
# ── 2. Basic reader — list input ──────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
_r1 = reader(['a,b,c', '1,2,3'])
|
|
28
|
+
_row = _r1.__next__()
|
|
29
|
+
ade(_row, ['a', 'b', 'c'])
|
|
30
|
+
_row = _r1.__next__()
|
|
31
|
+
ade(_row, ['1', '2', '3'])
|
|
32
|
+
_done = False
|
|
33
|
+
try:
|
|
34
|
+
_r1.__next__()
|
|
35
|
+
except StopIteration:
|
|
36
|
+
_done = True
|
|
37
|
+
ok(_done, 'reader raises StopIteration at end')
|
|
38
|
+
|
|
39
|
+
# ── 3. Reader via for loop ─────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
_rows = []
|
|
42
|
+
for _row in reader(['x,y', 'p,q']):
|
|
43
|
+
_rows.push(_row)
|
|
44
|
+
ae(_rows.length, 2)
|
|
45
|
+
ade(_rows[0], ['x', 'y'])
|
|
46
|
+
ade(_rows[1], ['p', 'q'])
|
|
47
|
+
|
|
48
|
+
# ── 4. Reader — quoted fields ─────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
_rows = []
|
|
51
|
+
for _row in reader(['"hello, world",foo', '"has ""quotes""",bar']):
|
|
52
|
+
_rows.push(_row)
|
|
53
|
+
ade(_rows[0], ['hello, world', 'foo'])
|
|
54
|
+
ade(_rows[1], ['has "quotes"', 'bar'])
|
|
55
|
+
|
|
56
|
+
# ── 5. Reader — custom delimiter ──────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
_rows = []
|
|
59
|
+
for _row in reader(['a|b|c', '1|2|3'], delimiter='|'):
|
|
60
|
+
_rows.push(_row)
|
|
61
|
+
ade(_rows[0], ['a', 'b', 'c'])
|
|
62
|
+
ade(_rows[1], ['1', '2', '3'])
|
|
63
|
+
|
|
64
|
+
# ── 6. Reader — skipinitialspace ──────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
_rows = []
|
|
67
|
+
for _row in reader(['a, b, c'], skipinitialspace=True):
|
|
68
|
+
_rows.push(_row)
|
|
69
|
+
ade(_rows[0], ['a', 'b', 'c'])
|
|
70
|
+
|
|
71
|
+
# ── 7. Reader — tab-delimited (excel-tab dialect) ────────────────────────────
|
|
72
|
+
|
|
73
|
+
_rows = []
|
|
74
|
+
for _row in reader(['a\tb\tc'], dialect='excel-tab'):
|
|
75
|
+
_rows.push(_row)
|
|
76
|
+
ade(_rows[0], ['a', 'b', 'c'])
|
|
77
|
+
|
|
78
|
+
# ── 8. Reader — QUOTE_NONNUMERIC converts unquoted fields to float ────────────
|
|
79
|
+
|
|
80
|
+
_rows = []
|
|
81
|
+
for _row in reader(['"text",3.14,42'], quoting=QUOTE_NONNUMERIC):
|
|
82
|
+
_rows.push(_row)
|
|
83
|
+
ae(_rows[0][0], 'text') # quoted → stays string
|
|
84
|
+
ae(_rows[0][1], 3.14) # unquoted numeric → float
|
|
85
|
+
ae(_rows[0][2], 42.0) # unquoted int → float
|
|
86
|
+
|
|
87
|
+
# ── 9. Reader — multi-line quoted field ───────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
_rows = []
|
|
90
|
+
for _row in reader(['"line1\nline2",b']):
|
|
91
|
+
_rows.push(_row)
|
|
92
|
+
ae(_rows[0][0], 'line1\nline2')
|
|
93
|
+
ae(_rows[0][1], 'b')
|
|
94
|
+
|
|
95
|
+
# ── 10. Reader — empty fields and trailing delimiter ─────────────────────────
|
|
96
|
+
|
|
97
|
+
_rows = []
|
|
98
|
+
for _row in reader(['a,,c', ',,']):
|
|
99
|
+
_rows.push(_row)
|
|
100
|
+
ade(_rows[0], ['a', '', 'c'])
|
|
101
|
+
ade(_rows[1], ['', '', ''])
|
|
102
|
+
|
|
103
|
+
# ── 11. Reader — file-like input (StringIO) ───────────────────────────────────
|
|
104
|
+
|
|
105
|
+
_sio_in = StringIO('hello,world\nfoo,bar\n')
|
|
106
|
+
_rows = []
|
|
107
|
+
for _row in reader(_sio_in):
|
|
108
|
+
_rows.push(_row)
|
|
109
|
+
ae(_rows.length, 2)
|
|
110
|
+
ade(_rows[0], ['hello', 'world'])
|
|
111
|
+
ade(_rows[1], ['foo', 'bar'])
|
|
112
|
+
|
|
113
|
+
# ── 12. Reader — line_num ─────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
_r2 = reader(['a,b', 'c,d', 'e,f'])
|
|
116
|
+
ae(_r2.line_num, 0)
|
|
117
|
+
_r2.__next__()
|
|
118
|
+
ae(_r2.line_num, 1)
|
|
119
|
+
_r2.__next__()
|
|
120
|
+
ae(_r2.line_num, 2)
|
|
121
|
+
|
|
122
|
+
# ── 13. Reader — list items with trailing newlines ───────────────────────────
|
|
123
|
+
|
|
124
|
+
_rows = []
|
|
125
|
+
for _row in reader(['a,b\n', 'c,d\n']):
|
|
126
|
+
_rows.push(_row)
|
|
127
|
+
ae(_rows.length, 2)
|
|
128
|
+
ade(_rows[0], ['a', 'b'])
|
|
129
|
+
ade(_rows[1], ['c', 'd'])
|
|
130
|
+
|
|
131
|
+
# ── 14. Reader — empty list ───────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
_rows = []
|
|
134
|
+
for _row in reader([]):
|
|
135
|
+
_rows.push(_row)
|
|
136
|
+
ae(_rows.length, 0)
|
|
137
|
+
|
|
138
|
+
# ── 15. Reader — single empty field ──────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
_rows = []
|
|
141
|
+
for _row in reader(['']):
|
|
142
|
+
_rows.push(_row)
|
|
143
|
+
ae(_rows.length, 1)
|
|
144
|
+
ade(_rows[0], [''])
|
|
145
|
+
|
|
146
|
+
# ── 16. Reader — dialect attribute ────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
_r3 = reader(['a,b'])
|
|
149
|
+
ae(_r3.dialect.delimiter, ',')
|
|
150
|
+
ae(_r3.dialect.quotechar, '"')
|
|
151
|
+
ok(_r3.dialect.doublequote)
|
|
152
|
+
|
|
153
|
+
# ── 17. Writer — basic writerow ───────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
_out = StringIO()
|
|
156
|
+
_w = writer(_out)
|
|
157
|
+
_w.writerow(['a', 'b', 'c'])
|
|
158
|
+
ae(_out.getvalue(), 'a,b,c\r\n')
|
|
159
|
+
|
|
160
|
+
# ── 18. Writer — writerow with field needing quoting ─────────────────────────
|
|
161
|
+
|
|
162
|
+
_out = StringIO()
|
|
163
|
+
_w = writer(_out)
|
|
164
|
+
_w.writerow(['hello, world', 'foo'])
|
|
165
|
+
ae(_out.getvalue(), '"hello, world",foo\r\n')
|
|
166
|
+
|
|
167
|
+
# ── 19. Writer — writerow quotes double-quote characters ─────────────────────
|
|
168
|
+
|
|
169
|
+
_out = StringIO()
|
|
170
|
+
_w = writer(_out)
|
|
171
|
+
_w.writerow(['say "hi"', 'ok'])
|
|
172
|
+
ae(_out.getvalue(), '"say ""hi""",ok\r\n')
|
|
173
|
+
|
|
174
|
+
# ── 20. Writer — QUOTE_ALL ────────────────────────────────────────────────────
|
|
175
|
+
|
|
176
|
+
_out = StringIO()
|
|
177
|
+
_w = writer(_out, quoting=QUOTE_ALL)
|
|
178
|
+
_w.writerow(['a', 'b', 'c'])
|
|
179
|
+
ae(_out.getvalue(), '"a","b","c"\r\n')
|
|
180
|
+
|
|
181
|
+
# ── 21. Writer — QUOTE_NONE with escapechar ───────────────────────────────────
|
|
182
|
+
|
|
183
|
+
_out = StringIO()
|
|
184
|
+
_w = writer(_out, quoting=QUOTE_NONE, escapechar='\\')
|
|
185
|
+
_w.writerow(['a,b', 'c'])
|
|
186
|
+
ae(_out.getvalue(), 'a\\,b,c\r\n')
|
|
187
|
+
|
|
188
|
+
# ── 22. Writer — custom delimiter ─────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
_out = StringIO()
|
|
191
|
+
_w = writer(_out, delimiter='|')
|
|
192
|
+
_w.writerow(['x', 'y', 'z'])
|
|
193
|
+
ae(_out.getvalue(), 'x|y|z\r\n')
|
|
194
|
+
|
|
195
|
+
# ── 23. Writer — writerows ────────────────────────────────────────────────────
|
|
196
|
+
|
|
197
|
+
_out = StringIO()
|
|
198
|
+
_w = writer(_out)
|
|
199
|
+
_w.writerows([['1', '2'], ['3', '4']])
|
|
200
|
+
ae(_out.getvalue(), '1,2\r\n3,4\r\n')
|
|
201
|
+
|
|
202
|
+
# ── 24. Writer — unix dialect (lineterminator=\n) ────────────────────────────
|
|
203
|
+
|
|
204
|
+
_out = StringIO()
|
|
205
|
+
_w = writer(_out, dialect='unix')
|
|
206
|
+
_w.writerow(['a', 'b'])
|
|
207
|
+
ae(_out.getvalue(), '"a","b"\n')
|
|
208
|
+
|
|
209
|
+
# ── 25. Writer — numeric values ───────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
_out = StringIO()
|
|
212
|
+
_w = writer(_out)
|
|
213
|
+
_w.writerow([1, 3.14, True])
|
|
214
|
+
ae(_out.getvalue(), '1,3.14,true\r\n')
|
|
215
|
+
|
|
216
|
+
# ── 26. DictReader — fieldnames from first row ───────────────────────────────
|
|
217
|
+
|
|
218
|
+
_dr = DictReader(['name,age', 'Alice,30', 'Bob,25'])
|
|
219
|
+
_rows = []
|
|
220
|
+
for _row in _dr:
|
|
221
|
+
_rows.push(_row)
|
|
222
|
+
ae(_rows.length, 2)
|
|
223
|
+
ae(_rows[0]['name'], 'Alice')
|
|
224
|
+
ae(_rows[0]['age'], '30')
|
|
225
|
+
ae(_rows[1]['name'], 'Bob')
|
|
226
|
+
ae(_rows[1]['age'], '25')
|
|
227
|
+
|
|
228
|
+
# ── 27. DictReader — provided fieldnames ─────────────────────────────────────
|
|
229
|
+
|
|
230
|
+
_dr2 = DictReader(['Alice,30', 'Bob,25'], fieldnames=['name', 'age'])
|
|
231
|
+
_rows = []
|
|
232
|
+
for _row in _dr2:
|
|
233
|
+
_rows.push(_row)
|
|
234
|
+
ae(_rows.length, 2)
|
|
235
|
+
ae(_rows[0]['name'], 'Alice')
|
|
236
|
+
ae(_rows[0]['age'], '30')
|
|
237
|
+
|
|
238
|
+
# ── 28. DictReader — restval for missing fields ───────────────────────────────
|
|
239
|
+
|
|
240
|
+
_dr3 = DictReader(['name,age,city', 'Alice,30'], restval='N/A')
|
|
241
|
+
_rows = []
|
|
242
|
+
for _row in _dr3:
|
|
243
|
+
_rows.push(_row)
|
|
244
|
+
ae(_rows[0]['city'], 'N/A')
|
|
245
|
+
|
|
246
|
+
# ── 29. DictReader — extra fields go to restkey ──────────────────────────────
|
|
247
|
+
|
|
248
|
+
_dr4 = DictReader(['name,age', 'Alice,30,extra1,extra2'])
|
|
249
|
+
_row = _dr4.__next__()
|
|
250
|
+
ok(_row['EXTRA'] is not None)
|
|
251
|
+
ae(_row['EXTRA'].length, 2)
|
|
252
|
+
ae(_row['EXTRA'][0], 'extra1')
|
|
253
|
+
|
|
254
|
+
# ── 30. DictReader — empty input ─────────────────────────────────────────────
|
|
255
|
+
|
|
256
|
+
_dr5 = DictReader([])
|
|
257
|
+
_empty = True
|
|
258
|
+
for _row in _dr5:
|
|
259
|
+
_empty = False
|
|
260
|
+
ok(_empty, 'DictReader on empty input produces no rows')
|
|
261
|
+
|
|
262
|
+
# ── 31. DictWriter — basic writerow ──────────────────────────────────────────
|
|
263
|
+
|
|
264
|
+
_out = StringIO()
|
|
265
|
+
_dw = DictWriter(_out, ['name', 'age'])
|
|
266
|
+
_dw.writerow({'name': 'Alice', 'age': '30'})
|
|
267
|
+
ae(_out.getvalue(), 'Alice,30\r\n')
|
|
268
|
+
|
|
269
|
+
# ── 32. DictWriter — writeheader ──────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
_out = StringIO()
|
|
272
|
+
_dw = DictWriter(_out, ['name', 'age'])
|
|
273
|
+
_dw.writeheader()
|
|
274
|
+
ae(_out.getvalue(), 'name,age\r\n')
|
|
275
|
+
|
|
276
|
+
# ── 33. DictWriter — restval for missing fields ───────────────────────────────
|
|
277
|
+
|
|
278
|
+
_out = StringIO()
|
|
279
|
+
_dw = DictWriter(_out, ['name', 'age', 'city'], restval='')
|
|
280
|
+
_dw.writerow({'name': 'Alice', 'age': '30'})
|
|
281
|
+
ae(_out.getvalue(), 'Alice,30,\r\n')
|
|
282
|
+
|
|
283
|
+
# ── 34. DictWriter — writerows ────────────────────────────────────────────────
|
|
284
|
+
|
|
285
|
+
_out = StringIO()
|
|
286
|
+
_dw = DictWriter(_out, ['x', 'y'])
|
|
287
|
+
_dw.writerows([{'x': '1', 'y': '2'}, {'x': '3', 'y': '4'}])
|
|
288
|
+
ae(_out.getvalue(), '1,2\r\n3,4\r\n')
|
|
289
|
+
|
|
290
|
+
# ── 35. DictWriter — extrasaction='raise' detects unknown fields ──────────────
|
|
291
|
+
|
|
292
|
+
_out = StringIO()
|
|
293
|
+
_dw2 = DictWriter(_out, ['name'], extrasaction='raise')
|
|
294
|
+
_extra_raised = False
|
|
295
|
+
try:
|
|
296
|
+
_dw2.writerow({'name': 'Alice', 'foo': 'bar'})
|
|
297
|
+
except ValueError:
|
|
298
|
+
_extra_raised = True
|
|
299
|
+
ok(_extra_raised, "DictWriter extrasaction='raise' should raise ValueError for extra fields")
|
|
300
|
+
|
|
301
|
+
# ── 36. DictWriter — extrasaction='ignore' silently ignores extra fields ──────
|
|
302
|
+
|
|
303
|
+
_out = StringIO()
|
|
304
|
+
_dw3 = DictWriter(_out, ['name'], extrasaction='ignore')
|
|
305
|
+
_dw3.writerow({'name': 'Alice', 'extra': 'ignored'})
|
|
306
|
+
ae(_out.getvalue(), 'Alice\r\n')
|
|
307
|
+
|
|
308
|
+
# ── 37. register_dialect / list_dialects / get_dialect ───────────────────────
|
|
309
|
+
|
|
310
|
+
register_dialect('pipes', delimiter='|')
|
|
311
|
+
_dl = list_dialects()
|
|
312
|
+
ok(_dl.indexOf('pipes') >= 0, 'pipes dialect should be in list_dialects()')
|
|
313
|
+
|
|
314
|
+
_d = get_dialect('pipes')
|
|
315
|
+
ae(_d.delimiter, '|')
|
|
316
|
+
|
|
317
|
+
_out = StringIO()
|
|
318
|
+
_w = writer(_out, dialect='pipes')
|
|
319
|
+
_w.writerow(['a', 'b'])
|
|
320
|
+
ae(_out.getvalue(), 'a|b\r\n')
|
|
321
|
+
|
|
322
|
+
# ── 38. unregister_dialect ────────────────────────────────────────────────────
|
|
323
|
+
|
|
324
|
+
unregister_dialect('pipes')
|
|
325
|
+
_dl2 = list_dialects()
|
|
326
|
+
ok(_dl2.indexOf('pipes') < 0, 'pipes dialect removed after unregister_dialect')
|
|
327
|
+
|
|
328
|
+
_err_raised = False
|
|
329
|
+
try:
|
|
330
|
+
get_dialect('pipes')
|
|
331
|
+
except Error:
|
|
332
|
+
_err_raised = True
|
|
333
|
+
ok(_err_raised, 'get_dialect on unknown name should raise csv.Error')
|
|
334
|
+
|
|
335
|
+
# ── 39. unregister_dialect on built-ins raises Error ─────────────────────────
|
|
336
|
+
|
|
337
|
+
_unregister_bad = False
|
|
338
|
+
try:
|
|
339
|
+
unregister_dialect('no_such_dialect')
|
|
340
|
+
except Error:
|
|
341
|
+
_unregister_bad = True
|
|
342
|
+
ok(_unregister_bad, 'unregister_dialect on unknown name should raise csv.Error')
|
|
343
|
+
|
|
344
|
+
# ── 40. reader with unknown dialect raises Error ──────────────────────────────
|
|
345
|
+
|
|
346
|
+
_bad_dialect = False
|
|
347
|
+
try:
|
|
348
|
+
reader(['a,b'], dialect='nonexistent')
|
|
349
|
+
except Error:
|
|
350
|
+
_bad_dialect = True
|
|
351
|
+
ok(_bad_dialect, 'reader with unknown dialect should raise csv.Error')
|
|
352
|
+
|
|
353
|
+
# ── 41. field_size_limit ──────────────────────────────────────────────────────
|
|
354
|
+
|
|
355
|
+
ae(field_size_limit(), 131072)
|
|
356
|
+
_old = field_size_limit(65536)
|
|
357
|
+
ae(_old, 131072)
|
|
358
|
+
ae(field_size_limit(), 65536)
|
|
359
|
+
field_size_limit(131072) # restore
|
|
360
|
+
|
|
361
|
+
# ── 42. list_dialects includes defaults ───────────────────────────────────────
|
|
362
|
+
|
|
363
|
+
_default_dialects = list_dialects()
|
|
364
|
+
ok(_default_dialects.indexOf('excel') >= 0)
|
|
365
|
+
ok(_default_dialects.indexOf('excel-tab') >= 0)
|
|
366
|
+
ok(_default_dialects.indexOf('unix') >= 0)
|
|
367
|
+
|
|
368
|
+
# ── 43. Writer — dialect attribute ────────────────────────────────────────────
|
|
369
|
+
|
|
370
|
+
_out = StringIO()
|
|
371
|
+
_w4 = writer(_out, dialect='excel-tab')
|
|
372
|
+
ae(_w4.dialect.delimiter, '\t')
|
|
373
|
+
|
|
374
|
+
# ── 44. Round-trip: write then read ──────────────────────────────────────────
|
|
375
|
+
|
|
376
|
+
_buf = StringIO()
|
|
377
|
+
_wrt = writer(_buf)
|
|
378
|
+
_wrt.writerow(['name', 'age', 'city'])
|
|
379
|
+
_wrt.writerow(['Alice', '30', 'New York'])
|
|
380
|
+
_wrt.writerow(['Bob\'s Diner', '25', 'Los Angeles, CA'])
|
|
381
|
+
_buf.seek(0)
|
|
382
|
+
_result = []
|
|
383
|
+
for _r in reader(_buf):
|
|
384
|
+
_result.push(_r)
|
|
385
|
+
ae(_result.length, 3)
|
|
386
|
+
ade(_result[0], ['name', 'age', 'city'])
|
|
387
|
+
ade(_result[1], ['Alice', '30', 'New York'])
|
|
388
|
+
ade(_result[2], ["Bob's Diner", '25', 'Los Angeles, CA'])
|
|
389
|
+
|
|
390
|
+
# ── 45. Round-trip: DictWriter then DictReader ───────────────────────────────
|
|
391
|
+
|
|
392
|
+
_buf2 = StringIO()
|
|
393
|
+
_dw4 = DictWriter(_buf2, ['name', 'score'])
|
|
394
|
+
_dw4.writeheader()
|
|
395
|
+
_dw4.writerow({'name': 'Eve', 'score': '99'})
|
|
396
|
+
_dw4.writerow({'name': 'Frank', 'score': '88'})
|
|
397
|
+
_buf2.seek(0)
|
|
398
|
+
_result2 = []
|
|
399
|
+
for _r in DictReader(_buf2):
|
|
400
|
+
_result2.push(_r)
|
|
401
|
+
ae(_result2.length, 2)
|
|
402
|
+
ae(_result2[0]['name'], 'Eve')
|
|
403
|
+
ae(_result2[0]['score'], '99')
|
|
404
|
+
ae(_result2[1]['name'], 'Frank')
|
|
405
|
+
ae(_result2[1]['score'], '88')
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# vim:fileencoding=utf-8
|
|
2
|
+
# globals: assrt
|
|
3
|
+
|
|
4
|
+
ae = assrt.equal
|
|
5
|
+
ok = assrt.ok
|
|
6
|
+
|
|
7
|
+
# ── float() — special string values ───────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
# 'inf' / '+inf'
|
|
10
|
+
ae(float('inf'), v'Infinity')
|
|
11
|
+
ae(float('+inf'), v'Infinity')
|
|
12
|
+
ae(float('INF'), v'Infinity')
|
|
13
|
+
ae(float('Inf'), v'Infinity')
|
|
14
|
+
|
|
15
|
+
# '-inf'
|
|
16
|
+
ae(float('-inf'), v'-Infinity')
|
|
17
|
+
ae(float('-INF'), v'-Infinity')
|
|
18
|
+
ae(float('-Inf'), v'-Infinity')
|
|
19
|
+
|
|
20
|
+
# 'infinity' variants
|
|
21
|
+
ae(float('infinity'), v'Infinity')
|
|
22
|
+
ae(float('+infinity'), v'Infinity')
|
|
23
|
+
ae(float('-infinity'), v'-Infinity')
|
|
24
|
+
ae(float('Infinity'), v'Infinity')
|
|
25
|
+
ae(float('+Infinity'), v'Infinity')
|
|
26
|
+
ae(float('-Infinity'), v'-Infinity')
|
|
27
|
+
ae(float('INFINITY'), v'Infinity')
|
|
28
|
+
ae(float('-INFINITY'), v'-Infinity')
|
|
29
|
+
|
|
30
|
+
# 'nan' variants
|
|
31
|
+
ok(isNaN(float('nan')))
|
|
32
|
+
ok(isNaN(float('NaN')))
|
|
33
|
+
ok(isNaN(float('NAN')))
|
|
34
|
+
ok(isNaN(float('+nan')))
|
|
35
|
+
ok(isNaN(float('-nan')))
|
|
36
|
+
|
|
37
|
+
# leading/trailing whitespace is accepted (matches Python)
|
|
38
|
+
ae(float(' inf '), v'Infinity')
|
|
39
|
+
ae(float(' -inf '), v'-Infinity')
|
|
40
|
+
ok(isNaN(float(' nan ')))
|
|
41
|
+
|
|
42
|
+
# numeric strings still work
|
|
43
|
+
ae(float('3.14'), 3.14)
|
|
44
|
+
ae(float('1e10'), 1e10)
|
|
45
|
+
ae(float('-2.5'), -2.5)
|
|
46
|
+
|
|
47
|
+
# passing a real Infinity/NaN JS value through float() still works
|
|
48
|
+
ae(float(v'Infinity'), v'Infinity')
|
|
49
|
+
ae(float(v'-Infinity'), v'-Infinity')
|
|
50
|
+
|
|
51
|
+
# ValueError is still raised for unrecognised strings
|
|
52
|
+
_err = False
|
|
53
|
+
try:
|
|
54
|
+
float('not_a_number')
|
|
55
|
+
except ValueError:
|
|
56
|
+
_err = True
|
|
57
|
+
ok(_err)
|
|
58
|
+
|
|
59
|
+
_err2 = False
|
|
60
|
+
try:
|
|
61
|
+
float('')
|
|
62
|
+
except ValueError:
|
|
63
|
+
_err2 = True
|
|
64
|
+
ok(_err2)
|
package/test/heapq.pyj
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# globals: assrt
|
|
2
|
+
# vim:fileencoding=utf-8
|
|
3
|
+
#
|
|
4
|
+
# heapq.pyj
|
|
5
|
+
# Tests for the heapq standard library module.
|
|
6
|
+
|
|
7
|
+
from heapq import heappush, heappop, heapify, heapreplace, heappushpop, nlargest, nsmallest
|
|
8
|
+
|
|
9
|
+
ae = assrt.equal
|
|
10
|
+
ade = assrt.deepEqual
|
|
11
|
+
ok = assrt.ok
|
|
12
|
+
|
|
13
|
+
# ── 1. heappush / heappop — basic sort order ──────────────────────────────────
|
|
14
|
+
|
|
15
|
+
h = []
|
|
16
|
+
heappush(h, 3)
|
|
17
|
+
heappush(h, 1)
|
|
18
|
+
heappush(h, 4)
|
|
19
|
+
heappush(h, 1)
|
|
20
|
+
heappush(h, 5)
|
|
21
|
+
ae(heappop(h), 1)
|
|
22
|
+
ae(heappop(h), 1)
|
|
23
|
+
ae(heappop(h), 3)
|
|
24
|
+
ae(heappop(h), 4)
|
|
25
|
+
ae(heappop(h), 5)
|
|
26
|
+
ae(h.length, 0)
|
|
27
|
+
|
|
28
|
+
# ── 2. heapify — min at root ──────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
x = [5, 3, 8, 1, 2, 4]
|
|
31
|
+
heapify(x)
|
|
32
|
+
ae(x[0], 1)
|
|
33
|
+
|
|
34
|
+
# verify heap invariant: every parent <= its children
|
|
35
|
+
_hi = 0
|
|
36
|
+
while _hi < Math.floor(x.length / 2):
|
|
37
|
+
_left = 2 * _hi + 1
|
|
38
|
+
_right = 2 * _hi + 2
|
|
39
|
+
ok(x[_hi] <= x[_left], 'parent <= left child at ' + str(_hi))
|
|
40
|
+
if _right < x.length:
|
|
41
|
+
ok(x[_hi] <= x[_right], 'parent <= right child at ' + str(_hi))
|
|
42
|
+
_hi += 1
|
|
43
|
+
|
|
44
|
+
# ── 3. heapify + heappop produces sorted output ───────────────────────────────
|
|
45
|
+
|
|
46
|
+
_sort_data = [5, 3, 8, 1, 2, 4]
|
|
47
|
+
heapify(_sort_data)
|
|
48
|
+
_sort_result = []
|
|
49
|
+
while _sort_data.length > 0:
|
|
50
|
+
_sort_result.push(heappop(_sort_data))
|
|
51
|
+
ade(_sort_result, [1, 2, 3, 4, 5, 8])
|
|
52
|
+
|
|
53
|
+
# ── 4. heapreplace — returns old min, inserts new item ────────────────────────
|
|
54
|
+
|
|
55
|
+
_r = [1, 3, 5, 7, 9]
|
|
56
|
+
heapify(_r)
|
|
57
|
+
_old = heapreplace(_r, 4)
|
|
58
|
+
ae(_old, 1)
|
|
59
|
+
ae(_r[0], 3)
|
|
60
|
+
|
|
61
|
+
_r_sorted = []
|
|
62
|
+
while _r.length > 0:
|
|
63
|
+
_r_sorted.push(heappop(_r))
|
|
64
|
+
ade(_r_sorted, [3, 4, 5, 7, 9])
|
|
65
|
+
|
|
66
|
+
# ── 5. heappushpop ────────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
# item > heap[0]: swap root out, sift new item in
|
|
69
|
+
_pp = [1, 3, 5]
|
|
70
|
+
heapify(_pp)
|
|
71
|
+
_res_pp = heappushpop(_pp, 2)
|
|
72
|
+
ae(_res_pp, 1)
|
|
73
|
+
ae(_pp[0], 2)
|
|
74
|
+
|
|
75
|
+
# item <= heap[0]: return item unchanged, heap unmodified
|
|
76
|
+
_pp2 = [5, 7, 9]
|
|
77
|
+
heapify(_pp2)
|
|
78
|
+
_res_pp2 = heappushpop(_pp2, 4)
|
|
79
|
+
ae(_res_pp2, 4)
|
|
80
|
+
ae(_pp2[0], 5)
|
|
81
|
+
|
|
82
|
+
# ── 6. heappop raises IndexError on empty heap ────────────────────────────────
|
|
83
|
+
|
|
84
|
+
_pop_err = False
|
|
85
|
+
try:
|
|
86
|
+
heappop([])
|
|
87
|
+
except IndexError:
|
|
88
|
+
_pop_err = True
|
|
89
|
+
ok(_pop_err, 'heappop on empty heap raises IndexError')
|
|
90
|
+
|
|
91
|
+
# ── 7. heapreplace raises IndexError on empty heap ───────────────────────────
|
|
92
|
+
|
|
93
|
+
_rep_err = False
|
|
94
|
+
try:
|
|
95
|
+
heapreplace([], 1)
|
|
96
|
+
except IndexError:
|
|
97
|
+
_rep_err = True
|
|
98
|
+
ok(_rep_err, 'heapreplace on empty heap raises IndexError')
|
|
99
|
+
|
|
100
|
+
# ── 8. nsmallest — basic ─────────────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
_ns_data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
|
|
103
|
+
ade(nsmallest(3, _ns_data), [1, 1, 2])
|
|
104
|
+
ade(nsmallest(1, _ns_data), [1])
|
|
105
|
+
ade(nsmallest(0, _ns_data), [])
|
|
106
|
+
ade(nsmallest(100, _ns_data), [1, 1, 2, 3, 3, 4, 5, 5, 6, 9])
|
|
107
|
+
|
|
108
|
+
# ── 9. nlargest — basic ──────────────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
ade(nlargest(3, _ns_data), [9, 6, 5])
|
|
111
|
+
ade(nlargest(1, _ns_data), [9])
|
|
112
|
+
ade(nlargest(0, _ns_data), [])
|
|
113
|
+
ade(nlargest(100, _ns_data), [9, 6, 5, 5, 4, 3, 3, 2, 1, 1])
|
|
114
|
+
|
|
115
|
+
# ── 10. nsmallest / nlargest with key ────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
_pairs = [[3, 'c'], [1, 'a'], [4, 'd'], [1, 'b'], [5, 'e']]
|
|
118
|
+
_kfn = def(p): return p[0];
|
|
119
|
+
|
|
120
|
+
_sm2 = nsmallest(2, _pairs, key=_kfn)
|
|
121
|
+
ae(_sm2.length, 2)
|
|
122
|
+
ae(_sm2[0][0], 1)
|
|
123
|
+
ae(_sm2[1][0], 1)
|
|
124
|
+
|
|
125
|
+
_lg2 = nlargest(2, _pairs, key=_kfn)
|
|
126
|
+
ae(_lg2.length, 2)
|
|
127
|
+
ae(_lg2[0][0], 5)
|
|
128
|
+
ae(_lg2[1][0], 4)
|
|
129
|
+
|
|
130
|
+
# ── 11. Single element ────────────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
_single = [42]
|
|
133
|
+
heapify(_single)
|
|
134
|
+
ae(_single[0], 42)
|
|
135
|
+
ae(heappop(_single), 42)
|
|
136
|
+
ae(_single.length, 0)
|
|
137
|
+
|
|
138
|
+
# ── 12. Negative numbers ─────────────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
_neg = [-3, -1, -4, -1, -5]
|
|
141
|
+
heapify(_neg)
|
|
142
|
+
_neg_sorted = []
|
|
143
|
+
while _neg.length > 0:
|
|
144
|
+
_neg_sorted.push(heappop(_neg))
|
|
145
|
+
ade(_neg_sorted, [-5, -4, -3, -1, -1])
|
|
146
|
+
|
|
147
|
+
# ── 13. Duplicates ───────────────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
_dups = [2, 2, 2, 1, 1, 1, 3, 3, 3]
|
|
150
|
+
heapify(_dups)
|
|
151
|
+
_dups_sorted = []
|
|
152
|
+
while _dups.length > 0:
|
|
153
|
+
_dups_sorted.push(heappop(_dups))
|
|
154
|
+
ade(_dups_sorted, [1, 1, 1, 2, 2, 2, 3, 3, 3])
|
|
155
|
+
|
|
156
|
+
# ── 14. heappush onto pre-existing heap ──────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
_pre = [2, 5, 8]
|
|
159
|
+
heapify(_pre)
|
|
160
|
+
heappush(_pre, 1)
|
|
161
|
+
ae(_pre[0], 1)
|
|
162
|
+
heappush(_pre, 3)
|
|
163
|
+
_pre_sorted = []
|
|
164
|
+
while _pre.length > 0:
|
|
165
|
+
_pre_sorted.push(heappop(_pre))
|
|
166
|
+
ade(_pre_sorted, [1, 2, 3, 5, 8])
|
|
167
|
+
|
|
168
|
+
# ── 15. nsmallest / nlargest do not mutate original ──────────────────────────
|
|
169
|
+
|
|
170
|
+
_orig = [5, 2, 8, 1, 9]
|
|
171
|
+
_orig_copy = _orig.slice()
|
|
172
|
+
nsmallest(3, _orig)
|
|
173
|
+
nlargest(3, _orig)
|
|
174
|
+
ade(_orig, _orig_copy)
|