rapydscript-ns 0.9.0 → 0.9.2

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 (100) hide show
  1. package/.agignore +1 -1
  2. package/.github/workflows/ci.yml +38 -38
  3. package/=template.pyj +5 -5
  4. package/CHANGELOG.md +10 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/README.md +7 -6
  8. package/TODO.md +116 -1
  9. package/add-toc-to-readme +2 -2
  10. package/bin/export +75 -75
  11. package/bin/rapydscript +70 -70
  12. package/bin/web-repl-export +102 -102
  13. package/build +2 -2
  14. package/language-service/index.js +9 -9
  15. package/language-service/language-service.d.ts +1 -1
  16. package/package.json +6 -2
  17. package/publish.py +37 -37
  18. package/release/compiler.js +246 -231
  19. package/release/signatures.json +23 -23
  20. package/session.vim +4 -4
  21. package/setup.cfg +2 -2
  22. package/src/compiler.pyj +36 -36
  23. package/src/errors.pyj +30 -30
  24. package/src/lib/aes.pyj +646 -646
  25. package/src/lib/contextlib.pyj +379 -0
  26. package/src/lib/copy.pyj +120 -120
  27. package/src/lib/datetime.pyj +712 -0
  28. package/src/lib/elementmaker.pyj +83 -83
  29. package/src/lib/encodings.pyj +126 -126
  30. package/src/lib/gettext.pyj +569 -569
  31. package/src/lib/io.pyj +500 -0
  32. package/src/lib/itertools.pyj +580 -580
  33. package/src/lib/json.pyj +227 -0
  34. package/src/lib/math.pyj +193 -193
  35. package/src/lib/operator.pyj +11 -11
  36. package/src/lib/pythonize.pyj +20 -20
  37. package/src/lib/random.pyj +118 -118
  38. package/src/lib/react.pyj +74 -74
  39. package/src/lib/traceback.pyj +63 -63
  40. package/src/lib/uuid.pyj +77 -77
  41. package/src/monaco-language-service/diagnostics.js +4 -4
  42. package/src/monaco-language-service/dts.js +550 -550
  43. package/src/monaco-language-service/index.js +2 -2
  44. package/src/output/comments.pyj +45 -45
  45. package/src/output/exceptions.pyj +201 -201
  46. package/src/output/jsx.pyj +164 -164
  47. package/src/output/loops.pyj +9 -0
  48. package/src/output/treeshake.pyj +182 -182
  49. package/src/output/utils.pyj +72 -72
  50. package/src/string_interpolation.pyj +72 -72
  51. package/src/tokenizer.pyj +1 -1
  52. package/src/unicode_aliases.pyj +576 -576
  53. package/src/utils.pyj +192 -192
  54. package/test/_import_one.pyj +37 -37
  55. package/test/_import_two/__init__.pyj +11 -11
  56. package/test/_import_two/level2/deep.pyj +4 -4
  57. package/test/_import_two/other.pyj +6 -6
  58. package/test/_import_two/sub.pyj +13 -13
  59. package/test/aes_vectors.pyj +421 -421
  60. package/test/annotations.pyj +80 -80
  61. package/test/contextlib.pyj +362 -0
  62. package/test/datetime.pyj +500 -0
  63. package/test/debugger_stmt.pyj +41 -0
  64. package/test/decorators.pyj +77 -77
  65. package/test/docstrings.pyj +39 -39
  66. package/test/elementmaker_test.pyj +45 -45
  67. package/test/functions.pyj +151 -151
  68. package/test/generators.pyj +41 -41
  69. package/test/generic.pyj +370 -370
  70. package/test/imports.pyj +72 -72
  71. package/test/internationalization.pyj +73 -73
  72. package/test/io.pyj +316 -0
  73. package/test/json.pyj +196 -0
  74. package/test/lint.pyj +164 -164
  75. package/test/loops.pyj +85 -85
  76. package/test/numpy.pyj +734 -734
  77. package/test/omit_function_metadata.pyj +20 -20
  78. package/test/repl.pyj +121 -121
  79. package/test/scoped_flags.pyj +76 -76
  80. package/test/unit/index.js +66 -0
  81. package/test/unit/language-service-dts.js +543 -543
  82. package/test/unit/language-service-hover.js +455 -455
  83. package/test/unit/language-service.js +1 -1
  84. package/test/unit/web-repl.js +533 -0
  85. package/tools/compiler.d.ts +367 -0
  86. package/tools/completer.js +131 -131
  87. package/tools/gettext.js +185 -185
  88. package/tools/ini.js +65 -65
  89. package/tools/msgfmt.js +187 -187
  90. package/tools/repl.js +223 -223
  91. package/tools/test.js +118 -118
  92. package/tools/utils.js +128 -128
  93. package/tools/web_repl.js +95 -95
  94. package/try +41 -41
  95. package/web-repl/env.js +196 -196
  96. package/web-repl/index.html +163 -163
  97. package/web-repl/prism.css +139 -139
  98. package/web-repl/prism.js +113 -113
  99. package/web-repl/rapydscript.js +224 -224
  100. package/web-repl/sha1.js +25 -25
@@ -173,7 +173,7 @@ function make_tests(Diagnostics, RS, STDLIB_MODULES) {
173
173
  name: "undef_suppressed_extra_builtins",
174
174
  description: "extraBuiltins option prevents a name from being flagged",
175
175
  run: function () {
176
- var inst = new Diagnostics(RS, { MY_GLOBAL: true, ANOTHER: true });
176
+ var inst = new Diagnostics(RS, ['MY_GLOBAL', 'ANOTHER']);
177
177
  var markers = inst.check("print(MY_GLOBAL)\nprint(ANOTHER)");
178
178
  assert.deepStrictEqual(markers, []);
179
179
  },
@@ -1665,6 +1665,539 @@ var TESTS = [
1665
1665
  },
1666
1666
  },
1667
1667
 
1668
+ // ── datetime stdlib ───────────────────────────────────────────────────────
1669
+
1670
+ {
1671
+ name: "bundle_datetime_basic",
1672
+ description: "datetime stdlib: date/time/datetime/timedelta construct and report attributes correctly",
1673
+ run: function () {
1674
+ var repl = RS.web_repl();
1675
+ var js = bundle_compile(repl, [
1676
+ "from datetime import date, time, datetime, timedelta, MINYEAR, MAXYEAR",
1677
+ "assrt.equal(MINYEAR, 1)",
1678
+ "assrt.equal(MAXYEAR, 9999)",
1679
+ // date
1680
+ "d = date(2024, 6, 15)",
1681
+ "assrt.equal(d.year, 2024)",
1682
+ "assrt.equal(d.month, 6)",
1683
+ "assrt.equal(d.day, 15)",
1684
+ "assrt.equal(str(d), '2024-06-15')",
1685
+ // time
1686
+ "t = time(14, 30, 5)",
1687
+ "assrt.equal(t.hour, 14)",
1688
+ "assrt.equal(t.minute, 30)",
1689
+ "assrt.equal(str(t), '14:30:05')",
1690
+ // datetime
1691
+ "dt = datetime(2024, 6, 15, 14, 30, 5)",
1692
+ "assrt.equal(dt.year, 2024)",
1693
+ "assrt.equal(dt.hour, 14)",
1694
+ "assrt.equal(str(dt), '2024-06-15 14:30:05')",
1695
+ // timedelta
1696
+ "td = timedelta(1)",
1697
+ "assrt.equal(td.days, 1)",
1698
+ "assrt.equal(td.total_seconds(), 86400)",
1699
+ "assrt.equal(str(td), '1 day, 0:00:00')",
1700
+ ].join("\n"));
1701
+ run_js(js);
1702
+ },
1703
+ },
1704
+
1705
+ {
1706
+ name: "bundle_datetime_arithmetic",
1707
+ description: "datetime stdlib: date/datetime arithmetic via overload_operators",
1708
+ run: function () {
1709
+ var repl = RS.web_repl();
1710
+ var js = bundle_compile(repl, [
1711
+ "from __python__ import overload_operators",
1712
+ "from datetime import date, datetime, timedelta",
1713
+ // date + timedelta
1714
+ "d1 = date(2024, 1, 31)",
1715
+ "d2 = d1 + timedelta(1)",
1716
+ "assrt.equal(d2.month, 2)",
1717
+ "assrt.equal(d2.day, 1)",
1718
+ // date - date
1719
+ "delta = date(2024, 6, 15) - date(2024, 1, 1)",
1720
+ "assrt.ok(delta.days > 0)",
1721
+ // datetime + timedelta
1722
+ "dt1 = datetime(2024, 1, 15, 23, 30, 0)",
1723
+ "dt2 = dt1 + timedelta(0, 3600)",
1724
+ "assrt.equal(dt2.day, 16)",
1725
+ "assrt.equal(dt2.hour, 0)",
1726
+ "assrt.equal(dt2.minute, 30)",
1727
+ // datetime - datetime
1728
+ "diff = datetime(2024, 1, 10, 0, 0) - datetime(2024, 1, 5, 0, 0)",
1729
+ "assrt.equal(diff.days, 5)",
1730
+ // timedelta + timedelta
1731
+ "td = timedelta(1) + timedelta(0, 3600)",
1732
+ "assrt.equal(td.days, 1)",
1733
+ "assrt.equal(td.seconds, 3600)",
1734
+ ].join("\n"));
1735
+ run_js(js);
1736
+ },
1737
+ },
1738
+
1739
+ {
1740
+ name: "bundle_datetime_fromisoformat",
1741
+ description: "datetime stdlib: fromisoformat parses ISO strings correctly",
1742
+ run: function () {
1743
+ var repl = RS.web_repl();
1744
+ var js = bundle_compile(repl, [
1745
+ "from datetime import date, datetime",
1746
+ "d = date.fromisoformat('2024-06-15')",
1747
+ "assrt.equal(d.year, 2024)",
1748
+ "assrt.equal(d.month, 6)",
1749
+ "assrt.equal(d.day, 15)",
1750
+ "dt = datetime.fromisoformat('2024-06-15T09:30:45.123456')",
1751
+ "assrt.equal(dt.hour, 9)",
1752
+ "assrt.equal(dt.minute, 30)",
1753
+ "assrt.equal(dt.second, 45)",
1754
+ "assrt.equal(dt.microsecond, 123456)",
1755
+ ].join("\n"));
1756
+ run_js(js);
1757
+ },
1758
+ },
1759
+
1760
+ {
1761
+ name: "bundle_datetime_strftime",
1762
+ description: "datetime stdlib: strftime formats date and datetime correctly",
1763
+ run: function () {
1764
+ var repl = RS.web_repl();
1765
+ var js = bundle_compile(repl, [
1766
+ "from datetime import date, datetime",
1767
+ "d = date(2024, 1, 15)",
1768
+ "assrt.equal(d.strftime('%Y-%m-%d'), '2024-01-15')",
1769
+ "assrt.equal(d.strftime('%B %d, %Y'), 'January 15, 2024')",
1770
+ "assrt.equal(d.strftime('%a'), 'Mon')",
1771
+ "assrt.equal(d.strftime('%%'), '%')",
1772
+ "dt = datetime(2024, 1, 15, 14, 5, 9)",
1773
+ "assrt.equal(dt.strftime('%H:%M:%S'), '14:05:09')",
1774
+ "assrt.equal(dt.strftime('%I:%M %p'), '02:05 PM')",
1775
+ ].join("\n"));
1776
+ run_js(js);
1777
+ },
1778
+ },
1779
+
1780
+ // ── contextlib ────────────────────────────────────────────────────────
1781
+
1782
+ {
1783
+ name: "bundle_contextlib_suppress",
1784
+ description: "contextlib.suppress silences listed exceptions in the web-repl bundle",
1785
+ run: function () {
1786
+ var repl = RS.web_repl();
1787
+ var js = bundle_compile(repl, [
1788
+ "from contextlib import suppress",
1789
+ // matched exception is suppressed
1790
+ "reached = False",
1791
+ "with suppress(ValueError):",
1792
+ " raise ValueError('ignored')",
1793
+ "reached = True",
1794
+ "assrt.equal(reached, True)",
1795
+ // non-matching exception propagates
1796
+ "propagated = False",
1797
+ "try:",
1798
+ " with suppress(KeyError):",
1799
+ " raise ValueError('not suppressed')",
1800
+ "except ValueError:",
1801
+ " propagated = True",
1802
+ "assrt.equal(propagated, True)",
1803
+ // suppress multiple types
1804
+ "hit = False",
1805
+ "with suppress(TypeError, KeyError):",
1806
+ " raise KeyError('one of two')",
1807
+ "hit = True",
1808
+ "assrt.equal(hit, True)",
1809
+ ].join("\n"));
1810
+ run_js(js);
1811
+ },
1812
+ },
1813
+
1814
+ {
1815
+ name: "bundle_contextlib_closing",
1816
+ description: "contextlib.closing calls close() on exit in the web-repl bundle",
1817
+ run: function () {
1818
+ var repl = RS.web_repl();
1819
+ var js = bundle_compile(repl, [
1820
+ "from contextlib import closing",
1821
+ "class _Obj:",
1822
+ " def __init__(self):",
1823
+ " self.closed = False",
1824
+ " def close(self):",
1825
+ " self.closed = True",
1826
+ "obj = _Obj()",
1827
+ "with closing(obj) as c:",
1828
+ " assrt.equal(c, obj)",
1829
+ " assrt.equal(c.closed, False)",
1830
+ "assrt.equal(obj.closed, True)",
1831
+ // close() is called even on exception
1832
+ "obj2 = _Obj()",
1833
+ "try:",
1834
+ " with closing(obj2):",
1835
+ " raise ValueError('test')",
1836
+ "except ValueError:",
1837
+ " pass",
1838
+ "assrt.equal(obj2.closed, True)",
1839
+ ].join("\n"));
1840
+ run_js(js);
1841
+ },
1842
+ },
1843
+
1844
+ // ── json stdlib ──────────────────────────────────────────────────────────
1845
+
1846
+ {
1847
+ name: "bundle_json_dumps_loads_basic",
1848
+ description: "json stdlib: dumps/loads round-trip for basic types and collections",
1849
+ run: function () {
1850
+ var repl = RS.web_repl();
1851
+ var js = bundle_compile(repl, [
1852
+ "from json import dumps, loads",
1853
+ // basic scalars
1854
+ "assrt.equal(dumps(None), 'null')",
1855
+ "assrt.equal(dumps(True), 'true')",
1856
+ "assrt.equal(dumps(False), 'false')",
1857
+ "assrt.equal(dumps(42), '42')",
1858
+ "assrt.equal(dumps('hello'), '\"hello\"')",
1859
+ // list round-trip
1860
+ "assrt.deepEqual(loads(dumps([1, 2, 3])), [1, 2, 3])",
1861
+ // object round-trip
1862
+ "obj = loads(dumps({'a': 1, 'b': 2}))",
1863
+ "assrt.equal(obj.a, 1)",
1864
+ "assrt.equal(obj.b, 2)",
1865
+ ].join("\n"));
1866
+ run_js(js);
1867
+ },
1868
+ },
1869
+
1870
+ {
1871
+ name: "bundle_json_dumps_options",
1872
+ description: "json stdlib: dumps respects sort_keys, indent, and separators",
1873
+ run: function () {
1874
+ var repl = RS.web_repl();
1875
+ var js = bundle_compile(repl, [
1876
+ "from json import dumps",
1877
+ // sort_keys
1878
+ "assrt.equal(dumps({'b': 2, 'a': 1}, sort_keys=True), '{\"a\":1,\"b\":2}')",
1879
+ // indent produces newlines
1880
+ "pretty = dumps([1, 2], indent=2)",
1881
+ "assrt.ok(pretty.indexOf('\\n') >= 0)",
1882
+ // compact separators
1883
+ "assrt.equal(dumps({'a': 1}, sort_keys=True, separators=(',', ':')), '{\"a\":1}')",
1884
+ ].join("\n"));
1885
+ run_js(js);
1886
+ },
1887
+ },
1888
+
1889
+ {
1890
+ name: "bundle_json_loads_hooks",
1891
+ description: "json stdlib: loads supports object_hook and JSONDecodeError",
1892
+ run: function () {
1893
+ var repl = RS.web_repl();
1894
+ var js = bundle_compile(repl, [
1895
+ "from json import loads, JSONDecodeError",
1896
+ // object_hook
1897
+ "hits = []",
1898
+ "def hook(d):",
1899
+ " hits.push(1)",
1900
+ " return d",
1901
+ "loads('{\"x\": 1}', object_hook=hook)",
1902
+ "assrt.equal(hits.length, 1)",
1903
+ // JSONDecodeError on bad JSON
1904
+ "got_err = False",
1905
+ "try:",
1906
+ " loads('{bad json}')",
1907
+ "except JSONDecodeError:",
1908
+ " got_err = True",
1909
+ "assrt.ok(got_err)",
1910
+ ].join("\n"));
1911
+ run_js(js);
1912
+ },
1913
+ },
1914
+
1915
+ {
1916
+ name: "bundle_json_dump_load_file",
1917
+ description: "json stdlib: dump/load work with file-like objects",
1918
+ run: function () {
1919
+ var repl = RS.web_repl();
1920
+ var js = bundle_compile(repl, [
1921
+ "from json import dump, load",
1922
+ "class _SIO:",
1923
+ " def __init__(self): self._buf = ''",
1924
+ " def write(self, s): self._buf += s",
1925
+ " def read(self): return self._buf",
1926
+ "sio = _SIO()",
1927
+ "dump({'key': 'value', 'n': 7}, sio)",
1928
+ "result = load(sio)",
1929
+ "assrt.equal(result.key, 'value')",
1930
+ "assrt.equal(result.n, 7)",
1931
+ ].join("\n"));
1932
+ run_js(js);
1933
+ },
1934
+ },
1935
+
1936
+ {
1937
+ name: "bundle_contextlib_nullcontext",
1938
+ description: "contextlib.nullcontext works as a no-op context manager in the web-repl bundle",
1939
+ run: function () {
1940
+ var repl = RS.web_repl();
1941
+ var js = bundle_compile(repl, [
1942
+ "from contextlib import nullcontext",
1943
+ "with nullcontext() as v:",
1944
+ " assrt.equal(v, None)",
1945
+ "with nullcontext(42) as v:",
1946
+ " assrt.equal(v, 42)",
1947
+ "with nullcontext('hi') as v:",
1948
+ " assrt.equal(v, 'hi')",
1949
+ ].join("\n"));
1950
+ run_js(js);
1951
+ },
1952
+ },
1953
+
1954
+ {
1955
+ name: "bundle_contextlib_contextmanager",
1956
+ description: "contextlib.contextmanager creates generator-based context managers in the web-repl bundle",
1957
+ run: function () {
1958
+ var repl = RS.web_repl();
1959
+ var js = bundle_compile(repl, [
1960
+ "from contextlib import contextmanager",
1961
+ "log = []",
1962
+ "@contextmanager",
1963
+ "def _cm(name):",
1964
+ " log.append('enter:' + name)",
1965
+ " try:",
1966
+ " yield name.upper()",
1967
+ " finally:",
1968
+ " log.append('exit:' + name)",
1969
+ "with _cm('hello') as v:",
1970
+ " assrt.equal(v, 'HELLO')",
1971
+ " log.append('body')",
1972
+ "assrt.deepEqual(log, ['enter:hello', 'body', 'exit:hello'])",
1973
+ // exception propagates through finally
1974
+ "log2 = []",
1975
+ "@contextmanager",
1976
+ "def _cm2():",
1977
+ " try:",
1978
+ " yield",
1979
+ " finally:",
1980
+ " log2.append('cleanup')",
1981
+ "caught = False",
1982
+ "try:",
1983
+ " with _cm2():",
1984
+ " raise ValueError('oops')",
1985
+ "except ValueError:",
1986
+ " caught = True",
1987
+ "assrt.equal(caught, True)",
1988
+ "assrt.deepEqual(log2, ['cleanup'])",
1989
+ // generator can suppress exceptions
1990
+ "@contextmanager",
1991
+ "def _cm3():",
1992
+ " try:",
1993
+ " yield",
1994
+ " except ValueError:",
1995
+ " pass",
1996
+ "after = False",
1997
+ "with _cm3():",
1998
+ " raise ValueError('suppressed')",
1999
+ "after = True",
2000
+ "assrt.equal(after, True)",
2001
+ ].join("\n"));
2002
+ run_js(js);
2003
+ },
2004
+ },
2005
+
2006
+ {
2007
+ name: "bundle_contextlib_exitstack",
2008
+ description: "contextlib.ExitStack enters/exits context managers in LIFO order in the web-repl bundle",
2009
+ run: function () {
2010
+ var repl = RS.web_repl();
2011
+ var js = bundle_compile(repl, [
2012
+ "from contextlib import ExitStack",
2013
+ "exit_order = []",
2014
+ "class _CM:",
2015
+ " def __init__(self, label):",
2016
+ " self.label = label",
2017
+ " def __enter__(self):",
2018
+ " return self.label",
2019
+ " def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):",
2020
+ " exit_order.append(self.label)",
2021
+ " return False",
2022
+ "with ExitStack() as stack:",
2023
+ " a = stack.enter_context(_CM('a'))",
2024
+ " b = stack.enter_context(_CM('b'))",
2025
+ " c = stack.enter_context(_CM('c'))",
2026
+ " assrt.equal(a, 'a')",
2027
+ " assrt.equal(b, 'b')",
2028
+ " assrt.equal(c, 'c')",
2029
+ "assrt.deepEqual(exit_order, ['c', 'b', 'a'])",
2030
+ // callback
2031
+ "cb_log = []",
2032
+ "def _append_done():",
2033
+ " cb_log.append('done')",
2034
+ "with ExitStack() as stack:",
2035
+ " stack.callback(_append_done)",
2036
+ "assrt.deepEqual(cb_log, ['done'])",
2037
+ // close() outside with
2038
+ "close_log = []",
2039
+ "class _CM2:",
2040
+ " def __enter__(self): return self",
2041
+ " def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):",
2042
+ " close_log.append('closed')",
2043
+ " return False",
2044
+ "s2 = ExitStack()",
2045
+ "s2.enter_context(_CM2())",
2046
+ "s2.close()",
2047
+ "assrt.deepEqual(close_log, ['closed'])",
2048
+ ].join("\n"));
2049
+ run_js(js);
2050
+ },
2051
+ },
2052
+
2053
+ {
2054
+ name: "bundle_io_stringio_basic",
2055
+ description: "io.StringIO: write, seek, read, getvalue work in the web-repl bundle",
2056
+ run: function () {
2057
+ var repl = RS.web_repl();
2058
+ var js = bundle_compile(repl, [
2059
+ "from io import StringIO",
2060
+ // basic write + seek + read
2061
+ "sio = StringIO()",
2062
+ "sio.write('hello')",
2063
+ "sio.write(' world')",
2064
+ "sio.seek(0)",
2065
+ "assrt.equal(sio.read(), 'hello world')",
2066
+ // getvalue independent of position
2067
+ "sio.seek(3)",
2068
+ "assrt.equal(sio.getvalue(), 'hello world')",
2069
+ // tell / seek with whence
2070
+ "sio.seek(0)",
2071
+ "assrt.equal(sio.tell(), 0)",
2072
+ "sio.seek(0, 2)",
2073
+ "assrt.equal(sio.tell(), 11)",
2074
+ // readline
2075
+ "ml = StringIO('line1\\nline2\\nline3')",
2076
+ "assrt.equal(ml.readline(), 'line1\\n')",
2077
+ "assrt.equal(ml.readline(), 'line2\\n')",
2078
+ "assrt.equal(ml.readline(), 'line3')",
2079
+ "assrt.equal(ml.readline(), '')",
2080
+ // truncate
2081
+ "tr = StringIO('hello world')",
2082
+ "tr.truncate(5)",
2083
+ "assrt.equal(tr.getvalue(), 'hello')",
2084
+ ].join("\n"));
2085
+ run_js(js);
2086
+ },
2087
+ },
2088
+
2089
+ {
2090
+ name: "bundle_io_stringio_context",
2091
+ description: "io.StringIO: context manager and closed attribute work in the web-repl bundle",
2092
+ run: function () {
2093
+ var repl = RS.web_repl();
2094
+ var js = bundle_compile(repl, [
2095
+ "from io import StringIO",
2096
+ // context manager
2097
+ "result = ''",
2098
+ "cm = StringIO('context text')",
2099
+ "with cm as f:",
2100
+ " result = f.read()",
2101
+ "assrt.equal(result, 'context text')",
2102
+ "assrt.equal(cm.closed, True)",
2103
+ // ValueError on read after close
2104
+ "got_err = False",
2105
+ "try:",
2106
+ " cm.read()",
2107
+ "except ValueError:",
2108
+ " got_err = True",
2109
+ "assrt.ok(got_err)",
2110
+ // readable / writable / seekable
2111
+ "s2 = StringIO()",
2112
+ "assrt.ok(s2.readable())",
2113
+ "assrt.ok(s2.writable())",
2114
+ "assrt.ok(s2.seekable())",
2115
+ // init with value
2116
+ "s3 = StringIO('preset')",
2117
+ "assrt.equal(s3.read(), 'preset')",
2118
+ ].join("\n"));
2119
+ run_js(js);
2120
+ },
2121
+ },
2122
+
2123
+ {
2124
+ name: "bundle_io_bytesio_basic",
2125
+ description: "io.BytesIO: write, seek, read, getvalue work in the web-repl bundle",
2126
+ run: function () {
2127
+ var repl = RS.web_repl();
2128
+ var js = bundle_compile(repl, [
2129
+ "from io import BytesIO",
2130
+ // basic write + seek + read
2131
+ "bio = BytesIO()",
2132
+ "bio.write(bytes([1, 2, 3]))",
2133
+ "bio.write(bytes([4, 5]))",
2134
+ "bio.seek(0)",
2135
+ "data = bio.read()",
2136
+ "assrt.equal(len(data), 5)",
2137
+ "assrt.equal(data[0], 1)",
2138
+ "assrt.equal(data[4], 5)",
2139
+ // getvalue
2140
+ "bio.seek(2)",
2141
+ "assrt.equal(len(bio.getvalue()), 5)",
2142
+ // partial read
2143
+ "bio.seek(0)",
2144
+ "chunk = bio.read(3)",
2145
+ "assrt.equal(len(chunk), 3)",
2146
+ "assrt.equal(chunk[2], 3)",
2147
+ // init from bytes
2148
+ "bio2 = BytesIO(bytes([10, 20, 30]))",
2149
+ "bio2.seek(0)",
2150
+ "assrt.equal(bio2.read()[1], 20)",
2151
+ // seek whence=2
2152
+ "bio2.seek(0)",
2153
+ "bio2.seek(-1, 2)",
2154
+ "assrt.equal(bio2.tell(), 2)",
2155
+ // truncate
2156
+ "bt = BytesIO(bytes([1, 2, 3, 4, 5]))",
2157
+ "bt.truncate(3)",
2158
+ "assrt.equal(len(bt.getvalue()), 3)",
2159
+ ].join("\n"));
2160
+ run_js(js);
2161
+ },
2162
+ },
2163
+
2164
+ {
2165
+ name: "bundle_io_bytesio_context",
2166
+ description: "io.BytesIO: context manager, readline, and writelines in the web-repl bundle",
2167
+ run: function () {
2168
+ var repl = RS.web_repl();
2169
+ var js = bundle_compile(repl, [
2170
+ "from io import BytesIO",
2171
+ // context manager
2172
+ "bcm = BytesIO(bytes([7, 8, 9]))",
2173
+ "with bcm as bf:",
2174
+ " bf.seek(0)",
2175
+ " got = bf.read()",
2176
+ "assrt.equal(got[0], 7)",
2177
+ "assrt.equal(bcm.closed, True)",
2178
+ // ValueError on closed
2179
+ "berr = False",
2180
+ "try:",
2181
+ " bcm.read()",
2182
+ "except ValueError:",
2183
+ " berr = True",
2184
+ "assrt.ok(berr)",
2185
+ // writelines
2186
+ "bwl = BytesIO()",
2187
+ "bwl.writelines([bytes([1, 2]), bytes([3, 4])])",
2188
+ "assrt.equal(len(bwl.getvalue()), 4)",
2189
+ // readline
2190
+ "brl = BytesIO(bytes([65, 66, 10, 67, 68]))",
2191
+ "first = brl.readline()",
2192
+ "assrt.equal(len(first), 3)",
2193
+ "assrt.equal(first[2], 10)",
2194
+ "second = brl.readline()",
2195
+ "assrt.equal(len(second), 2)",
2196
+ ].join("\n"));
2197
+ run_js(js);
2198
+ },
2199
+ },
2200
+
1668
2201
  {
1669
2202
  name: "repl_exists_persistence",
1670
2203
  description: "ρσ_exists accessible after baselib init — existential operator on non-SymbolRef in web-repl context",