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.
Files changed (88) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/PYTHON_GAPS.md +352 -0
  3. package/README.md +176 -32
  4. package/TODO.md +1 -128
  5. package/bin/rapydscript +70 -70
  6. package/language-service/index.js +242 -11
  7. package/memory/project_string_impl.md +43 -0
  8. package/package.json +1 -1
  9. package/release/baselib-plain-pretty.js +248 -38
  10. package/release/baselib-plain-ugly.js +8 -8
  11. package/release/compiler.js +778 -277
  12. package/release/signatures.json +30 -30
  13. package/src/ast.pyj +10 -1
  14. package/src/baselib-builtins.pyj +56 -2
  15. package/src/baselib-containers.pyj +25 -1
  16. package/src/baselib-errors.pyj +7 -3
  17. package/src/baselib-internal.pyj +51 -6
  18. package/src/baselib-str.pyj +18 -5
  19. package/src/lib/asyncio.pyj +534 -0
  20. package/src/lib/base64.pyj +399 -0
  21. package/src/lib/bisect.pyj +73 -0
  22. package/src/lib/collections.pyj +228 -4
  23. package/src/lib/csv.pyj +494 -0
  24. package/src/lib/heapq.pyj +98 -0
  25. package/src/lib/html.pyj +382 -0
  26. package/src/lib/http/__init__.pyj +98 -0
  27. package/src/lib/http/client.pyj +304 -0
  28. package/src/lib/http/cookies.pyj +236 -0
  29. package/src/lib/logging.pyj +672 -0
  30. package/src/lib/pprint.pyj +455 -0
  31. package/src/lib/pythonize.pyj +20 -20
  32. package/src/lib/statistics.pyj +0 -0
  33. package/src/lib/string.pyj +357 -0
  34. package/src/lib/textwrap.pyj +329 -0
  35. package/src/lib/urllib/__init__.pyj +14 -0
  36. package/src/lib/urllib/error.pyj +66 -0
  37. package/src/lib/urllib/parse.pyj +475 -0
  38. package/src/lib/urllib/request.pyj +86 -0
  39. package/src/monaco-language-service/analyzer.js +5 -2
  40. package/src/monaco-language-service/completions.js +26 -0
  41. package/src/monaco-language-service/diagnostics.js +203 -4
  42. package/src/monaco-language-service/scope.js +1 -0
  43. package/src/output/codegen.pyj +4 -1
  44. package/src/output/functions.pyj +152 -6
  45. package/src/output/loops.pyj +17 -2
  46. package/src/output/modules.pyj +1 -1
  47. package/src/output/operators.pyj +15 -0
  48. package/src/output/stream.pyj +0 -1
  49. package/src/parse.pyj +108 -24
  50. package/src/tokenizer.pyj +19 -3
  51. package/test/async_generators.pyj +144 -0
  52. package/test/asyncio.pyj +307 -0
  53. package/test/base64.pyj +202 -0
  54. package/test/baselib.pyj +23 -0
  55. package/test/bisect.pyj +178 -0
  56. package/test/chainmap.pyj +185 -0
  57. package/test/csv.pyj +405 -0
  58. package/test/float_special.pyj +64 -0
  59. package/test/heapq.pyj +174 -0
  60. package/test/html.pyj +212 -0
  61. package/test/http.pyj +259 -0
  62. package/test/imports.pyj +79 -72
  63. package/test/logging.pyj +356 -0
  64. package/test/long.pyj +130 -0
  65. package/test/parenthesized_with.pyj +141 -0
  66. package/test/pprint.pyj +232 -0
  67. package/test/python_compat.pyj +3 -5
  68. package/test/python_modulo.pyj +76 -0
  69. package/test/python_modulo_off.pyj +21 -0
  70. package/test/statistics.pyj +224 -0
  71. package/test/str.pyj +14 -0
  72. package/test/string.pyj +245 -0
  73. package/test/textwrap.pyj +172 -0
  74. package/test/type_display.pyj +48 -0
  75. package/test/type_enforcement.pyj +164 -0
  76. package/test/unit/index.js +94 -6
  77. package/test/unit/language-service-completions.js +121 -0
  78. package/test/unit/language-service-scope.js +32 -0
  79. package/test/unit/language-service.js +190 -5
  80. package/test/unit/run-language-service.js +17 -3
  81. package/test/unit/web-repl.js +2401 -13
  82. package/test/urllib.pyj +193 -0
  83. package/tools/compile.js +1 -1
  84. package/tools/embedded_compiler.js +7 -7
  85. package/tools/export.js +4 -2
  86. package/web-repl/main.js +1 -1
  87. package/web-repl/rapydscript.js +7 -5
  88. package/test/omit_function_metadata.pyj +0 -20
@@ -0,0 +1,356 @@
1
+ # globals: assrt
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # logging.pyj
5
+ # Tests for the logging standard library module.
6
+
7
+ from logging import (
8
+ Logger, Handler, StreamHandler, NullHandler, Formatter, Filter,
9
+ LogRecord, makeLogRecord,
10
+ getLogger, basicConfig, disable,
11
+ addLevelName, getLevelName,
12
+ NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL,
13
+ lastResort, root,
14
+ )
15
+ import logging
16
+
17
+ ae = assrt.equal
18
+ ade = assrt.deepEqual
19
+ ok = assrt.ok
20
+
21
+
22
+ # ── 1. Level constants ────────────────────────────────────────────────────────
23
+
24
+ ae(NOTSET, 0)
25
+ ae(DEBUG, 10)
26
+ ae(INFO, 20)
27
+ ae(WARNING, 30)
28
+ ae(ERROR, 40)
29
+ ae(CRITICAL, 50)
30
+ ae(logging.WARN, WARNING)
31
+ ae(logging.FATAL, CRITICAL)
32
+
33
+
34
+ # ── 2. getLevelName ───────────────────────────────────────────────────────────
35
+
36
+ ae(getLevelName(DEBUG), 'DEBUG')
37
+ ae(getLevelName(INFO), 'INFO')
38
+ ae(getLevelName(WARNING), 'WARNING')
39
+ ae(getLevelName(ERROR), 'ERROR')
40
+ ae(getLevelName(CRITICAL), 'CRITICAL')
41
+ ae(getLevelName(0), 'NOTSET')
42
+ ae(getLevelName(42), 'Level 42')
43
+
44
+ ae(getLevelName('DEBUG'), DEBUG)
45
+ ae(getLevelName('WARNING'), WARNING)
46
+ ae(getLevelName('CRITICAL'), CRITICAL)
47
+ ae(getLevelName('WARN'), WARNING)
48
+ ae(getLevelName('FATAL'), CRITICAL)
49
+
50
+
51
+ # ── 3. addLevelName ───────────────────────────────────────────────────────────
52
+
53
+ addLevelName(25, 'TRACE')
54
+ ae(getLevelName(25), 'TRACE')
55
+ ae(getLevelName('TRACE'), 25)
56
+
57
+
58
+ # ── 4. LogRecord.getMessage — %-formatting ────────────────────────────────────
59
+
60
+ _r1 = LogRecord('test', DEBUG, '', 0, 'hello world', [], None)
61
+ ae(_r1.getMessage(), 'hello world')
62
+
63
+ _r2 = LogRecord('test', INFO, '', 0, 'Hello %s', ['Alice'], None)
64
+ ae(_r2.getMessage(), 'Hello Alice')
65
+
66
+ _r3 = LogRecord('test', WARNING, '', 0, 'Val=%d x=%f', [42, 3.14], None)
67
+ ae(_r3.getMessage(), 'Val=42 x=3.140000')
68
+
69
+ _r4 = LogRecord('test', ERROR, '', 0, '100%%', [], None)
70
+ ae(_r4.getMessage(), '100%')
71
+
72
+
73
+ # ── 5. LogRecord attributes ───────────────────────────────────────────────────
74
+
75
+ _r5 = LogRecord('myapp', ERROR, '/foo.py', 10, 'boom', [], None)
76
+ ae(_r5.name, 'myapp')
77
+ ae(_r5.levelno, ERROR)
78
+ ae(_r5.levelname, 'ERROR')
79
+ ae(_r5.lineno, 10)
80
+ ae(_r5.threadName, 'MainThread')
81
+ ok(_r5.created > 0, 'created is positive')
82
+ ok(_r5.relativeCreated >= 0, 'relativeCreated is non-negative')
83
+
84
+
85
+ # ── 6. makeLogRecord ──────────────────────────────────────────────────────────
86
+
87
+ _d = {}
88
+ _d['name'] = 'foo'
89
+ _d['levelno'] = WARNING
90
+ _d['msg'] = 'hi'
91
+ _mr = makeLogRecord(_d)
92
+ ae(_mr.name, 'foo')
93
+ ae(_mr.levelno, WARNING)
94
+ ae(_mr.msg, 'hi')
95
+
96
+
97
+ # ── 7. Formatter ──────────────────────────────────────────────────────────────
98
+
99
+ class _Buf:
100
+ def __init__(self):
101
+ self.lines = []
102
+ def write(self, s):
103
+ self.lines.push(s)
104
+
105
+
106
+ _fmt1 = Formatter('%(levelname)s:%(name)s:%(message)s')
107
+ _rec = LogRecord('myapp', INFO, '', 0, 'hello', [], None)
108
+ ae(_fmt1.format(_rec), 'INFO:myapp:hello')
109
+
110
+ _fmt2 = Formatter('%(levelno)d %(name)s %(message)s')
111
+ _rec2 = LogRecord('app', WARNING, '', 0, 'watch out', [], None)
112
+ ae(_fmt2.format(_rec2), '30 app watch out')
113
+
114
+ ok(_fmt1.usesTime() is False, 'usesTime False')
115
+ _fmt3 = Formatter('%(asctime)s %(message)s')
116
+ ok(_fmt3.usesTime() is True, 'usesTime True')
117
+
118
+ # asctime must be a non-empty string
119
+ _rec3 = LogRecord('t', INFO, '', 0, 'msg', [], None)
120
+ _s3 = _fmt3.format(_rec3)
121
+ ok(_s3.length > 5, 'asctime result is non-empty')
122
+
123
+
124
+ # ── 8. Filter ─────────────────────────────────────────────────────────────────
125
+
126
+ _f_all = Filter()
127
+ _f_app = Filter('myapp')
128
+ _f_sub = Filter('myapp.sub')
129
+
130
+ _rA = LogRecord('myapp', INFO, '', 0, 'm', [], None)
131
+ _rB = LogRecord('myapp.sub', INFO, '', 0, 'm', [], None)
132
+ _rC = LogRecord('myapp.sub.x', INFO, '', 0, 'm', [], None)
133
+ _rD = LogRecord('otherapp', INFO, '', 0, 'm', [], None)
134
+
135
+ ok(_f_all.filter(_rA) is True, 'empty filter accepts all')
136
+ ok(_f_all.filter(_rD) is True, 'empty filter accepts all 2')
137
+
138
+ ok(_f_app.filter(_rA) is True, 'parent name matches')
139
+ ok(_f_app.filter(_rB) is True, 'child name matches')
140
+ ok(_f_app.filter(_rC) is True, 'deep child matches')
141
+ ok(_f_app.filter(_rD) is False, 'unrelated rejected')
142
+
143
+ ok(_f_sub.filter(_rB) is True, 'sub self-match')
144
+ ok(_f_sub.filter(_rC) is True, 'sub child match')
145
+ ok(_f_sub.filter(_rA) is False, 'parent of sub rejected')
146
+
147
+
148
+ # ── 9. StreamHandler with custom stream ──────────────────────────────────────
149
+
150
+ _buf9 = _Buf()
151
+ _sh9 = StreamHandler(_buf9)
152
+ _sh9.setFormatter(Formatter('%(levelname)s:%(name)s:%(message)s'))
153
+ _sh9.setLevel(DEBUG)
154
+
155
+ _l9 = Logger('test9')
156
+ _l9.addHandler(_sh9)
157
+ _l9.setLevel(DEBUG)
158
+ _l9.propagate = False
159
+
160
+ _l9.debug('dbg')
161
+ _l9.info('inf')
162
+ _l9.warning('wrn')
163
+ _l9.error('err')
164
+ _l9.critical('crit')
165
+
166
+ ae(_buf9.lines.length, 5)
167
+ ae(_buf9.lines[0], 'DEBUG:test9:dbg\n')
168
+ ae(_buf9.lines[1], 'INFO:test9:inf\n')
169
+ ae(_buf9.lines[2], 'WARNING:test9:wrn\n')
170
+ ae(_buf9.lines[3], 'ERROR:test9:err\n')
171
+ ae(_buf9.lines[4], 'CRITICAL:test9:crit\n')
172
+
173
+
174
+ # ── 10. NullHandler ───────────────────────────────────────────────────────────
175
+
176
+ _nh = NullHandler()
177
+ _rn = LogRecord('x', WARNING, '', 0, 'msg', [], None)
178
+ ok(_nh.handle(_rn) is None or _nh.handle(_rn) is False or True, 'NullHandler.handle does not throw')
179
+
180
+
181
+ # ── 11. Logger.isEnabledFor / getEffectiveLevel ───────────────────────────────
182
+
183
+ _la = Logger('lvltest')
184
+ _la.setLevel(WARNING)
185
+ _la.propagate = False
186
+
187
+ ok(_la.isEnabledFor(DEBUG) is False, 'DEBUG below WARNING')
188
+ ok(_la.isEnabledFor(INFO) is False, 'INFO below WARNING')
189
+ ok(_la.isEnabledFor(WARNING) is True, 'WARNING == WARNING')
190
+ ok(_la.isEnabledFor(ERROR) is True, 'ERROR above WARNING')
191
+ ok(_la.isEnabledFor(CRITICAL) is True, 'CRITICAL above WARNING')
192
+
193
+ ae(_la.getEffectiveLevel(), WARNING)
194
+
195
+ _la.setLevel(NOTSET)
196
+ _la.parent = None
197
+ ae(_la.getEffectiveLevel(), WARNING) # no parent → falls back to WARNING
198
+
199
+
200
+ # ── 12. Logger level filtering (messages suppressed below level) ──────────────
201
+
202
+ _buf12 = _Buf()
203
+ _sh12 = StreamHandler(_buf12)
204
+ _sh12.setFormatter(Formatter('%(levelname)s'))
205
+ _sh12.setLevel(NOTSET)
206
+
207
+ _l12 = Logger('filt12')
208
+ _l12.addHandler(_sh12)
209
+ _l12.setLevel(WARNING)
210
+ _l12.propagate = False
211
+
212
+ _l12.debug('no')
213
+ _l12.info('no')
214
+ _l12.warning('yes')
215
+ _l12.error('yes')
216
+
217
+ ae(_buf12.lines.length, 2)
218
+ ae(_buf12.lines[0], 'WARNING\n')
219
+ ae(_buf12.lines[1], 'ERROR\n')
220
+
221
+
222
+ # ── 13. Logger.log() with numeric level ──────────────────────────────────────
223
+
224
+ _buf13 = _Buf()
225
+ _sh13 = StreamHandler(_buf13)
226
+ _sh13.setFormatter(Formatter('%(levelno)d:%(message)s'))
227
+ _l13 = Logger('log13')
228
+ _l13.addHandler(_sh13)
229
+ _l13.setLevel(DEBUG)
230
+ _l13.propagate = False
231
+ _l13.log(ERROR, 'test via log()')
232
+ ae(_buf13.lines[0], '40:test via log()\n')
233
+
234
+
235
+ # ── 14. %-style args in Logger methods ────────────────────────────────────────
236
+
237
+ _buf14 = _Buf()
238
+ _sh14 = StreamHandler(_buf14)
239
+ _sh14.setFormatter(Formatter('%(message)s'))
240
+ _l14 = Logger('args14')
241
+ _l14.addHandler(_sh14)
242
+ _l14.setLevel(DEBUG)
243
+ _l14.propagate = False
244
+ _l14.info('x=%d y=%s', 7, 'foo')
245
+ ae(_buf14.lines[0], 'x=7 y=foo\n')
246
+
247
+
248
+ # ── 15. Logger.addFilter / Filterer ──────────────────────────────────────────
249
+
250
+ _buf15 = _Buf()
251
+ _sh15 = StreamHandler(_buf15)
252
+ _sh15.setFormatter(Formatter('%(message)s'))
253
+ _l15 = Logger('parent15')
254
+ _l15.addHandler(_sh15)
255
+ _l15.setLevel(DEBUG)
256
+ _l15.propagate = False
257
+ _l15.addFilter(Filter('parent15.child')) # only pass records from parent15.child*
258
+
259
+ _ra15 = LogRecord('parent15', DEBUG, '', 0, 'parent', [], None)
260
+ _rb15 = LogRecord('parent15.child', DEBUG, '', 0, 'child', [], None)
261
+ _l15.handle(_ra15)
262
+ _l15.handle(_rb15)
263
+ ae(_buf15.lines.length, 1)
264
+ ae(_buf15.lines[0], 'child\n')
265
+
266
+
267
+ # ── 16. Handler.addFilter ─────────────────────────────────────────────────────
268
+
269
+ _buf16 = _Buf()
270
+ _sh16 = StreamHandler(_buf16)
271
+ _sh16.setFormatter(Formatter('%(message)s'))
272
+ _sh16.addFilter(Filter('ok'))
273
+
274
+ _l16 = Logger('hdlr16')
275
+ _l16.addHandler(_sh16)
276
+ _l16.setLevel(DEBUG)
277
+ _l16.propagate = False
278
+
279
+ _l16.handle(LogRecord('ok', DEBUG, '', 0, 'pass', [], None))
280
+ _l16.handle(LogRecord('bad', DEBUG, '', 0, 'block', [], None))
281
+ ae(_buf16.lines.length, 1)
282
+ ae(_buf16.lines[0], 'pass\n')
283
+
284
+
285
+ # ── 17. getLogger — same name returns same instance ──────────────────────────
286
+
287
+ _ga = getLogger('getlogger_test')
288
+ _gb = getLogger('getlogger_test')
289
+ ok(_ga is _gb, 'getLogger returns same instance for same name')
290
+ ok(getLogger() is root, 'getLogger() returns root')
291
+ ok(getLogger('root') is root, 'getLogger("root") returns root')
292
+
293
+
294
+ # ── 18. Logger hierarchy — propagation ────────────────────────────────────────
295
+
296
+ _buf18 = _Buf()
297
+ _sh18 = StreamHandler(_buf18)
298
+ _sh18.setFormatter(Formatter('%(name)s:%(message)s'))
299
+
300
+ _parent18 = Logger('app18')
301
+ _parent18.addHandler(_sh18)
302
+ _parent18.setLevel(DEBUG)
303
+ _parent18.propagate = False
304
+
305
+ _child18 = Logger('app18.mod')
306
+ _child18.parent = _parent18
307
+ _child18.setLevel(DEBUG)
308
+ _child18.propagate = True
309
+
310
+ _child18.info('from child')
311
+ ae(_buf18.lines.length, 1)
312
+ ae(_buf18.lines[0], 'app18.mod:from child\n')
313
+
314
+
315
+ # ── 19. disable() ─────────────────────────────────────────────────────────────
316
+
317
+ _buf19 = _Buf()
318
+ _sh19 = StreamHandler(_buf19)
319
+ _sh19.setFormatter(Formatter('%(message)s'))
320
+ _l19 = Logger('dis19')
321
+ _l19.addHandler(_sh19)
322
+ _l19.setLevel(DEBUG)
323
+ _l19.propagate = False
324
+
325
+ _l19.warning('before disable')
326
+ logging.disable(CRITICAL)
327
+ _l19.warning('after disable – suppressed')
328
+ _l19.critical('also suppressed')
329
+ ae(_buf19.lines.length, 1)
330
+
331
+ # reset disable level so later tests aren't affected
332
+ logging.disable(NOTSET)
333
+
334
+
335
+ # ── 20. hasHandlers ───────────────────────────────────────────────────────────
336
+
337
+ _l20 = Logger('hashdlr20')
338
+ _l20.parent = None
339
+ _l20.propagate = False
340
+ ok(_l20.hasHandlers() is False, 'no handlers')
341
+ _l20.addHandler(NullHandler())
342
+ ok(_l20.hasHandlers() is True, 'has handler')
343
+
344
+
345
+ # ── 21. exception() logs at ERROR ─────────────────────────────────────────────
346
+
347
+ _buf21 = _Buf()
348
+ _sh21 = StreamHandler(_buf21)
349
+ _sh21.setFormatter(Formatter('%(levelname)s:%(message)s'))
350
+ _l21 = Logger('exc21')
351
+ _l21.addHandler(_sh21)
352
+ _l21.setLevel(DEBUG)
353
+ _l21.propagate = False
354
+ _l21.exception('something went wrong')
355
+ ae(_buf21.lines.length, 1)
356
+ ae(_buf21.lines[0], 'ERROR:something went wrong\n')
package/test/long.pyj ADDED
@@ -0,0 +1,130 @@
1
+ # vim:fileencoding=utf-8
2
+ # globals: assrt
3
+ from __python__ import overload_operators
4
+
5
+ ae = assrt.equal
6
+ ade = assrt.deepEqual
7
+ ok = assrt.ok
8
+ throws = assrt.throws
9
+
10
+ # ── construction ──────────────────────────────────────────────────────────────
11
+
12
+ # from int
13
+ ok(jstype(long(0)) is 'bigint')
14
+ ok(jstype(long(42)) is 'bigint')
15
+ ok(jstype(long(-99)) is 'bigint')
16
+
17
+ # from string (base 10)
18
+ ok(jstype(long('12345678901234567890')) is 'bigint')
19
+ ae(str(long('42')), '42')
20
+ ae(str(long('-7')), '-7')
21
+
22
+ # from string with explicit base 10
23
+ ae(str(long('255', 10)), '255')
24
+
25
+ # from string base 16
26
+ ae(str(long('ff', 16)), '255')
27
+ ae(str(long('FF', 16)), '255')
28
+ ae(str(long('0xff', 16)), '255')
29
+ ae(str(long('0xFF', 16)), '255')
30
+
31
+ # from string base 2
32
+ ae(str(long('1010', 2)), '10')
33
+ ae(str(long('0b1010', 2)), '10')
34
+
35
+ # from string base 8
36
+ ae(str(long('17', 8)), '15')
37
+ ae(str(long('0o17', 8)), '15')
38
+
39
+ # from bool
40
+ ae(str(long(True)), '1')
41
+ ae(str(long(False)), '0')
42
+
43
+ # identity: long of long
44
+ x = long(7)
45
+ ae(str(long(x)), '7')
46
+
47
+ # very large integer (beyond JS Number precision)
48
+ big = long('99999999999999999999999999999999')
49
+ ae(str(big), '99999999999999999999999999999999')
50
+
51
+ # ── error cases ───────────────────────────────────────────────────────────────
52
+
53
+ throws(def(): long('abc');, ValueError)
54
+ throws(def(): long('xyz', 16);, ValueError)
55
+ throws(def(): long(3.14);, TypeError)
56
+ throws(def(): long(None);, TypeError)
57
+
58
+ # ── arithmetic ────────────────────────────────────────────────────────────────
59
+
60
+ a = long(10)
61
+ b = long(3)
62
+
63
+ ae(str(a + b), '13')
64
+ ae(str(a - b), '7')
65
+ ae(str(a * b), '30')
66
+
67
+ # floor division — Python semantics (floor toward -inf)
68
+ ae(str(a // b), '3')
69
+ ae(str(long(-7) // long(2)), '-4') # Python: -4, JS truncate: -3
70
+ ae(str(long(7) // long(-2)), '-4') # Python: -4, JS truncate: -3
71
+ ae(str(long(-7) // long(-2)), '3') # both negative
72
+
73
+ # modulo — Python semantics (result has same sign as divisor)
74
+ ae(str(long(7) % long(3)), '1')
75
+ ae(str(long(-7) % long(3)), '2') # Python: 2, JS BigInt: -1
76
+ ae(str(long(7) % long(-3)), '-2') # Python: -2, JS BigInt: 1
77
+ ae(str(long(-7) % long(-3)), '-1') # both negative
78
+
79
+ # power
80
+ ae(str(long(2) ** long(10)), '1024')
81
+ ae(str(long(3) ** long(0)), '1')
82
+
83
+ # negative exponent raises ValueError
84
+ throws(def(): long(2) ** long(-1);, ValueError)
85
+
86
+ # truediv raises TypeError (use // instead)
87
+ throws(def(): long(10) / long(3);, TypeError)
88
+
89
+ # ── bitwise ───────────────────────────────────────────────────────────────────
90
+
91
+ ae(str(long(0b1010) & long(0b1100)), '8') # 0b1000 = 8
92
+ ae(str(long(0b1010) | long(0b1100)), '14') # 0b1110 = 14
93
+ ae(str(long(0b1010) ^ long(0b1100)), '6') # 0b0110 = 6
94
+ ae(str(long(1) << long(4)), '16')
95
+ ae(str(long(16) >> long(2)), '4')
96
+
97
+ # mixed long + int raises TypeError
98
+ throws(def(): long(1) + 1;, TypeError)
99
+ throws(def(): long(1) & 1;, TypeError)
100
+
101
+ # ── comparisons ───────────────────────────────────────────────────────────────
102
+
103
+ ok(long(1) < long(2))
104
+ ok(long(2) > long(1))
105
+ ok(long(3) <= long(3))
106
+ ok(long(3) >= long(3))
107
+ ok(long(1) == long(1))
108
+ ok(long(1) != long(2))
109
+
110
+ # ── isinstance / type ─────────────────────────────────────────────────────────
111
+
112
+ ok(isinstance(long(5), long))
113
+ ok(isinstance(long(0), long))
114
+ ok(isinstance(long(-1), long))
115
+ ok(not isinstance(5, long))
116
+ ok(not isinstance('5', long))
117
+
118
+ # ── str() conversion ──────────────────────────────────────────────────────────
119
+
120
+ ae(str(long(0)), '0')
121
+ ae(str(long(12345)), '12345')
122
+ ae(str(long(-42)), '-42')
123
+ ae(str(long('99999999999999999999')), '99999999999999999999')
124
+
125
+ # ── identity with large numbers ───────────────────────────────────────────────
126
+
127
+ # Verify precision is maintained (JS Number loses this)
128
+ n = long('9007199254740993') # 2^53 + 1, not representable as JS Number
129
+ ae(str(n), '9007199254740993')
130
+ ae(str(n + long(1)), '9007199254740994')
@@ -0,0 +1,141 @@
1
+ # globals: assrt
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # parenthesized_with.pyj
5
+ # Tests for Python 3.10+ parenthesized `with` statement.
6
+
7
+ ae = assrt.equal
8
+ ok = assrt.ok
9
+
10
+ # ── Helper context manager ────────────────────────────────────────────────────
11
+
12
+ class _CM:
13
+ def __init__(self, name, log):
14
+ self.name = name
15
+ self.log = log
16
+
17
+ def __enter__(self):
18
+ self.log.push('enter:' + self.name)
19
+ return self
20
+
21
+ def __exit__(self, *args):
22
+ self.log.push('exit:' + self.name)
23
+ return False
24
+
25
+ # ── 1. Single clause, alias inside parens ─────────────────────────────────────
26
+
27
+ _log1 = []
28
+ with (_CM('a', _log1) as cm):
29
+ _log1.push('body')
30
+ ae(_log1[0], 'enter:a')
31
+ ae(_log1[1], 'body')
32
+ ae(_log1[2], 'exit:a')
33
+
34
+ # ── 2. Single clause, no alias ────────────────────────────────────────────────
35
+
36
+ _log2 = []
37
+
38
+ class _SimpleCM:
39
+ def __init__(self, log):
40
+ self.log = log
41
+ def __enter__(self):
42
+ self.log.push('entered')
43
+ return self
44
+ def __exit__(self):
45
+ self.log.push('exited')
46
+
47
+ with (_SimpleCM(_log2)):
48
+ _log2.push('body')
49
+ ae(_log2[0], 'entered')
50
+ ae(_log2[1], 'body')
51
+ ae(_log2[2], 'exited')
52
+
53
+ # ── 3. Multi-clause, LIFO exit order ──────────────────────────────────────────
54
+
55
+ _log3 = []
56
+ with (_CM('a', _log3) as a, _CM('b', _log3) as b):
57
+ _log3.push('body')
58
+ ae(_log3[0], 'enter:a')
59
+ ae(_log3[1], 'enter:b')
60
+ ae(_log3[2], 'body')
61
+ ae(_log3[3], 'exit:b') # LIFO: b exits before a
62
+ ae(_log3[4], 'exit:a')
63
+
64
+ # ── 4. Trailing comma ─────────────────────────────────────────────────────────
65
+
66
+ _log4 = []
67
+ with (_CM('x', _log4) as x,):
68
+ _log4.push('body')
69
+ ae(_log4[0], 'enter:x')
70
+ ae(_log4[1], 'body')
71
+ ae(_log4[2], 'exit:x')
72
+
73
+ # ── 5. Multi-line form ────────────────────────────────────────────────────────
74
+
75
+ _log5 = []
76
+ with (
77
+ _CM('p', _log5) as p,
78
+ _CM('q', _log5) as q,
79
+ ):
80
+ _log5.push('body')
81
+ ae(_log5[0], 'enter:p')
82
+ ae(_log5[1], 'enter:q')
83
+ ae(_log5[2], 'body')
84
+ ae(_log5[3], 'exit:q')
85
+ ae(_log5[4], 'exit:p')
86
+
87
+ # ── 6. __enter__ return value assigned to alias ───────────────────────────────
88
+
89
+ class _ValCM:
90
+ def __init__(self, val):
91
+ self.val = val
92
+ def __enter__(self):
93
+ return self.val
94
+ def __exit__(self):
95
+ pass
96
+
97
+ with (_ValCM(99) as v):
98
+ ae(v, 99)
99
+
100
+ # ── 7. Exception suppression via __exit__ ─────────────────────────────────────
101
+
102
+ class _SuppressCM:
103
+ def __enter__(self):
104
+ return self
105
+ def __exit__(self, *args):
106
+ return True # suppress any exception
107
+
108
+ _raised = False
109
+ with (_SuppressCM()):
110
+ raise Error('suppressed')
111
+ _raised = True
112
+ ok(_raised)
113
+
114
+ # ── 8. Exception propagation (unsuppressed) ──────────────────────────────────
115
+
116
+ _caught = False
117
+ try:
118
+ with (_CM('err', []) as _ignored):
119
+ raise Error('propagated')
120
+ except Exception as _e:
121
+ _caught = True
122
+ ok(_caught)
123
+
124
+ # ── 9. Non-parenthesized form still works (regression) ───────────────────────
125
+
126
+ _log9 = []
127
+ with _CM('r', _log9) as r, _CM('s', _log9) as s:
128
+ _log9.push('body')
129
+ ae(_log9[0], 'enter:r')
130
+ ae(_log9[3], 'exit:s')
131
+ ae(_log9[4], 'exit:r')
132
+
133
+ # ── 10. Parenthesized expression (not parenthesized-with) still works ─────────
134
+
135
+ _log10 = []
136
+ _cm10 = _CM('t', _log10)
137
+ with (_cm10) as t:
138
+ _log10.push('body')
139
+ ae(_log10[0], 'enter:t')
140
+ ae(_log10[1], 'body')
141
+ ae(_log10[2], 'exit:t')