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/logging.pyj
ADDED
|
@@ -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')
|