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
|
@@ -900,13 +900,14 @@ function make_tests(Diagnostics, RS, STDLIB_MODULES) {
|
|
|
900
900
|
description: "Importing all collections classes produces no errors",
|
|
901
901
|
run: function () {
|
|
902
902
|
var markers = d().check([
|
|
903
|
-
"from collections import defaultdict, Counter, OrderedDict, deque, namedtuple",
|
|
903
|
+
"from collections import defaultdict, Counter, OrderedDict, deque, namedtuple, ChainMap",
|
|
904
904
|
"d = defaultdict(list)",
|
|
905
905
|
"c = Counter([1, 2, 2, 3])",
|
|
906
906
|
"od = OrderedDict()",
|
|
907
907
|
"dq = deque([1, 2, 3])",
|
|
908
908
|
"Point = namedtuple('Point', 'x y')",
|
|
909
|
-
"
|
|
909
|
+
"cm = ChainMap({'a': 1}, {'b': 2})",
|
|
910
|
+
"print(d, c, od, dq, Point, cm)",
|
|
910
911
|
].join("\n"),
|
|
911
912
|
{ virtualFiles: { mymod: "def foo(): pass" } }
|
|
912
913
|
);
|
|
@@ -930,6 +931,36 @@ function make_tests(Diagnostics, RS, STDLIB_MODULES) {
|
|
|
930
931
|
},
|
|
931
932
|
},
|
|
932
933
|
|
|
934
|
+
{
|
|
935
|
+
name: "stdlib_statistics_no_bad_import",
|
|
936
|
+
description: "Importing and using statistics functions produces no errors",
|
|
937
|
+
run: function () {
|
|
938
|
+
var markers = d().check([
|
|
939
|
+
"from statistics import mean, median, mode, stdev, variance",
|
|
940
|
+
"from statistics import quantiles, correlation, linear_regression",
|
|
941
|
+
"from statistics import NormalDist, StatisticsError",
|
|
942
|
+
"data = [1, 2, 3, 4, 5]",
|
|
943
|
+
"m = mean(data)",
|
|
944
|
+
"md = median(data)",
|
|
945
|
+
"mo = mode(data)",
|
|
946
|
+
"sd = stdev(data)",
|
|
947
|
+
"v = variance(data)",
|
|
948
|
+
"q = quantiles(data)",
|
|
949
|
+
"c = correlation(data, data)",
|
|
950
|
+
"lr = linear_regression(data, data)",
|
|
951
|
+
"nd = NormalDist(0, 1)",
|
|
952
|
+
"print(m, md, mo, sd, v, q, c, lr.slope, lr.intercept)",
|
|
953
|
+
"print(nd.mean, nd.stdev, nd.cdf(0), nd.pdf(0), StatisticsError)",
|
|
954
|
+
].join("\n"),
|
|
955
|
+
{ virtualFiles: { sentinel: "x = 1" } }
|
|
956
|
+
);
|
|
957
|
+
var errors = markers.filter(function (m) { return m.severity === SEV_ERROR; });
|
|
958
|
+
assert.deepStrictEqual(errors, [],
|
|
959
|
+
"Expected no errors for statistics imports and usage, got: " +
|
|
960
|
+
JSON.stringify(errors.map(function (m) { return m.message; })));
|
|
961
|
+
},
|
|
962
|
+
},
|
|
963
|
+
|
|
933
964
|
{
|
|
934
965
|
name: "copy_no_bad_import",
|
|
935
966
|
description: "from copy import copy, deepcopy produces no bad-import error",
|
|
@@ -1591,6 +1622,108 @@ function make_tests(Diagnostics, RS, STDLIB_MODULES) {
|
|
|
1591
1622
|
},
|
|
1592
1623
|
},
|
|
1593
1624
|
|
|
1625
|
+
// ── BigInt literals ──────────────────────────────────────────────
|
|
1626
|
+
|
|
1627
|
+
{
|
|
1628
|
+
name: "bigint_literal_no_errors",
|
|
1629
|
+
description: "BigInt literals (42n, 0xFFn, 0b1010n, 0o77n) produce no markers",
|
|
1630
|
+
run: function () {
|
|
1631
|
+
var markers = d().check([
|
|
1632
|
+
"x = 42n",
|
|
1633
|
+
"y = 0xFFn",
|
|
1634
|
+
"z = 0b1010n",
|
|
1635
|
+
"w = 0o77n",
|
|
1636
|
+
].join("\n"));
|
|
1637
|
+
assert.deepStrictEqual(markers, [],
|
|
1638
|
+
"Expected no markers for bigint literals, got: " + JSON.stringify(markers));
|
|
1639
|
+
},
|
|
1640
|
+
},
|
|
1641
|
+
|
|
1642
|
+
{
|
|
1643
|
+
name: "bigint_literal_assignment_no_errors",
|
|
1644
|
+
description: "BigInt literal assignment and arithmetic produce no markers",
|
|
1645
|
+
run: function () {
|
|
1646
|
+
var markers = d().check([
|
|
1647
|
+
"x = 42n",
|
|
1648
|
+
"y = x + 1n",
|
|
1649
|
+
].join("\n"));
|
|
1650
|
+
assert.deepStrictEqual(markers, [],
|
|
1651
|
+
"Expected no markers for bigint assignment, got: " + JSON.stringify(markers));
|
|
1652
|
+
},
|
|
1653
|
+
},
|
|
1654
|
+
|
|
1655
|
+
// ── Exception.args ───────────────────────────────────────────────
|
|
1656
|
+
{
|
|
1657
|
+
name: "exception_args_no_errors",
|
|
1658
|
+
description: "Accessing .args on caught exception produces no diagnostics",
|
|
1659
|
+
run: function () {
|
|
1660
|
+
var markers = d().check([
|
|
1661
|
+
"try:",
|
|
1662
|
+
" raise ValueError('oops', 123)",
|
|
1663
|
+
"except ValueError as e:",
|
|
1664
|
+
" x = e.args",
|
|
1665
|
+
" y = e.args[0]",
|
|
1666
|
+
" z = len(e.args)",
|
|
1667
|
+
].join("\n"));
|
|
1668
|
+
assert.deepStrictEqual(markers, [],
|
|
1669
|
+
"Expected no markers for exception .args access, got: " + JSON.stringify(markers));
|
|
1670
|
+
},
|
|
1671
|
+
},
|
|
1672
|
+
{
|
|
1673
|
+
name: "exception_args_custom_class_no_errors",
|
|
1674
|
+
description: "Custom exception class with variadic __init__ produces no diagnostics",
|
|
1675
|
+
run: function () {
|
|
1676
|
+
var markers = d().check([
|
|
1677
|
+
"class MyError(Exception):",
|
|
1678
|
+
" def __init__(self, code, detail):",
|
|
1679
|
+
" Exception.__init__(self, code, detail)",
|
|
1680
|
+
" self.code = code",
|
|
1681
|
+
"e = MyError(404, 'not found')",
|
|
1682
|
+
"x = e.args",
|
|
1683
|
+
].join("\n"));
|
|
1684
|
+
assert.deepStrictEqual(markers, [],
|
|
1685
|
+
"Expected no markers for custom exception .args, got: " + JSON.stringify(markers));
|
|
1686
|
+
},
|
|
1687
|
+
},
|
|
1688
|
+
|
|
1689
|
+
// ── __slots__ ──────────────────────────────────────────────────────
|
|
1690
|
+
{
|
|
1691
|
+
name: "slots_no_errors",
|
|
1692
|
+
description: "Class with __slots__ produces no linter errors",
|
|
1693
|
+
run: function () {
|
|
1694
|
+
var markers = d().check([
|
|
1695
|
+
"class Point:",
|
|
1696
|
+
" __slots__ = ['x', 'y']",
|
|
1697
|
+
" def __init__(self, x, y):",
|
|
1698
|
+
" self.x = x",
|
|
1699
|
+
" self.y = y",
|
|
1700
|
+
"p = Point(1, 2)",
|
|
1701
|
+
].join("\n"));
|
|
1702
|
+
assert.deepStrictEqual(markers, [],
|
|
1703
|
+
"Expected no markers for __slots__ class, got: " + JSON.stringify(markers));
|
|
1704
|
+
},
|
|
1705
|
+
},
|
|
1706
|
+
{
|
|
1707
|
+
name: "slots_subclass_no_errors",
|
|
1708
|
+
description: "Subclass with __slots__ produces no linter errors",
|
|
1709
|
+
run: function () {
|
|
1710
|
+
var markers = d().check([
|
|
1711
|
+
"class Base:",
|
|
1712
|
+
" __slots__ = ['x']",
|
|
1713
|
+
" def __init__(self):",
|
|
1714
|
+
" self.x = 1",
|
|
1715
|
+
"class Child(Base):",
|
|
1716
|
+
" __slots__ = ['y']",
|
|
1717
|
+
" def __init__(self):",
|
|
1718
|
+
" Base.__init__(self)",
|
|
1719
|
+
" self.y = 2",
|
|
1720
|
+
"c = Child()",
|
|
1721
|
+
].join("\n"));
|
|
1722
|
+
assert.deepStrictEqual(markers, [],
|
|
1723
|
+
"Expected no markers for __slots__ subclass, got: " + JSON.stringify(markers));
|
|
1724
|
+
},
|
|
1725
|
+
},
|
|
1726
|
+
|
|
1594
1727
|
];
|
|
1595
1728
|
|
|
1596
1729
|
return TESTS;
|
package/test/unit/web-repl.js
CHANGED
|
@@ -270,6 +270,95 @@ var TESTS = [
|
|
|
270
270
|
},
|
|
271
271
|
},
|
|
272
272
|
|
|
273
|
+
{
|
|
274
|
+
name: "bundle_chainmap_basic",
|
|
275
|
+
description: "ChainMap construction and first-map-wins lookup work in the web-repl bundle",
|
|
276
|
+
run: function () {
|
|
277
|
+
var repl = RS.web_repl();
|
|
278
|
+
var js = bundle_compile(repl, [
|
|
279
|
+
"from collections import ChainMap",
|
|
280
|
+
"defaults = {'color': 'red', 'user': 'guest'}",
|
|
281
|
+
"overrides = {'user': 'admin'}",
|
|
282
|
+
"cm = ChainMap(overrides, defaults)",
|
|
283
|
+
"assrt.equal(cm['user'], 'admin')",
|
|
284
|
+
"assrt.equal(cm['color'], 'red')",
|
|
285
|
+
"assrt.equal(len(cm), 2)",
|
|
286
|
+
"assrt.ok('color' in cm)",
|
|
287
|
+
"assrt.ok('missing' not in cm)",
|
|
288
|
+
"assrt.equal(cm.get('missing', 'fallback'), 'fallback')",
|
|
289
|
+
].join("\n"));
|
|
290
|
+
run_js(js);
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
{
|
|
295
|
+
name: "bundle_chainmap_writes",
|
|
296
|
+
description: "ChainMap writes, deletes and updates affect only the first map in the bundle",
|
|
297
|
+
run: function () {
|
|
298
|
+
var repl = RS.web_repl();
|
|
299
|
+
var js = bundle_compile(repl, [
|
|
300
|
+
"from collections import ChainMap",
|
|
301
|
+
"defaults = {'depth': 1}",
|
|
302
|
+
"cm = ChainMap({}, defaults)",
|
|
303
|
+
"cm['depth'] = 99",
|
|
304
|
+
"assrt.equal(cm['depth'], 99)",
|
|
305
|
+
"assrt.equal(defaults['depth'], 1)",
|
|
306
|
+
"del cm['depth']",
|
|
307
|
+
"assrt.equal(cm['depth'], 1)",
|
|
308
|
+
"cm.update({'a': 1}, b=2)",
|
|
309
|
+
"assrt.equal(cm['a'], 1)",
|
|
310
|
+
"assrt.equal(cm['b'], 2)",
|
|
311
|
+
"assrt.equal(cm.pop('a'), 1)",
|
|
312
|
+
"assrt.equal(cm.pop('depth', 'dflt'), 'dflt')",
|
|
313
|
+
"assrt.equal(cm.setdefault('new', 7), 7)",
|
|
314
|
+
"assrt.equal(cm['new'], 7)",
|
|
315
|
+
].join("\n"));
|
|
316
|
+
run_js(js);
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
{
|
|
321
|
+
name: "bundle_chainmap_new_child",
|
|
322
|
+
description: "ChainMap new_child and parents work in the web-repl bundle",
|
|
323
|
+
run: function () {
|
|
324
|
+
var repl = RS.web_repl();
|
|
325
|
+
var js = bundle_compile(repl, [
|
|
326
|
+
"from collections import ChainMap",
|
|
327
|
+
"base = ChainMap({'x': 1})",
|
|
328
|
+
"child = base.new_child({'x': 2, 'y': 3})",
|
|
329
|
+
"assrt.equal(child['x'], 2)",
|
|
330
|
+
"assrt.equal(child['y'], 3)",
|
|
331
|
+
"assrt.equal(base['x'], 1)",
|
|
332
|
+
"assrt.equal(child.maps.length, 2)",
|
|
333
|
+
"parents = child.parents",
|
|
334
|
+
"assrt.equal(parents['x'], 1)",
|
|
335
|
+
"assrt.equal(parents.maps.length, 1)",
|
|
336
|
+
].join("\n"));
|
|
337
|
+
run_js(js);
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
{
|
|
342
|
+
name: "bundle_chainmap_iteration",
|
|
343
|
+
description: "ChainMap keys/values/items, iteration order and copy work in the bundle",
|
|
344
|
+
run: function () {
|
|
345
|
+
var repl = RS.web_repl();
|
|
346
|
+
var js = bundle_compile(repl, [
|
|
347
|
+
"from collections import ChainMap",
|
|
348
|
+
"cm = ChainMap({'a': 1, 'b': 2}, {'c': 3})",
|
|
349
|
+
"assrt.deepEqual(list(cm), ['c', 'a', 'b'])",
|
|
350
|
+
"assrt.deepEqual(cm.keys(), ['c', 'a', 'b'])",
|
|
351
|
+
"assrt.deepEqual(cm.values(), [3, 1, 2])",
|
|
352
|
+
"dup = cm.copy()",
|
|
353
|
+
"dup['a'] = 100",
|
|
354
|
+
"assrt.equal(cm['a'], 1)",
|
|
355
|
+
"assrt.equal(dup['a'], 100)",
|
|
356
|
+
"assrt.equal(dup['c'], 3)",
|
|
357
|
+
].join("\n"));
|
|
358
|
+
run_js(js);
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
|
|
273
362
|
{
|
|
274
363
|
name: "bundle_operator_overloading",
|
|
275
364
|
description: "overload_operators flag works in the web-repl bundle",
|
|
@@ -1290,7 +1379,7 @@ var TESTS = [
|
|
|
1290
1379
|
var js = bundle_compile(repl, [
|
|
1291
1380
|
"msg = 'hello'",
|
|
1292
1381
|
"nums = [1, 2, 3]",
|
|
1293
|
-
"assrt.equal(f'{msg=!r}', '
|
|
1382
|
+
"assrt.equal(f'{msg=!r}', \"msg='hello'\")",
|
|
1294
1383
|
"assrt.equal(f'{nums=!r}', 'nums=[1, 2, 3]')",
|
|
1295
1384
|
].join("\n"));
|
|
1296
1385
|
run_js(js);
|
|
@@ -3914,6 +4003,121 @@ var TESTS = [
|
|
|
3914
4003
|
},
|
|
3915
4004
|
},
|
|
3916
4005
|
|
|
4006
|
+
// ── pprint stdlib ────────────────────────────────────────────────────────
|
|
4007
|
+
|
|
4008
|
+
{
|
|
4009
|
+
name: "bundle_pprint_basic",
|
|
4010
|
+
description: "pprint stdlib: pformat of atoms and short containers in the web-repl bundle",
|
|
4011
|
+
run: function () {
|
|
4012
|
+
var repl = RS.web_repl();
|
|
4013
|
+
var js = bundle_compile(repl, [
|
|
4014
|
+
"from pprint import pformat",
|
|
4015
|
+
// atoms -> repr()
|
|
4016
|
+
"assrt.equal(pformat(None), 'None')",
|
|
4017
|
+
"assrt.equal(pformat(True), 'True')",
|
|
4018
|
+
"assrt.equal(pformat(42), '42')",
|
|
4019
|
+
"assrt.equal(pformat('hi'), \"'hi'\")",
|
|
4020
|
+
// empty containers
|
|
4021
|
+
"assrt.equal(pformat([]), '[]')",
|
|
4022
|
+
"assrt.equal(pformat({}), '{}')",
|
|
4023
|
+
"assrt.equal(pformat(set()), 'set()')",
|
|
4024
|
+
// short containers fit on one line
|
|
4025
|
+
"assrt.equal(pformat([1, 2, 3]), '[1, 2, 3]')",
|
|
4026
|
+
"assrt.equal(pformat({'a': 1, 'b': 2}), \"{'a': 1, 'b': 2}\")",
|
|
4027
|
+
"assrt.equal(pformat(frozenset([1])), 'frozenset({1})')",
|
|
4028
|
+
].join("\n"));
|
|
4029
|
+
run_js(js);
|
|
4030
|
+
},
|
|
4031
|
+
},
|
|
4032
|
+
|
|
4033
|
+
{
|
|
4034
|
+
name: "bundle_pprint_wrap",
|
|
4035
|
+
description: "pprint stdlib: wide containers break across lines in the web-repl bundle",
|
|
4036
|
+
run: function () {
|
|
4037
|
+
var repl = RS.web_repl();
|
|
4038
|
+
var js = bundle_compile(repl, [
|
|
4039
|
+
"from pprint import pformat",
|
|
4040
|
+
// wide list breaks one element per line
|
|
4041
|
+
"assrt.equal(pformat([1, 2, 3], width=5), '[1,\\n 2,\\n 3]')",
|
|
4042
|
+
// wide dict breaks, keys sorted by default
|
|
4043
|
+
"assrt.equal(pformat({'name': 'Al', 'age': 3}, width=12), \"{'age': 3,\\n 'name': 'Al'}\")",
|
|
4044
|
+
// indent parameter widens inner indentation
|
|
4045
|
+
"assrt.equal(pformat([1, 2, 3], width=5, indent=4), '[ 1,\\n 2,\\n 3]')",
|
|
4046
|
+
// single-element containers never break
|
|
4047
|
+
"assrt.equal(pformat([42], width=1), '[42]')",
|
|
4048
|
+
].join("\n"));
|
|
4049
|
+
run_js(js);
|
|
4050
|
+
},
|
|
4051
|
+
},
|
|
4052
|
+
|
|
4053
|
+
{
|
|
4054
|
+
name: "bundle_pprint_features",
|
|
4055
|
+
description: "pprint stdlib: depth, compact, sort_dicts, and pp() in the web-repl bundle",
|
|
4056
|
+
run: function () {
|
|
4057
|
+
var repl = RS.web_repl();
|
|
4058
|
+
var js = bundle_compile(repl, [
|
|
4059
|
+
"from pprint import pformat, pp",
|
|
4060
|
+
// depth limits expansion
|
|
4061
|
+
"assrt.equal(pformat([1, [2, [3]]], depth=1), '[1, [...]]')",
|
|
4062
|
+
"assrt.equal(pformat([1, [2, [3]]], depth=2), '[1, [2, [...]]]')",
|
|
4063
|
+
// sort_dicts=False keeps insertion order (ρσ_dict preserves it)
|
|
4064
|
+
"d = dict()",
|
|
4065
|
+
"d.set('c', 1)",
|
|
4066
|
+
"d.set('a', 2)",
|
|
4067
|
+
"assrt.equal(pformat(d, sort_dicts=False), \"{'c': 1, 'a': 2}\")",
|
|
4068
|
+
"assrt.equal(pformat(d, sort_dicts=True), \"{'a': 2, 'c': 1}\")",
|
|
4069
|
+
// compact packs multiple items per line
|
|
4070
|
+
"compact_out = pformat([1, 2, 3, 4, 5, 6, 7, 8], compact=True, width=15)",
|
|
4071
|
+
"assrt.equal(compact_out, '[1, 2, 3, 4, 5,\\n 6, 7, 8]')",
|
|
4072
|
+
// pp() writes to a custom stream and defaults sort_dicts=False
|
|
4073
|
+
"class _C:",
|
|
4074
|
+
" def __init__(self):",
|
|
4075
|
+
" self.parts = []",
|
|
4076
|
+
" def write(self, s):",
|
|
4077
|
+
" self.parts.push(s)",
|
|
4078
|
+
"col = _C()",
|
|
4079
|
+
"pp(d, stream=col)",
|
|
4080
|
+
"assrt.equal(col.parts.join(''), \"{'c': 1, 'a': 2}\\n\")",
|
|
4081
|
+
].join("\n"));
|
|
4082
|
+
run_js(js);
|
|
4083
|
+
},
|
|
4084
|
+
},
|
|
4085
|
+
|
|
4086
|
+
{
|
|
4087
|
+
name: "bundle_pprint_safe",
|
|
4088
|
+
description: "pprint stdlib: saferepr, isreadable, isrecursive, PrettyPrinter in the web-repl bundle",
|
|
4089
|
+
run: function () {
|
|
4090
|
+
var repl = RS.web_repl();
|
|
4091
|
+
var js = bundle_compile(repl, [
|
|
4092
|
+
"from pprint import saferepr, isreadable, isrecursive, PrettyPrinter",
|
|
4093
|
+
// saferepr of normal structures == single-line repr
|
|
4094
|
+
"assrt.equal(saferepr([1, 2, 3]), '[1, 2, 3]')",
|
|
4095
|
+
"assrt.equal(saferepr({'a': 1}), \"{'a': 1}\")",
|
|
4096
|
+
// isreadable / isrecursive on plain structures
|
|
4097
|
+
"assrt.ok(isreadable([1, 2, 3]))",
|
|
4098
|
+
"assrt.ok(not isrecursive([1, 2, 3]))",
|
|
4099
|
+
// self-referential list -> recursion detected and marked
|
|
4100
|
+
"cyclic = [1, 2]",
|
|
4101
|
+
"cyclic.push(cyclic)",
|
|
4102
|
+
"assrt.ok(isrecursive(cyclic))",
|
|
4103
|
+
"assrt.ok(not isreadable(cyclic))",
|
|
4104
|
+
"assrt.ok(saferepr(cyclic).indexOf('<Recursion on') >= 0)",
|
|
4105
|
+
// PrettyPrinter class: pformat + instance predicates
|
|
4106
|
+
"p = PrettyPrinter(indent=2, width=8)",
|
|
4107
|
+
"assrt.equal(p.pformat([10, 20, 30]), '[ 10,\\n 20,\\n 30]')",
|
|
4108
|
+
"assrt.ok(p.isrecursive(cyclic))",
|
|
4109
|
+
// invalid args raise ValueError
|
|
4110
|
+
"caught = False",
|
|
4111
|
+
"try:",
|
|
4112
|
+
" PrettyPrinter(depth=0)",
|
|
4113
|
+
"except ValueError:",
|
|
4114
|
+
" caught = True",
|
|
4115
|
+
"assrt.ok(caught)",
|
|
4116
|
+
].join("\n"));
|
|
4117
|
+
run_js(js);
|
|
4118
|
+
},
|
|
4119
|
+
},
|
|
4120
|
+
|
|
3917
4121
|
{
|
|
3918
4122
|
name: "bundle_type_enforcement_basic",
|
|
3919
4123
|
description: "type_enforcement: max args, missing required, type annotations",
|
|
@@ -4275,6 +4479,150 @@ var TESTS = [
|
|
|
4275
4479
|
},
|
|
4276
4480
|
},
|
|
4277
4481
|
|
|
4482
|
+
// ── statistics ───────────────────────────────────────────────────────────
|
|
4483
|
+
|
|
4484
|
+
{
|
|
4485
|
+
name: "bundle_statistics_averages",
|
|
4486
|
+
description: "statistics stdlib: averages and central location in the web-repl bundle",
|
|
4487
|
+
run: function () {
|
|
4488
|
+
var repl = RS.web_repl();
|
|
4489
|
+
var js = bundle_compile(repl, [
|
|
4490
|
+
"from statistics import mean, fmean, median, median_low, median_high",
|
|
4491
|
+
"from statistics import mode, multimode, harmonic_mean, geometric_mean",
|
|
4492
|
+
"assrt.equal(mean([1, 2, 3, 4]), 2.5)",
|
|
4493
|
+
"assrt.equal(mean([1, 2, 3]), 2)",
|
|
4494
|
+
"assrt.equal(fmean([1, 2, 3, 4]), 2.5)",
|
|
4495
|
+
"assrt.equal(median([1, 3, 5]), 3)",
|
|
4496
|
+
"assrt.equal(median([1, 3, 5, 7]), 4)",
|
|
4497
|
+
"assrt.equal(median([5, 1, 3]), 3)", // unsorted input
|
|
4498
|
+
"assrt.equal(median_low([1, 3, 5, 7]), 3)",
|
|
4499
|
+
"assrt.equal(median_high([1, 3, 5, 7]), 5)",
|
|
4500
|
+
"assrt.equal(mode([1, 1, 2, 3, 3, 3]), 3)",
|
|
4501
|
+
"assrt.equal(mode(['x', 'y', 'x']), 'x')",
|
|
4502
|
+
"assrt.deepEqual(multimode([1, 1, 2, 2, 3]), [1, 2])",
|
|
4503
|
+
"assrt.ok(Math.abs(harmonic_mean([40, 60]) - 48.0) < 1e-9)",
|
|
4504
|
+
"assrt.ok(Math.abs(geometric_mean([2, 8]) - 4.0) < 1e-9)",
|
|
4505
|
+
].join("\n"));
|
|
4506
|
+
run_js(js);
|
|
4507
|
+
},
|
|
4508
|
+
},
|
|
4509
|
+
|
|
4510
|
+
{
|
|
4511
|
+
name: "bundle_statistics_spread",
|
|
4512
|
+
description: "statistics stdlib: variance, stdev and quantiles in the web-repl bundle",
|
|
4513
|
+
run: function () {
|
|
4514
|
+
var repl = RS.web_repl();
|
|
4515
|
+
var js = bundle_compile(repl, [
|
|
4516
|
+
"from statistics import variance, pvariance, stdev, pstdev, quantiles",
|
|
4517
|
+
"assrt.equal(variance([1, 2, 3, 4, 5]), 2.5)",
|
|
4518
|
+
"assrt.equal(pvariance([1, 2, 3, 4, 5]), 2.0)",
|
|
4519
|
+
"assrt.ok(Math.abs(stdev([1, 2, 3, 4, 5]) - Math.sqrt(2.5)) < 1e-9)",
|
|
4520
|
+
"assrt.ok(Math.abs(pstdev([1, 2, 3, 4, 5]) - Math.sqrt(2.0)) < 1e-9)",
|
|
4521
|
+
"assrt.deepEqual(quantiles([1, 2, 3, 4]), [1.25, 2.5, 3.75])",
|
|
4522
|
+
"q = quantiles([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], n=10)",
|
|
4523
|
+
"assrt.equal(q.length, 9)",
|
|
4524
|
+
].join("\n"));
|
|
4525
|
+
run_js(js);
|
|
4526
|
+
},
|
|
4527
|
+
},
|
|
4528
|
+
|
|
4529
|
+
{
|
|
4530
|
+
name: "bundle_statistics_relations",
|
|
4531
|
+
description: "statistics stdlib: covariance, correlation, linear_regression in the bundle",
|
|
4532
|
+
run: function () {
|
|
4533
|
+
var repl = RS.web_repl();
|
|
4534
|
+
var js = bundle_compile(repl, [
|
|
4535
|
+
"from statistics import covariance, correlation, linear_regression",
|
|
4536
|
+
"x = [1, 2, 3, 4, 5, 6, 7, 8, 9]",
|
|
4537
|
+
"y = [1, 2, 3, 1, 2, 3, 1, 2, 3]",
|
|
4538
|
+
"assrt.ok(Math.abs(covariance(x, y) - 0.75) < 1e-9)",
|
|
4539
|
+
"assrt.ok(Math.abs(correlation(x, x) - 1.0) < 1e-9)",
|
|
4540
|
+
"lr = linear_regression([1, 2, 3, 4, 5], [2, 4, 6, 8, 10])",
|
|
4541
|
+
"assrt.ok(Math.abs(lr.slope - 2.0) < 1e-9)",
|
|
4542
|
+
"assrt.ok(Math.abs(lr.intercept - 0.0) < 1e-9)",
|
|
4543
|
+
].join("\n"));
|
|
4544
|
+
run_js(js);
|
|
4545
|
+
},
|
|
4546
|
+
},
|
|
4547
|
+
|
|
4548
|
+
{
|
|
4549
|
+
name: "bundle_statistics_normaldist",
|
|
4550
|
+
description: "statistics stdlib: NormalDist in the web-repl bundle",
|
|
4551
|
+
run: function () {
|
|
4552
|
+
var repl = RS.web_repl();
|
|
4553
|
+
var js = bundle_compile(repl, [
|
|
4554
|
+
"from statistics import NormalDist",
|
|
4555
|
+
"nd = NormalDist(100, 15)",
|
|
4556
|
+
"assrt.equal(nd.mean, 100)",
|
|
4557
|
+
"assrt.equal(nd.stdev, 15)",
|
|
4558
|
+
"assrt.equal(nd.variance, 225)",
|
|
4559
|
+
"assrt.ok(Math.abs(nd.cdf(100) - 0.5) < 1e-6)",
|
|
4560
|
+
"assrt.equal(nd.inv_cdf(0.5), 100)",
|
|
4561
|
+
"assrt.equal(nd.zscore(115), 1.0)",
|
|
4562
|
+
"fs = NormalDist.from_samples([1, 2, 3, 4, 5])",
|
|
4563
|
+
"assrt.ok(Math.abs(fs.mean - 3.0) < 1e-9)",
|
|
4564
|
+
// operator overloading dispatches to __add__
|
|
4565
|
+
"combined = nd + NormalDist(50, 20)",
|
|
4566
|
+
"assrt.equal(combined.mean, 150)",
|
|
4567
|
+
"assrt.equal(combined.stdev, 25)",
|
|
4568
|
+
].join("\n"));
|
|
4569
|
+
run_js(js);
|
|
4570
|
+
},
|
|
4571
|
+
},
|
|
4572
|
+
|
|
4573
|
+
// ── list sort: comparator detection + __lt__ dispatch ────────────────────
|
|
4574
|
+
|
|
4575
|
+
{
|
|
4576
|
+
name: "bundle_sort_comparator_and_lt",
|
|
4577
|
+
description: "list sort: positional comparator and __lt__ dispatch in the web-repl bundle",
|
|
4578
|
+
run: function () {
|
|
4579
|
+
var repl = RS.web_repl();
|
|
4580
|
+
var js = bundle_compile(repl, [
|
|
4581
|
+
// a positional two-argument function is treated as a comparator
|
|
4582
|
+
"assrt.deepEqual(sorted([3, 1, 2, 10], def(x, y): return x - y;), [1, 2, 3, 10])",
|
|
4583
|
+
"m = [5, 2, 8, 1]",
|
|
4584
|
+
"m.sort(def(x, y): return y - x;)",
|
|
4585
|
+
"assrt.deepEqual(m, [8, 5, 2, 1])",
|
|
4586
|
+
// a one-argument function is still a key function
|
|
4587
|
+
"assrt.deepEqual(sorted([3, 1, 2], key=def(x): return -x;), [3, 2, 1])",
|
|
4588
|
+
// custom objects are ordered through their __lt__ method
|
|
4589
|
+
"class Ord:",
|
|
4590
|
+
" def __init__(self, v):",
|
|
4591
|
+
" self.v = v",
|
|
4592
|
+
" def __lt__(self, other):",
|
|
4593
|
+
" return self.v < other.v",
|
|
4594
|
+
"s = sorted([Ord(3), Ord(1), Ord(2)])",
|
|
4595
|
+
"assrt.deepEqual([s[0].v, s[1].v, s[2].v], [1, 2, 3])",
|
|
4596
|
+
].join("\n"));
|
|
4597
|
+
run_js(js);
|
|
4598
|
+
},
|
|
4599
|
+
},
|
|
4600
|
+
|
|
4601
|
+
// ── __slots__ ──────────────────────────────────────────────────────────
|
|
4602
|
+
{
|
|
4603
|
+
name: "slots_basic",
|
|
4604
|
+
description: "Basic __slots__ enforcement in web-repl bundle",
|
|
4605
|
+
run: function () {
|
|
4606
|
+
var repl = RS.web_repl();
|
|
4607
|
+
var js = bundle_compile(repl, [
|
|
4608
|
+
"class Point:",
|
|
4609
|
+
" __slots__ = ['x', 'y']",
|
|
4610
|
+
" def __init__(self, x, y):",
|
|
4611
|
+
" self.x = x",
|
|
4612
|
+
" self.y = y",
|
|
4613
|
+
"p = Point(1, 2)",
|
|
4614
|
+
"assrt.equal(p.x, 1)",
|
|
4615
|
+
"assrt.equal(p.y, 2)",
|
|
4616
|
+
"try:",
|
|
4617
|
+
" p.z = 3",
|
|
4618
|
+
" assrt.ok(False, 'should have raised')",
|
|
4619
|
+
"except AttributeError:",
|
|
4620
|
+
" assrt.ok(True)",
|
|
4621
|
+
].join("\n"));
|
|
4622
|
+
run_js(js);
|
|
4623
|
+
},
|
|
4624
|
+
},
|
|
4625
|
+
|
|
4278
4626
|
];
|
|
4279
4627
|
|
|
4280
4628
|
// ---------------------------------------------------------------------------
|