rapydscript-ns 0.8.3 → 0.9.0

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 (72) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1351 -141
  3. package/TODO.md +12 -6
  4. package/language-service/index.js +184 -26
  5. package/package.json +1 -1
  6. package/release/baselib-plain-pretty.js +5895 -1928
  7. package/release/baselib-plain-ugly.js +140 -3
  8. package/release/compiler.js +16282 -5408
  9. package/release/signatures.json +25 -22
  10. package/src/ast.pyj +94 -1
  11. package/src/baselib-builtins.pyj +362 -3
  12. package/src/baselib-bytes.pyj +664 -0
  13. package/src/baselib-containers.pyj +99 -0
  14. package/src/baselib-errors.pyj +45 -1
  15. package/src/baselib-internal.pyj +346 -49
  16. package/src/baselib-itertools.pyj +17 -4
  17. package/src/baselib-str.pyj +46 -4
  18. package/src/lib/abc.pyj +317 -0
  19. package/src/lib/copy.pyj +120 -0
  20. package/src/lib/dataclasses.pyj +532 -0
  21. package/src/lib/enum.pyj +125 -0
  22. package/src/lib/pythonize.pyj +1 -1
  23. package/src/lib/re.pyj +35 -1
  24. package/src/lib/react.pyj +74 -0
  25. package/src/lib/typing.pyj +577 -0
  26. package/src/monaco-language-service/builtins.js +19 -4
  27. package/src/monaco-language-service/diagnostics.js +40 -19
  28. package/src/output/classes.pyj +161 -25
  29. package/src/output/codegen.pyj +16 -2
  30. package/src/output/exceptions.pyj +97 -1
  31. package/src/output/functions.pyj +87 -5
  32. package/src/output/jsx.pyj +164 -0
  33. package/src/output/literals.pyj +28 -2
  34. package/src/output/loops.pyj +5 -2
  35. package/src/output/modules.pyj +1 -1
  36. package/src/output/operators.pyj +108 -36
  37. package/src/output/statements.pyj +2 -2
  38. package/src/output/stream.pyj +1 -0
  39. package/src/parse.pyj +496 -128
  40. package/src/tokenizer.pyj +38 -4
  41. package/test/abc.pyj +291 -0
  42. package/test/arithmetic_nostrict.pyj +88 -0
  43. package/test/arithmetic_types.pyj +169 -0
  44. package/test/baselib.pyj +91 -0
  45. package/test/bytes.pyj +467 -0
  46. package/test/classes.pyj +1 -0
  47. package/test/comparison_ops.pyj +173 -0
  48. package/test/dataclasses.pyj +253 -0
  49. package/test/enum.pyj +134 -0
  50. package/test/eval_exec.pyj +56 -0
  51. package/test/format.pyj +148 -0
  52. package/test/object.pyj +64 -0
  53. package/test/python_compat.pyj +17 -15
  54. package/test/python_features.pyj +89 -21
  55. package/test/regexp.pyj +29 -1
  56. package/test/tuples.pyj +96 -0
  57. package/test/typing.pyj +469 -0
  58. package/test/unit/index.js +2292 -70
  59. package/test/unit/language-service.js +674 -4
  60. package/test/unit/web-repl.js +1106 -0
  61. package/test/vars_locals_globals.pyj +94 -0
  62. package/tools/cli.js +11 -0
  63. package/tools/compile.js +5 -0
  64. package/tools/embedded_compiler.js +15 -4
  65. package/tools/lint.js +16 -19
  66. package/tools/repl.js +1 -1
  67. package/web-repl/env.js +122 -0
  68. package/web-repl/main.js +1 -3
  69. package/web-repl/rapydscript.js +125 -3
  70. package/PYTHON_DIFFERENCES_REPORT.md +0 -291
  71. package/PYTHON_FEATURE_COVERAGE.md +0 -200
  72. package/hack_demo.pyj +0 -112
@@ -0,0 +1,469 @@
1
+ # globals: assrt
2
+ # Tests for the typing standard library module.
3
+ # Verifies that typing constructs transpile correctly to JavaScript and
4
+ # that the resulting runtime objects carry the expected attributes.
5
+
6
+ from typing import (
7
+ TYPE_CHECKING, Any, Union, Optional, ClassVar, Final, Literal, NoReturn,
8
+ List, Dict, Set, FrozenSet, Tuple, Type, Callable,
9
+ Iterator, Iterable, Generator, Sequence, MutableSequence,
10
+ Mapping, MutableMapping, AsyncGenerator, AsyncIterator, AsyncIterable,
11
+ Awaitable, Coroutine, IO, TextIO, BinaryIO, Pattern, Match,
12
+ TypeVar, Generic, Protocol,
13
+ cast, overload, no_type_check, no_type_check_decorator,
14
+ runtime_checkable, get_type_hints,
15
+ TypedDict, NamedTuple, AnyStr, ByteString, Text
16
+ )
17
+
18
+
19
+ # ── TYPE_CHECKING constant ─────────────────────────────────────────────────────
20
+
21
+ assrt.equal(TYPE_CHECKING, False)
22
+
23
+
24
+ # ── Generic aliases: __origin__ and __args__ ──────────────────────────────────
25
+
26
+ def _test_list_alias():
27
+ alias = List[int]
28
+ assrt.ok(alias is not None)
29
+ assrt.equal(alias.__origin__, list)
30
+ assrt.equal(alias.__args__[0], int)
31
+ assrt.equal(alias._name, 'List')
32
+ _test_list_alias()
33
+
34
+
35
+ def _test_dict_alias():
36
+ alias = Dict[str, int]
37
+ assrt.equal(alias.__origin__, dict)
38
+ assrt.equal(alias.__args__[0], str)
39
+ assrt.equal(alias.__args__[1], int)
40
+ assrt.equal(alias._name, 'Dict')
41
+ _test_dict_alias()
42
+
43
+
44
+ def _test_set_alias():
45
+ alias = Set[str]
46
+ assrt.equal(alias.__origin__, set)
47
+ assrt.equal(alias.__args__[0], str)
48
+ _test_set_alias()
49
+
50
+
51
+ def _test_frozenset_alias():
52
+ alias = FrozenSet[int]
53
+ assrt.equal(alias.__origin__, frozenset)
54
+ assrt.equal(alias.__args__[0], int)
55
+ _test_frozenset_alias()
56
+
57
+
58
+ def _test_tuple_alias():
59
+ # Homogeneous variable-length tuple: Tuple[int, ...]
60
+ alias = Tuple[int, ...]
61
+ assrt.equal(alias.__origin__, tuple)
62
+ assrt.equal(alias.__args__[0], int)
63
+ assrt.equal(alias._name, 'Tuple')
64
+ _test_tuple_alias()
65
+
66
+
67
+ def _test_type_alias():
68
+ alias = Type[int]
69
+ assrt.equal(alias.__origin__, type)
70
+ assrt.equal(alias.__args__[0], int)
71
+ _test_type_alias()
72
+
73
+
74
+ def _test_callable_alias():
75
+ alias = Callable[[int, str], bool]
76
+ assrt.equal(alias._name, 'Callable')
77
+ assrt.ok(alias.__args__ is not None)
78
+ _test_callable_alias()
79
+
80
+
81
+ # ── Abstract aliases ───────────────────────────────────────────────────────────
82
+
83
+ def _test_abstract_aliases():
84
+ assrt.equal(Iterator[int]._name, 'Iterator')
85
+ assrt.equal(Iterable[str]._name, 'Iterable')
86
+ assrt.equal(Generator[int, None, None]._name, 'Generator')
87
+ assrt.equal(Sequence[float]._name, 'Sequence')
88
+ assrt.equal(MutableSequence[float]._name, 'MutableSequence')
89
+ assrt.equal(Mapping[str, int]._name, 'Mapping')
90
+ assrt.equal(MutableMapping[str, int]._name, 'MutableMapping')
91
+ assrt.equal(Awaitable[int]._name, 'Awaitable')
92
+ assrt.equal(Coroutine[int, None, None]._name, 'Coroutine')
93
+ assrt.equal(AsyncGenerator[int, None]._name, 'AsyncGenerator')
94
+ assrt.equal(AsyncIterator[int]._name, 'AsyncIterator')
95
+ assrt.equal(AsyncIterable[int]._name, 'AsyncIterable')
96
+ _test_abstract_aliases()
97
+
98
+
99
+ # ── IO and pattern aliases ─────────────────────────────────────────────────────
100
+
101
+ def _test_io_aliases():
102
+ assrt.equal(IO[str]._name, 'IO')
103
+ assrt.ok(TextIO is not None)
104
+ assrt.ok(BinaryIO is not None)
105
+ assrt.equal(Pattern[str]._name, 'Pattern')
106
+ assrt.equal(Match[str]._name, 'Match')
107
+ _test_io_aliases()
108
+
109
+
110
+ # ── Special forms ──────────────────────────────────────────────────────────────
111
+
112
+ def _test_optional():
113
+ alias = Optional[str]
114
+ assrt.equal(alias._name, 'Optional')
115
+ assrt.equal(alias.__args__[0], str)
116
+ assrt.equal(alias.__args__[1], None)
117
+ _test_optional()
118
+
119
+
120
+ def _test_union():
121
+ alias = Union[str, int]
122
+ assrt.equal(alias._name, 'Union')
123
+ assrt.equal(alias.__args__.length, 2)
124
+ assrt.equal(alias.__args__[0], str)
125
+ assrt.equal(alias.__args__[1], int)
126
+ _test_union()
127
+
128
+
129
+ def _test_classvar():
130
+ alias = ClassVar[str]
131
+ assrt.equal(alias._name, 'ClassVar')
132
+ assrt.equal(alias.__args__[0], str)
133
+ _test_classvar()
134
+
135
+
136
+ def _test_final():
137
+ alias = Final[int]
138
+ assrt.equal(alias._name, 'Final')
139
+ assrt.equal(alias.__args__[0], int)
140
+ _test_final()
141
+
142
+
143
+ def _test_literal():
144
+ alias = Literal['r', 'w', 'a']
145
+ assrt.equal(alias._name, 'Literal')
146
+ assrt.equal(alias.__args__.length, 3)
147
+ assrt.equal(alias.__args__[0], 'r')
148
+ assrt.equal(alias.__args__[1], 'w')
149
+ assrt.equal(alias.__args__[2], 'a')
150
+ _test_literal()
151
+
152
+
153
+ def _test_any():
154
+ assrt.ok(Any is not None)
155
+ assrt.ok(repr(Any).indexOf('Any') >= 0)
156
+ _test_any()
157
+
158
+
159
+ def _test_noreturn():
160
+ assrt.ok(NoReturn is not None)
161
+ _test_noreturn()
162
+
163
+
164
+ # ── TypeVar ────────────────────────────────────────────────────────────────────
165
+
166
+ def _test_typevar():
167
+ T = TypeVar('T')
168
+ assrt.equal(T.__name__, 'T')
169
+ assrt.ok(repr(T).indexOf('T') >= 0)
170
+
171
+ S = TypeVar('S', str, int)
172
+ assrt.equal(S.__name__, 'S')
173
+ assrt.equal(S.__constraints__.length, 2)
174
+ assrt.equal(S.__constraints__[0], str)
175
+ assrt.equal(S.__constraints__[1], int)
176
+
177
+ assrt.equal(AnyStr.__name__, 'AnyStr')
178
+ # AnyStr is constrained to both str and bytes now that bytes is supported
179
+ assrt.equal(AnyStr.__constraints__.length, 2)
180
+ assrt.equal(AnyStr.__constraints__[0], str)
181
+ assrt.equal(AnyStr.__constraints__[1], bytes)
182
+ _test_typevar()
183
+
184
+
185
+ # ── Generic base class ─────────────────────────────────────────────────────────
186
+
187
+ def _test_generic():
188
+ T = TypeVar('T')
189
+
190
+ class Stack(Generic[T]):
191
+ def __init__(self):
192
+ self._items = []
193
+ def push(self, item):
194
+ self._items.append(item)
195
+ def pop(self):
196
+ return self._items.pop()
197
+ def empty(self):
198
+ return len(self._items) == 0
199
+
200
+ s = Stack()
201
+ s.push(1)
202
+ s.push(2)
203
+ assrt.equal(s.pop(), 2)
204
+ assrt.equal(s.pop(), 1)
205
+ assrt.ok(s.empty())
206
+
207
+ # __class_getitem__ on Generic subclass
208
+ alias = Stack[int]
209
+ assrt.ok(alias is not None)
210
+ _test_generic()
211
+
212
+
213
+ # ── Protocol base class ────────────────────────────────────────────────────────
214
+
215
+ def _test_protocol():
216
+ @runtime_checkable
217
+ class Drawable(Protocol):
218
+ def draw(self):
219
+ pass
220
+
221
+ class Circle:
222
+ def draw(self):
223
+ return 'circle'
224
+
225
+ c = Circle()
226
+ assrt.equal(c.draw(), 'circle')
227
+ assrt.ok(Drawable is not None)
228
+ _test_protocol()
229
+
230
+
231
+ # ── cast ───────────────────────────────────────────────────────────────────────
232
+
233
+ def _test_cast():
234
+ result = cast(int, 'hello')
235
+ assrt.equal(result, 'hello')
236
+ assrt.deepEqual(cast(List[int], [1, 2, 3]), [1, 2, 3])
237
+ assrt.equal(cast(str, 42), 42)
238
+ _test_cast()
239
+
240
+
241
+ # ── overload decorator ─────────────────────────────────────────────────────────
242
+
243
+ def _test_overload():
244
+ @overload
245
+ def process(x):
246
+ return x * 2
247
+
248
+ assrt.equal(process(5), 10)
249
+ _test_overload()
250
+
251
+
252
+ # ── no_type_check decorator ────────────────────────────────────────────────────
253
+
254
+ def _test_no_type_check():
255
+ @no_type_check
256
+ def f(x):
257
+ return x + 1
258
+
259
+ assrt.equal(f(3), 4)
260
+ _test_no_type_check()
261
+
262
+
263
+ # ── get_type_hints ─────────────────────────────────────────────────────────────
264
+
265
+ def _test_get_type_hints():
266
+ def annotated(x: int, y: str) -> bool:
267
+ pass
268
+
269
+ hints = get_type_hints(annotated)
270
+ assrt.equal(hints['x'], int)
271
+ assrt.equal(hints['y'], str)
272
+ assrt.equal(hints['return'], bool)
273
+
274
+ def no_hints():
275
+ pass
276
+
277
+ assrt.deepEqual(get_type_hints(no_hints), {})
278
+ _test_get_type_hints()
279
+
280
+
281
+ # ── Function annotations with typing types ─────────────────────────────────────
282
+
283
+ def _test_annotations_with_typing():
284
+ def process(items: List[int], label: Optional[str]) -> Dict[str, int]:
285
+ pass
286
+
287
+ annot = process.__annotations__
288
+ assrt.ok(annot is not None)
289
+ assrt.equal(annot['items'].__origin__, list)
290
+ assrt.equal(annot['items'].__args__[0], int)
291
+ assrt.equal(annot['label']._name, 'Optional')
292
+ assrt.equal(annot['return'].__origin__, dict)
293
+ _test_annotations_with_typing()
294
+
295
+
296
+ # ── TypedDict ──────────────────────────────────────────────────────────────────
297
+
298
+ def _test_typeddict():
299
+ class Movie(TypedDict):
300
+ pass
301
+
302
+ # TypedDict subclass is a valid class that can be instantiated
303
+ m = Movie()
304
+ assrt.ok(m is not None)
305
+ # TypedDict itself is importable
306
+ assrt.ok(TypedDict is not None)
307
+ _test_typeddict()
308
+
309
+
310
+ # ── NamedTuple (functional form) ───────────────────────────────────────────────
311
+
312
+ def _test_namedtuple():
313
+ from __python__ import overload_getitem
314
+ Point = NamedTuple('Point', [('x', float), ('y', float)])
315
+
316
+ p = Point(3.0, 4.0)
317
+ assrt.equal(p.x, 3.0)
318
+ assrt.equal(p.y, 4.0)
319
+
320
+ # Annotations carry type information
321
+ assrt.equal(Point.__annotations__['x'], float)
322
+ assrt.equal(Point.__annotations__['y'], float)
323
+
324
+ # Integer indexing
325
+ assrt.equal(p[0], 3.0)
326
+ assrt.equal(p[1], 4.0)
327
+
328
+ # Negative indexing
329
+ assrt.equal(p[-1], 4.0)
330
+ _test_namedtuple()
331
+
332
+
333
+ # ── ByteString ─────────────────────────────────────────────────────────────────
334
+
335
+ def _test_bytestring():
336
+ from __python__ import overload_operators
337
+ # ByteString is importable and is a class
338
+ assrt.ok(ByteString is not None)
339
+
340
+ # Use ByteString as a type annotation — it is a no-op at runtime
341
+ def consume(data: ByteString) -> int:
342
+ return len(data)
343
+
344
+ assrt.equal(consume(bytes([1, 2, 3])), 3)
345
+ assrt.equal(consume(bytearray([10, 20])), 2)
346
+
347
+ # Optional[ByteString] works via _GenericAlias
348
+ from typing import Optional
349
+ alias = Optional[ByteString]
350
+ assrt.equal(alias._name, 'Optional')
351
+ assrt.equal(alias.__args__[0], ByteString)
352
+
353
+ # Union[bytes, bytearray] round-trip
354
+ from typing import Union
355
+ u = Union[bytes, bytearray]
356
+ assrt.equal(u._name, 'Union')
357
+ assrt.equal(u.__args__[0], bytes)
358
+ assrt.equal(u.__args__[1], bytearray)
359
+ _test_bytestring()
360
+
361
+
362
+ # ── bytes / bytearray in generic aliases ───────────────────────────────────────
363
+
364
+ def _test_bytes_in_generic_aliases():
365
+ from __python__ import overload_operators
366
+ # List[bytes]
367
+ alias = List[bytes]
368
+ assrt.equal(alias.__origin__, list)
369
+ assrt.equal(alias.__args__[0], bytes)
370
+
371
+ # Dict[str, bytes]
372
+ alias = Dict[str, bytes]
373
+ assrt.equal(alias.__args__[0], str)
374
+ assrt.equal(alias.__args__[1], bytes)
375
+
376
+ # Optional[bytes]
377
+ from typing import Optional
378
+ alias = Optional[bytes]
379
+ assrt.equal(alias._name, 'Optional')
380
+ assrt.equal(alias.__args__[0], bytes)
381
+
382
+ # IO[bytes] — used to annotate binary-mode streams
383
+ alias = IO[bytes]
384
+ assrt.equal(alias._name, 'IO')
385
+ assrt.equal(alias.__args__[0], bytes)
386
+ _test_bytes_in_generic_aliases()
387
+
388
+
389
+ # ── Text alias ─────────────────────────────────────────────────────────────────
390
+
391
+ def _test_text_alias():
392
+ assrt.equal(Text, str)
393
+ _test_text_alias()
394
+
395
+
396
+ # ── repr smoke test ────────────────────────────────────────────────────────────
397
+
398
+ def _test_repr():
399
+ assrt.ok(repr(List[int]).indexOf('List') >= 0)
400
+ assrt.ok(repr(Dict[str, int]).indexOf('Dict') >= 0)
401
+ assrt.ok(repr(Optional[str]).indexOf('Optional') >= 0)
402
+ assrt.ok(repr(Union[str, int]).indexOf('Union') >= 0)
403
+ _test_repr()
404
+
405
+
406
+ # ── Annotated assignment with attribute target (self.x: Type = value) ──────────
407
+ # Regression: these were previously mis-parsed, causing "invalid left-hand side"
408
+ # in the generated JS output.
409
+
410
+ def _test_attr_annotated_assign():
411
+ T = TypeVar('T')
412
+
413
+ class Stack(Generic[T]):
414
+ def __init__(self):
415
+ self._items: List[T] = []
416
+
417
+ def push(self, item: T) -> None:
418
+ self._items.append(item)
419
+
420
+ def pop(self) -> Optional[T]:
421
+ return self._items.pop() if self._items else None
422
+
423
+ s = Stack()
424
+ s.push(10)
425
+ s.push(20)
426
+ assrt.equal(s.pop(), 20)
427
+ assrt.equal(s.pop(), 10)
428
+ # _items list was assigned correctly (not left as undefined)
429
+ assrt.equal(s._items.length, 0)
430
+ _test_attr_annotated_assign()
431
+
432
+
433
+ def _test_attr_annotated_assign_no_value():
434
+ # Annotation-only on an attribute (no rhs) should compile without error
435
+ # and emit nothing (attribute remains unset).
436
+ class Container:
437
+ def __init__(self):
438
+ self.x: int # annotation only — no assignment
439
+ self.y: str = 'hello'
440
+
441
+ c = Container()
442
+ assrt.equal(c.x, undefined)
443
+ assrt.equal(c.y, 'hello')
444
+ _test_attr_annotated_assign_no_value()
445
+
446
+
447
+ def _test_local_annotated_assign_complex_type():
448
+ # Local variable with a parameterised type annotation — the type is erased,
449
+ # only the assignment runs.
450
+ def make_pair() -> List[int]:
451
+ pair: List[int] = [1, 2]
452
+ return pair
453
+
454
+ result = make_pair()
455
+ assrt.equal(result.length, 2)
456
+ assrt.equal(result[0], 1)
457
+ assrt.equal(result[1], 2)
458
+ _test_local_annotated_assign_complex_type()
459
+
460
+
461
+ def _test_module_level_attr_annotated_assign():
462
+ # Annotated assignment on a plain object attribute at module level.
463
+ class Box:
464
+ pass
465
+
466
+ b = Box()
467
+ b.value: int = 42
468
+ assrt.equal(b.value, 42)
469
+ _test_module_level_attr_annotated_assign()