rapydscript-ns 0.9.3 → 0.9.5
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 +18 -0
- package/HACKING.md +103 -103
- package/LICENSE +24 -24
- package/PYTHON_GAPS.md +52 -142
- package/README.md +51 -21
- package/TODO.md +1 -26
- package/add-toc-to-readme +2 -2
- package/bin/export +75 -75
- package/bin/rapydscript +0 -0
- package/bin/web-repl-export +102 -102
- package/build +2 -2
- package/language-service/index.js +88 -36
- package/package.json +1 -1
- package/publish.py +37 -37
- package/release/baselib-plain-pretty.js +157 -31
- package/release/baselib-plain-ugly.js +5 -5
- package/release/compiler.js +724 -426
- package/release/signatures.json +29 -29
- package/session.vim +4 -4
- package/setup.cfg +2 -2
- package/src/ast.pyj +7 -0
- package/src/baselib-containers.pyj +41 -4
- package/src/baselib-errors.pyj +4 -3
- package/src/baselib-internal.pyj +47 -18
- package/src/baselib-str.pyj +16 -3
- package/src/compiler.pyj +36 -36
- package/src/errors.pyj +30 -30
- package/src/lib/aes.pyj +646 -646
- package/src/lib/collections.pyj +227 -3
- package/src/lib/copy.pyj +120 -120
- package/src/lib/elementmaker.pyj +83 -83
- package/src/lib/encodings.pyj +126 -126
- package/src/lib/gettext.pyj +569 -569
- package/src/lib/itertools.pyj +580 -580
- package/src/lib/math.pyj +193 -193
- package/src/lib/operator.pyj +11 -11
- package/src/lib/pprint.pyj +455 -0
- package/src/lib/random.pyj +118 -118
- package/src/lib/react.pyj +74 -74
- package/src/lib/statistics.pyj +0 -0
- package/src/lib/traceback.pyj +63 -63
- package/src/lib/uuid.pyj +77 -77
- package/src/monaco-language-service/completions.js +21 -14
- package/src/monaco-language-service/diagnostics.js +2 -2
- package/src/monaco-language-service/dts.js +58 -15
- package/src/monaco-language-service/package.json +3 -0
- package/src/output/classes.pyj +25 -2
- package/src/output/codegen.pyj +4 -1
- package/src/output/comments.pyj +45 -45
- package/src/output/exceptions.pyj +201 -201
- package/src/output/jsx.pyj +164 -164
- package/src/output/treeshake.pyj +182 -182
- package/src/output/utils.pyj +72 -72
- package/src/parse.pyj +42 -7
- package/src/string_interpolation.pyj +72 -72
- package/src/tokenizer.pyj +18 -2
- 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/baselib.pyj +23 -0
- package/test/chainmap.pyj +185 -0
- package/test/dataclasses.pyj +3 -4
- package/test/decorators.pyj +77 -77
- package/test/docstrings.pyj +39 -39
- package/test/elementmaker_test.pyj +45 -45
- package/test/enum.pyj +1 -1
- package/test/functions.pyj +151 -151
- package/test/generators.pyj +41 -41
- package/test/generic.pyj +370 -370
- package/test/internationalization.pyj +73 -73
- package/test/lint.pyj +164 -164
- package/test/loops.pyj +85 -85
- package/test/numpy.pyj +734 -734
- package/test/pprint.pyj +232 -0
- package/test/python_features.pyj +1 -1
- package/test/repl.pyj +121 -121
- package/test/scoped_flags.pyj +76 -76
- package/test/statistics.pyj +224 -0
- package/test/str.pyj +4 -4
- package/test/unit/index.js +455 -0
- package/test/unit/language-service-completions.js +2 -0
- package/test/unit/language-service-dts.js +113 -0
- package/test/unit/language-service-hover.js +455 -455
- package/test/unit/language-service.js +135 -2
- package/test/unit/web-repl.js +349 -1
- package/tools/compiler.d.ts +367 -367
- package/tools/completer.js +131 -131
- package/tools/export.js +4 -2
- 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 +141 -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/prism.css +139 -139
- package/web-repl/prism.js +113 -113
- package/web-repl/rapydscript.js +228 -226
- package/web-repl/sha1.js +25 -25
package/test/unit/index.js
CHANGED
|
@@ -2996,6 +2996,96 @@ assrt.equal(fib(15), 610)
|
|
|
2996
2996
|
js_checks: ["ρσ_op_add(", "ρσ_op_sub(", "ρσ_op_or(", "ρσ_op_and("],
|
|
2997
2997
|
},
|
|
2998
2998
|
|
|
2999
|
+
{
|
|
3000
|
+
name: "operator_dict_or",
|
|
3001
|
+
description: "| on plain objects creates a new merged dict; numeric | still works",
|
|
3002
|
+
src: [
|
|
3003
|
+
"# globals: assrt",
|
|
3004
|
+
"from __python__ import overload_operators",
|
|
3005
|
+
"a = {'x': 1, 'y': 2}",
|
|
3006
|
+
"b = {'z': 3}",
|
|
3007
|
+
"c = a | b",
|
|
3008
|
+
"assrt.deepEqual(c, {'x': 1, 'y': 2, 'z': 3})",
|
|
3009
|
+
"assrt.notStrictEqual(c, a)",
|
|
3010
|
+
"assrt.equal(5 | 3, 7)",
|
|
3011
|
+
].join("\n"),
|
|
3012
|
+
},
|
|
3013
|
+
|
|
3014
|
+
{
|
|
3015
|
+
name: "operator_dict_ior",
|
|
3016
|
+
description: "|= on plain objects merges in-place",
|
|
3017
|
+
src: [
|
|
3018
|
+
"# globals: assrt",
|
|
3019
|
+
"from __python__ import overload_operators",
|
|
3020
|
+
"d = {'a': 1}",
|
|
3021
|
+
"ref = d",
|
|
3022
|
+
"d |= {'b': 2}",
|
|
3023
|
+
"assrt.deepEqual(d, {'a': 1, 'b': 2})",
|
|
3024
|
+
"assrt.strictEqual(d, ref)",
|
|
3025
|
+
].join("\n"),
|
|
3026
|
+
},
|
|
3027
|
+
|
|
3028
|
+
{
|
|
3029
|
+
name: "operator_dict_or_override",
|
|
3030
|
+
description: "| on plain objects: right-hand values override left on key collision",
|
|
3031
|
+
src: [
|
|
3032
|
+
"# globals: assrt",
|
|
3033
|
+
"from __python__ import overload_operators",
|
|
3034
|
+
"a = {'x': 1, 'y': 2}",
|
|
3035
|
+
"b = {'y': 99, 'z': 3}",
|
|
3036
|
+
"c = a | b",
|
|
3037
|
+
"assrt.equal(c['y'], 99)",
|
|
3038
|
+
"assrt.equal(c['x'], 1)",
|
|
3039
|
+
"assrt.equal(c['z'], 3)",
|
|
3040
|
+
].join("\n"),
|
|
3041
|
+
},
|
|
3042
|
+
|
|
3043
|
+
{
|
|
3044
|
+
name: "operator_type_error_bitwise",
|
|
3045
|
+
description: "bitwise operators raise TypeError for invalid types",
|
|
3046
|
+
src: [
|
|
3047
|
+
"# globals: assrt",
|
|
3048
|
+
"from __python__ import overload_operators",
|
|
3049
|
+
"def check(fn, msg):",
|
|
3050
|
+
" try:",
|
|
3051
|
+
" fn()",
|
|
3052
|
+
" assrt.ok(False, 'expected TypeError for ' + msg)",
|
|
3053
|
+
" except TypeError:",
|
|
3054
|
+
" assrt.ok(True)",
|
|
3055
|
+
'check(def(): "str" & 5;, "str & int")',
|
|
3056
|
+
'check(def(): None | 5;, "None | int")',
|
|
3057
|
+
'check(def(): "a" ^ 1;, "str ^ int")',
|
|
3058
|
+
'check(def(): "a" << 1;, "str << int")',
|
|
3059
|
+
'check(def(): "a" >> 1;, "str >> int")',
|
|
3060
|
+
"assrt.equal(7 & 3, 3)",
|
|
3061
|
+
"assrt.equal(1 | 2, 3)",
|
|
3062
|
+
"assrt.equal(5 ^ 3, 6)",
|
|
3063
|
+
"assrt.equal(1 << 3, 8)",
|
|
3064
|
+
"assrt.equal(8 >> 2, 2)",
|
|
3065
|
+
].join("\n"),
|
|
3066
|
+
},
|
|
3067
|
+
|
|
3068
|
+
{
|
|
3069
|
+
name: "operator_type_error_unary",
|
|
3070
|
+
description: "unary operators raise TypeError for invalid types",
|
|
3071
|
+
src: [
|
|
3072
|
+
"# globals: assrt",
|
|
3073
|
+
"from __python__ import overload_operators",
|
|
3074
|
+
"def check(fn, msg):",
|
|
3075
|
+
" try:",
|
|
3076
|
+
" fn()",
|
|
3077
|
+
" assrt.ok(False, 'expected TypeError for ' + msg)",
|
|
3078
|
+
" except TypeError:",
|
|
3079
|
+
" assrt.ok(True)",
|
|
3080
|
+
'check(def(): -"hello";, "neg str")',
|
|
3081
|
+
'check(def(): +None;, "pos None")',
|
|
3082
|
+
'check(def(): ~"world";, "invert str")',
|
|
3083
|
+
"assrt.equal(-5, -5)",
|
|
3084
|
+
"assrt.equal(+3, 3)",
|
|
3085
|
+
"assrt.equal(~0, -1)",
|
|
3086
|
+
].join("\n"),
|
|
3087
|
+
},
|
|
3088
|
+
|
|
2999
3089
|
// ── nested comprehensions ──────────────────────────────────────────────
|
|
3000
3090
|
|
|
3001
3091
|
{
|
|
@@ -5275,6 +5365,86 @@ assrt.equal(fib(15), 610)
|
|
|
5275
5365
|
js_checks: [/let\s[^;]*ρσ_with_exception/, /let\s[^;]*ρσ_with_suppress/],
|
|
5276
5366
|
},
|
|
5277
5367
|
|
|
5368
|
+
// ── BigInt literals ────────────────────────────────────────────────────
|
|
5369
|
+
|
|
5370
|
+
{
|
|
5371
|
+
name: "bigint_literal_basic",
|
|
5372
|
+
description: "42n compiles to JS BigInt literal and has bigint type",
|
|
5373
|
+
src: [
|
|
5374
|
+
"# globals: assrt",
|
|
5375
|
+
"x = 42n",
|
|
5376
|
+
"assrt.ok(jstype(x) == 'bigint', 'type is bigint')",
|
|
5377
|
+
"assrt.ok(x == 42n, 'value is 42n')",
|
|
5378
|
+
].join("\n"),
|
|
5379
|
+
js_checks: ["42n"],
|
|
5380
|
+
},
|
|
5381
|
+
|
|
5382
|
+
{
|
|
5383
|
+
name: "bigint_literal_hex",
|
|
5384
|
+
description: "0xFFn compiles to JS hex BigInt literal",
|
|
5385
|
+
src: [
|
|
5386
|
+
"# globals: assrt",
|
|
5387
|
+
"x = 0xFFn",
|
|
5388
|
+
"assrt.ok(x == 255n, 'hex bigint value')",
|
|
5389
|
+
].join("\n"),
|
|
5390
|
+
js_checks: ["0xFFn"],
|
|
5391
|
+
},
|
|
5392
|
+
|
|
5393
|
+
{
|
|
5394
|
+
name: "bigint_literal_binary",
|
|
5395
|
+
description: "0b1010n compiles to JS binary BigInt literal",
|
|
5396
|
+
src: [
|
|
5397
|
+
"# globals: assrt",
|
|
5398
|
+
"x = 0b1010n",
|
|
5399
|
+
"assrt.ok(x == 10n, 'binary bigint value')",
|
|
5400
|
+
].join("\n"),
|
|
5401
|
+
js_checks: ["0b1010n"],
|
|
5402
|
+
},
|
|
5403
|
+
|
|
5404
|
+
{
|
|
5405
|
+
name: "bigint_literal_octal",
|
|
5406
|
+
description: "0o77n compiles to JS octal BigInt literal",
|
|
5407
|
+
src: [
|
|
5408
|
+
"# globals: assrt",
|
|
5409
|
+
"x = 0o77n",
|
|
5410
|
+
"assrt.ok(x == 63n, 'octal bigint value')",
|
|
5411
|
+
].join("\n"),
|
|
5412
|
+
js_checks: ["0o77n"],
|
|
5413
|
+
},
|
|
5414
|
+
|
|
5415
|
+
{
|
|
5416
|
+
name: "bigint_literal_zero",
|
|
5417
|
+
description: "0n compiles and works",
|
|
5418
|
+
src: [
|
|
5419
|
+
"# globals: assrt",
|
|
5420
|
+
"x = 0n",
|
|
5421
|
+
"assrt.ok(jstype(x) == 'bigint', 'type is bigint')",
|
|
5422
|
+
"assrt.ok(x == 0n, 'value is 0n')",
|
|
5423
|
+
].join("\n"),
|
|
5424
|
+
js_checks: ["0n"],
|
|
5425
|
+
},
|
|
5426
|
+
|
|
5427
|
+
{
|
|
5428
|
+
name: "bigint_literal_arithmetic",
|
|
5429
|
+
description: "BigInt arithmetic works correctly",
|
|
5430
|
+
src: [
|
|
5431
|
+
"# globals: assrt",
|
|
5432
|
+
"x = 10n + 3n",
|
|
5433
|
+
"assrt.ok(x == 13n, 'addition')",
|
|
5434
|
+
].join("\n"),
|
|
5435
|
+
},
|
|
5436
|
+
|
|
5437
|
+
{
|
|
5438
|
+
name: "bigint_literal_large",
|
|
5439
|
+
description: "Large BigInt literal preserves precision",
|
|
5440
|
+
src: [
|
|
5441
|
+
"# globals: assrt",
|
|
5442
|
+
"x = 999999999999999999999n",
|
|
5443
|
+
"assrt.ok(x == 999999999999999999999n, 'large bigint')",
|
|
5444
|
+
].join("\n"),
|
|
5445
|
+
js_checks: ["999999999999999999999n"],
|
|
5446
|
+
},
|
|
5447
|
+
|
|
5278
5448
|
{
|
|
5279
5449
|
name: "with_statement_suppresses_exception",
|
|
5280
5450
|
description: "with statement __exit__ returning True suppresses the exception",
|
|
@@ -5293,6 +5463,291 @@ assrt.equal(fib(15), 610)
|
|
|
5293
5463
|
].join("\n"),
|
|
5294
5464
|
},
|
|
5295
5465
|
|
|
5466
|
+
// ── Exception.args ───────────────────────────────────────────────────────
|
|
5467
|
+
{
|
|
5468
|
+
name: "exception_args_single",
|
|
5469
|
+
description: "Exception with single arg populates .args and .message",
|
|
5470
|
+
src: [
|
|
5471
|
+
"# globals: assrt",
|
|
5472
|
+
"e = Exception('hello')",
|
|
5473
|
+
"assrt.deepEqual(e.args, ['hello'])",
|
|
5474
|
+
"assrt.equal(e.message, 'hello')",
|
|
5475
|
+
].join("\n"),
|
|
5476
|
+
},
|
|
5477
|
+
{
|
|
5478
|
+
name: "exception_args_multiple",
|
|
5479
|
+
description: "Exception with multiple args populates .args tuple",
|
|
5480
|
+
src: [
|
|
5481
|
+
"# globals: assrt",
|
|
5482
|
+
"e = Exception('err', 42, 'extra')",
|
|
5483
|
+
"assrt.deepEqual(e.args, ['err', 42, 'extra'])",
|
|
5484
|
+
"assrt.equal(e.message, 'err')",
|
|
5485
|
+
"assrt.equal(e.args[1], 42)",
|
|
5486
|
+
"assrt.equal(e.args[2], 'extra')",
|
|
5487
|
+
].join("\n"),
|
|
5488
|
+
},
|
|
5489
|
+
{
|
|
5490
|
+
name: "exception_args_empty",
|
|
5491
|
+
description: "Exception with no args has empty .args and empty .message",
|
|
5492
|
+
src: [
|
|
5493
|
+
"# globals: assrt",
|
|
5494
|
+
"e = Exception()",
|
|
5495
|
+
"assrt.deepEqual(e.args, [])",
|
|
5496
|
+
"assrt.equal(e.message, '')",
|
|
5497
|
+
].join("\n"),
|
|
5498
|
+
},
|
|
5499
|
+
{
|
|
5500
|
+
name: "exception_args_subclass",
|
|
5501
|
+
description: "Exception subclass inherits .args behavior",
|
|
5502
|
+
src: [
|
|
5503
|
+
"# globals: assrt",
|
|
5504
|
+
"e = ValueError('bad', 'value')",
|
|
5505
|
+
"assrt.deepEqual(e.args, ['bad', 'value'])",
|
|
5506
|
+
"assrt.equal(e.message, 'bad')",
|
|
5507
|
+
"assrt.ok(isinstance(e, ValueError))",
|
|
5508
|
+
"assrt.ok(isinstance(e, Exception))",
|
|
5509
|
+
].join("\n"),
|
|
5510
|
+
},
|
|
5511
|
+
{
|
|
5512
|
+
name: "exception_args_catch",
|
|
5513
|
+
description: "Caught exception preserves .args",
|
|
5514
|
+
src: [
|
|
5515
|
+
"# globals: assrt",
|
|
5516
|
+
"try:",
|
|
5517
|
+
" raise ValueError('oops', 123)",
|
|
5518
|
+
"except ValueError as e:",
|
|
5519
|
+
" assrt.deepEqual(e.args, ['oops', 123])",
|
|
5520
|
+
" assrt.equal(e.message, 'oops')",
|
|
5521
|
+
" assrt.equal(e.args[1], 123)",
|
|
5522
|
+
].join("\n"),
|
|
5523
|
+
},
|
|
5524
|
+
{
|
|
5525
|
+
name: "exception_args_len",
|
|
5526
|
+
description: "len() works on exception .args",
|
|
5527
|
+
src: [
|
|
5528
|
+
"# globals: assrt",
|
|
5529
|
+
"e = Exception('a', 'b', 'c')",
|
|
5530
|
+
"assrt.equal(len(e.args), 3)",
|
|
5531
|
+
"e2 = Exception()",
|
|
5532
|
+
"assrt.equal(len(e2.args), 0)",
|
|
5533
|
+
].join("\n"),
|
|
5534
|
+
},
|
|
5535
|
+
{
|
|
5536
|
+
name: "exception_args_exception_group",
|
|
5537
|
+
description: "ExceptionGroup .args contains message and exceptions list",
|
|
5538
|
+
src: [
|
|
5539
|
+
"# globals: assrt",
|
|
5540
|
+
"eg = ExceptionGroup('grp', [ValueError('v')])",
|
|
5541
|
+
"assrt.equal(eg.args[0], 'grp')",
|
|
5542
|
+
"assrt.equal(len(eg.args), 2)",
|
|
5543
|
+
"assrt.equal(eg.message, 'grp')",
|
|
5544
|
+
"assrt.ok(isinstance(eg.args[1][0], ValueError))",
|
|
5545
|
+
].join("\n"),
|
|
5546
|
+
},
|
|
5547
|
+
{
|
|
5548
|
+
name: "exception_args_custom_class",
|
|
5549
|
+
description: "Custom exception class with __init__ can use .args",
|
|
5550
|
+
src: [
|
|
5551
|
+
"# globals: assrt",
|
|
5552
|
+
"class MyError(Exception):",
|
|
5553
|
+
" def __init__(self, code, detail):",
|
|
5554
|
+
" Exception.__init__(self, code, detail)",
|
|
5555
|
+
" self.code = code",
|
|
5556
|
+
" self.detail = detail",
|
|
5557
|
+
"e = MyError(404, 'not found')",
|
|
5558
|
+
"assrt.deepEqual(e.args, [404, 'not found'])",
|
|
5559
|
+
"assrt.equal(e.code, 404)",
|
|
5560
|
+
"assrt.equal(e.detail, 'not found')",
|
|
5561
|
+
"assrt.equal(e.message, 404)",
|
|
5562
|
+
].join("\n"),
|
|
5563
|
+
},
|
|
5564
|
+
|
|
5565
|
+
// ── __slots__ ─────────────────────────────────────────────────────────────
|
|
5566
|
+
{
|
|
5567
|
+
name: "slots_basic",
|
|
5568
|
+
description: "__slots__ allows declared attributes",
|
|
5569
|
+
src: [
|
|
5570
|
+
"# globals: assrt",
|
|
5571
|
+
"class Point:",
|
|
5572
|
+
" __slots__ = ['x', 'y']",
|
|
5573
|
+
" def __init__(self, x, y):",
|
|
5574
|
+
" self.x = x",
|
|
5575
|
+
" self.y = y",
|
|
5576
|
+
"p = Point(1, 2)",
|
|
5577
|
+
"assrt.equal(p.x, 1)",
|
|
5578
|
+
"assrt.equal(p.y, 2)",
|
|
5579
|
+
"p.x = 10",
|
|
5580
|
+
"assrt.equal(p.x, 10)",
|
|
5581
|
+
].join("\n"),
|
|
5582
|
+
},
|
|
5583
|
+
{
|
|
5584
|
+
name: "slots_raises_attributeerror",
|
|
5585
|
+
description: "__slots__ raises AttributeError for undeclared attrs",
|
|
5586
|
+
src: [
|
|
5587
|
+
"# globals: assrt",
|
|
5588
|
+
"class Point:",
|
|
5589
|
+
" __slots__ = ['x', 'y']",
|
|
5590
|
+
" def __init__(self, x, y):",
|
|
5591
|
+
" self.x = x",
|
|
5592
|
+
" self.y = y",
|
|
5593
|
+
"p = Point(1, 2)",
|
|
5594
|
+
"try:",
|
|
5595
|
+
" p.z = 3",
|
|
5596
|
+
" assrt.ok(False, 'should have raised')",
|
|
5597
|
+
"except AttributeError as e:",
|
|
5598
|
+
" assrt.ok(str(e).indexOf('z') != -1)",
|
|
5599
|
+
].join("\n"),
|
|
5600
|
+
},
|
|
5601
|
+
{
|
|
5602
|
+
name: "slots_inherited",
|
|
5603
|
+
description: "Subclass with __slots__ merges parent slots",
|
|
5604
|
+
src: [
|
|
5605
|
+
"# globals: assrt",
|
|
5606
|
+
"class Base:",
|
|
5607
|
+
" __slots__ = ['x']",
|
|
5608
|
+
" def __init__(self):",
|
|
5609
|
+
" self.x = 1",
|
|
5610
|
+
"class Child(Base):",
|
|
5611
|
+
" __slots__ = ['y']",
|
|
5612
|
+
" def __init__(self):",
|
|
5613
|
+
" Base.__init__(self)",
|
|
5614
|
+
" self.y = 2",
|
|
5615
|
+
"c = Child()",
|
|
5616
|
+
"assrt.equal(c.x, 1)",
|
|
5617
|
+
"assrt.equal(c.y, 2)",
|
|
5618
|
+
"try:",
|
|
5619
|
+
" c.z = 3",
|
|
5620
|
+
" assrt.ok(False, 'should have raised')",
|
|
5621
|
+
"except AttributeError:",
|
|
5622
|
+
" assrt.ok(True)",
|
|
5623
|
+
].join("\n"),
|
|
5624
|
+
},
|
|
5625
|
+
{
|
|
5626
|
+
name: "slots_subclass_no_slots",
|
|
5627
|
+
description: "Subclass without __slots__ is unrestricted",
|
|
5628
|
+
src: [
|
|
5629
|
+
"# globals: assrt",
|
|
5630
|
+
"class Base:",
|
|
5631
|
+
" __slots__ = ['x']",
|
|
5632
|
+
" def __init__(self):",
|
|
5633
|
+
" self.x = 1",
|
|
5634
|
+
"class Child(Base):",
|
|
5635
|
+
" def __init__(self):",
|
|
5636
|
+
" Base.__init__(self)",
|
|
5637
|
+
" self.y = 2",
|
|
5638
|
+
"c = Child()",
|
|
5639
|
+
"assrt.equal(c.x, 1)",
|
|
5640
|
+
"assrt.equal(c.y, 2)",
|
|
5641
|
+
"c.z = 3",
|
|
5642
|
+
"assrt.equal(c.z, 3)",
|
|
5643
|
+
].join("\n"),
|
|
5644
|
+
},
|
|
5645
|
+
{
|
|
5646
|
+
name: "slots_empty",
|
|
5647
|
+
description: "__slots__ = [] allows no instance attributes",
|
|
5648
|
+
src: [
|
|
5649
|
+
"# globals: assrt",
|
|
5650
|
+
"class Empty:",
|
|
5651
|
+
" __slots__ = []",
|
|
5652
|
+
" pass",
|
|
5653
|
+
"e = Empty()",
|
|
5654
|
+
"try:",
|
|
5655
|
+
" e.x = 1",
|
|
5656
|
+
" assrt.ok(False, 'should have raised')",
|
|
5657
|
+
"except AttributeError:",
|
|
5658
|
+
" assrt.ok(True)",
|
|
5659
|
+
].join("\n"),
|
|
5660
|
+
},
|
|
5661
|
+
{
|
|
5662
|
+
name: "slots_with_attr_dunders",
|
|
5663
|
+
description: "__setattr__ takes priority over __slots__",
|
|
5664
|
+
src: [
|
|
5665
|
+
"# globals: assrt",
|
|
5666
|
+
"class Tracked:",
|
|
5667
|
+
" __slots__ = ['x']",
|
|
5668
|
+
" def __init__(self):",
|
|
5669
|
+
" object.__setattr__(self, 'log', [])",
|
|
5670
|
+
" self.x = 1",
|
|
5671
|
+
" def __setattr__(self, name, value):",
|
|
5672
|
+
" self.log.append(name)",
|
|
5673
|
+
" object.__setattr__(self, name, value)",
|
|
5674
|
+
"t = Tracked()",
|
|
5675
|
+
"assrt.equal(t.x, 1)",
|
|
5676
|
+
"assrt.ok(t.log.length > 0)",
|
|
5677
|
+
].join("\n"),
|
|
5678
|
+
},
|
|
5679
|
+
|
|
5680
|
+
// ── Container pretty-printing ─────────────────────────────────────────────
|
|
5681
|
+
|
|
5682
|
+
{
|
|
5683
|
+
name: "repr_list_pretty",
|
|
5684
|
+
description: "repr/str of lists uses repr on elements (quotes strings, shows None/True)",
|
|
5685
|
+
src: [
|
|
5686
|
+
"# globals: assrt",
|
|
5687
|
+
"assrt.equal(repr([1, 'hello', None, True]), \"[1, 'hello', None, True]\")",
|
|
5688
|
+
"assrt.equal(str([1, 'hello', None, True]), \"[1, 'hello', None, True]\")",
|
|
5689
|
+
"assrt.equal(repr([]), '[]')",
|
|
5690
|
+
"assrt.equal(str([]), '[]')",
|
|
5691
|
+
].join("\n"),
|
|
5692
|
+
},
|
|
5693
|
+
|
|
5694
|
+
{
|
|
5695
|
+
name: "repr_dict_pretty",
|
|
5696
|
+
description: "repr/str of dicts uses single-quoted keys and values",
|
|
5697
|
+
src: [
|
|
5698
|
+
"# globals: assrt",
|
|
5699
|
+
"d = dict()",
|
|
5700
|
+
"d.set('key', 'val')",
|
|
5701
|
+
"assrt.equal(repr(d), \"{'key': 'val'}\")",
|
|
5702
|
+
"assrt.equal(str(d), \"{'key': 'val'}\")",
|
|
5703
|
+
].join("\n"),
|
|
5704
|
+
},
|
|
5705
|
+
|
|
5706
|
+
{
|
|
5707
|
+
name: "repr_set_pretty",
|
|
5708
|
+
description: "repr/str of sets uses repr on elements",
|
|
5709
|
+
src: [
|
|
5710
|
+
"# globals: assrt",
|
|
5711
|
+
"s = {1, 'two'}",
|
|
5712
|
+
"r = repr(s)",
|
|
5713
|
+
"assrt.ok(r.indexOf(\"'two'\") >= 0, 'set repr should quote strings')",
|
|
5714
|
+
"assrt.ok(r.indexOf('1') >= 0, 'set repr should include numbers')",
|
|
5715
|
+
"assrt.ok(r[0] is '{' and r[r.length-1] is '}', 'set repr uses braces')",
|
|
5716
|
+
].join("\n"),
|
|
5717
|
+
},
|
|
5718
|
+
|
|
5719
|
+
{
|
|
5720
|
+
name: "repr_nested_containers",
|
|
5721
|
+
description: "repr handles nested containers correctly",
|
|
5722
|
+
src: [
|
|
5723
|
+
"# globals: assrt",
|
|
5724
|
+
"assrt.equal(repr([[1], [2, 3]]), '[[1], [2, 3]]')",
|
|
5725
|
+
"assrt.equal(repr([None, True, False]), '[None, True, False]')",
|
|
5726
|
+
].join("\n"),
|
|
5727
|
+
},
|
|
5728
|
+
|
|
5729
|
+
{
|
|
5730
|
+
name: "repr_string_single_quotes",
|
|
5731
|
+
description: "repr of strings uses Python-style single quotes",
|
|
5732
|
+
src: [
|
|
5733
|
+
"# globals: assrt",
|
|
5734
|
+
"assrt.equal(repr('hello'), \"'hello'\")",
|
|
5735
|
+
"assrt.equal(repr(''), \"''\")",
|
|
5736
|
+
].join("\n"),
|
|
5737
|
+
},
|
|
5738
|
+
|
|
5739
|
+
{
|
|
5740
|
+
name: "repr_frozenset_pretty",
|
|
5741
|
+
description: "repr/str of frozenset uses repr on elements",
|
|
5742
|
+
src: [
|
|
5743
|
+
"# globals: assrt",
|
|
5744
|
+
"fs = frozenset([1, 'x'])",
|
|
5745
|
+
"r = repr(fs)",
|
|
5746
|
+
"assrt.ok(r.indexOf('frozenset(') is 0, 'starts with frozenset(')",
|
|
5747
|
+
"assrt.ok(r.indexOf(\"'x'\") >= 0, 'frozenset repr should quote strings')",
|
|
5748
|
+
].join("\n"),
|
|
5749
|
+
},
|
|
5750
|
+
|
|
5296
5751
|
];
|
|
5297
5752
|
|
|
5298
5753
|
// ── Runner ───────────────────────────────────────────────────────────────────
|
|
@@ -969,6 +969,7 @@ function make_tests(CompletionEngine, detect_context, SourceAnalyzer, DtsRegistr
|
|
|
969
969
|
assert_has(list, 'Counter', 'Counter in collections completions');
|
|
970
970
|
assert_has(list, 'OrderedDict', 'OrderedDict in collections completions');
|
|
971
971
|
assert_has(list, 'defaultdict', 'defaultdict in collections completions');
|
|
972
|
+
assert_has(list, 'ChainMap', 'ChainMap in collections completions');
|
|
972
973
|
},
|
|
973
974
|
},
|
|
974
975
|
|
|
@@ -1370,6 +1371,7 @@ function make_tests(CompletionEngine, detect_context, SourceAnalyzer, DtsRegistr
|
|
|
1370
1371
|
assert_has(list, 'Counter', 'Counter from collections');
|
|
1371
1372
|
assert_has(list, 'OrderedDict', 'OrderedDict from collections');
|
|
1372
1373
|
assert_has(list, 'defaultdict', 'defaultdict from collections');
|
|
1374
|
+
assert_has(list, 'ChainMap', 'ChainMap from collections');
|
|
1373
1375
|
},
|
|
1374
1376
|
},
|
|
1375
1377
|
|
|
@@ -458,6 +458,119 @@ function make_tests(parse_dts, DtsRegistry, TypeInfo) {
|
|
|
458
458
|
},
|
|
459
459
|
},
|
|
460
460
|
|
|
461
|
+
// ── Interface extends ─────────────────────────────────────────────
|
|
462
|
+
|
|
463
|
+
{
|
|
464
|
+
name: "parse_interface_extends",
|
|
465
|
+
description: "interface extends clause is parsed into extends_names",
|
|
466
|
+
run: function () {
|
|
467
|
+
var src = [
|
|
468
|
+
"interface Animal {",
|
|
469
|
+
" name: string;",
|
|
470
|
+
"}",
|
|
471
|
+
"interface Dog extends Animal {",
|
|
472
|
+
" breed: string;",
|
|
473
|
+
"}",
|
|
474
|
+
].join("\n");
|
|
475
|
+
var types = parse_dts(src);
|
|
476
|
+
assert.strictEqual(types.length, 2);
|
|
477
|
+
var dog = types[1];
|
|
478
|
+
assert.strictEqual(dog.name, "Dog");
|
|
479
|
+
assert.ok(dog.extends_names, "should have extends_names");
|
|
480
|
+
assert.deepStrictEqual(dog.extends_names, ["Animal"]);
|
|
481
|
+
// Animal should have no extends_names
|
|
482
|
+
assert.strictEqual(types[0].extends_names, null);
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
|
|
486
|
+
{
|
|
487
|
+
name: "parse_interface_extends_multiple",
|
|
488
|
+
description: "interface extends multiple parents parsed correctly",
|
|
489
|
+
run: function () {
|
|
490
|
+
var src = [
|
|
491
|
+
"interface A { a: number; }",
|
|
492
|
+
"interface B { b: string; }",
|
|
493
|
+
"interface C extends A, B {",
|
|
494
|
+
" c: boolean;",
|
|
495
|
+
"}",
|
|
496
|
+
].join("\n");
|
|
497
|
+
var types = parse_dts(src);
|
|
498
|
+
var c = types.find(function (t) { return t.name === "C"; });
|
|
499
|
+
assert.ok(c, "should find C");
|
|
500
|
+
assert.deepStrictEqual(c.extends_names, ["A", "B"]);
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
|
|
504
|
+
{
|
|
505
|
+
name: "registry_getAllMembers_inherits",
|
|
506
|
+
description: "getAllMembers includes inherited members",
|
|
507
|
+
run: function () {
|
|
508
|
+
var reg = new DtsRegistry();
|
|
509
|
+
reg.addDts("test", [
|
|
510
|
+
"interface Person {",
|
|
511
|
+
" name: string;",
|
|
512
|
+
" age: number;",
|
|
513
|
+
"}",
|
|
514
|
+
"interface Player extends Person {",
|
|
515
|
+
" score: number;",
|
|
516
|
+
"}",
|
|
517
|
+
].join("\n"));
|
|
518
|
+
var player = reg.getGlobal("Player");
|
|
519
|
+
var all = reg.getAllMembers(player);
|
|
520
|
+
assert.ok(all.has("score"), "should have own member score");
|
|
521
|
+
assert.ok(all.has("name"), "should have inherited member name");
|
|
522
|
+
assert.ok(all.has("age"), "should have inherited member age");
|
|
523
|
+
assert.strictEqual(all.size, 3);
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
|
|
527
|
+
{
|
|
528
|
+
name: "registry_getAllMembers_override",
|
|
529
|
+
description: "child members shadow parent members",
|
|
530
|
+
run: function () {
|
|
531
|
+
var reg = new DtsRegistry();
|
|
532
|
+
reg.addDts("test", [
|
|
533
|
+
"interface Base {",
|
|
534
|
+
" value: string;",
|
|
535
|
+
" info(): string;",
|
|
536
|
+
"}",
|
|
537
|
+
"interface Child extends Base {",
|
|
538
|
+
" value: number;",
|
|
539
|
+
"}",
|
|
540
|
+
].join("\n"));
|
|
541
|
+
var child = reg.getGlobal("Child");
|
|
542
|
+
var all = reg.getAllMembers(child);
|
|
543
|
+
assert.strictEqual(all.get("value").return_type, "number",
|
|
544
|
+
"child value should override parent");
|
|
545
|
+
assert.ok(all.has("info"), "should inherit info");
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
|
|
549
|
+
{
|
|
550
|
+
name: "registry_getMemberInfo_inherits",
|
|
551
|
+
description: "getMemberInfo finds inherited members",
|
|
552
|
+
run: function () {
|
|
553
|
+
var reg = new DtsRegistry();
|
|
554
|
+
reg.addDts("test", [
|
|
555
|
+
"interface Person {",
|
|
556
|
+
" city: string;",
|
|
557
|
+
"}",
|
|
558
|
+
"interface Player extends Person {",
|
|
559
|
+
" score: number;",
|
|
560
|
+
"}",
|
|
561
|
+
"declare var player: Player;",
|
|
562
|
+
].join("\n"));
|
|
563
|
+
// Direct member
|
|
564
|
+
var score = reg.getMemberInfo("player", "score");
|
|
565
|
+
assert.ok(score, "should find direct member score");
|
|
566
|
+
assert.strictEqual(score.return_type, "number");
|
|
567
|
+
// Inherited member
|
|
568
|
+
var city = reg.getMemberInfo("player", "city");
|
|
569
|
+
assert.ok(city, "should find inherited member city");
|
|
570
|
+
assert.strictEqual(city.return_type, "string");
|
|
571
|
+
},
|
|
572
|
+
},
|
|
573
|
+
|
|
461
574
|
];
|
|
462
575
|
|
|
463
576
|
return TESTS;
|