rapydscript-ns 0.8.4 → 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 (132) 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 +18 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/README.md +715 -169
  8. package/TODO.md +9 -2
  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 +36 -27
  15. package/package.json +1 -1
  16. package/publish.py +37 -37
  17. package/release/baselib-plain-pretty.js +2358 -168
  18. package/release/baselib-plain-ugly.js +73 -3
  19. package/release/compiler.js +6282 -3092
  20. package/release/signatures.json +31 -30
  21. package/session.vim +4 -4
  22. package/setup.cfg +2 -2
  23. package/src/ast.pyj +1 -0
  24. package/src/baselib-builtins.pyj +340 -2
  25. package/src/baselib-bytes.pyj +664 -0
  26. package/src/baselib-errors.pyj +1 -1
  27. package/src/baselib-internal.pyj +267 -60
  28. package/src/baselib-itertools.pyj +110 -97
  29. package/src/baselib-str.pyj +22 -4
  30. package/src/compiler.pyj +36 -36
  31. package/src/errors.pyj +30 -30
  32. package/src/lib/abc.pyj +317 -0
  33. package/src/lib/aes.pyj +646 -646
  34. package/src/lib/copy.pyj +120 -120
  35. package/src/lib/dataclasses.pyj +532 -0
  36. package/src/lib/elementmaker.pyj +83 -83
  37. package/src/lib/encodings.pyj +126 -126
  38. package/src/lib/enum.pyj +125 -0
  39. package/src/lib/gettext.pyj +569 -569
  40. package/src/lib/itertools.pyj +580 -580
  41. package/src/lib/math.pyj +193 -193
  42. package/src/lib/operator.pyj +11 -11
  43. package/src/lib/pythonize.pyj +20 -20
  44. package/src/lib/random.pyj +118 -118
  45. package/src/lib/re.pyj +504 -470
  46. package/src/lib/react.pyj +74 -74
  47. package/src/lib/traceback.pyj +63 -63
  48. package/src/lib/typing.pyj +577 -0
  49. package/src/lib/uuid.pyj +77 -77
  50. package/src/monaco-language-service/builtins.js +14 -4
  51. package/src/monaco-language-service/diagnostics.js +19 -20
  52. package/src/monaco-language-service/dts.js +550 -550
  53. package/src/output/classes.pyj +62 -26
  54. package/src/output/comments.pyj +45 -45
  55. package/src/output/exceptions.pyj +201 -201
  56. package/src/output/functions.pyj +78 -5
  57. package/src/output/jsx.pyj +164 -164
  58. package/src/output/loops.pyj +5 -2
  59. package/src/output/operators.pyj +100 -34
  60. package/src/output/treeshake.pyj +182 -182
  61. package/src/output/utils.pyj +72 -72
  62. package/src/parse.pyj +80 -16
  63. package/src/string_interpolation.pyj +72 -72
  64. package/src/tokenizer.pyj +9 -4
  65. package/src/unicode_aliases.pyj +576 -576
  66. package/src/utils.pyj +192 -192
  67. package/test/_import_one.pyj +37 -37
  68. package/test/_import_two/__init__.pyj +11 -11
  69. package/test/_import_two/level2/deep.pyj +4 -4
  70. package/test/_import_two/other.pyj +6 -6
  71. package/test/_import_two/sub.pyj +13 -13
  72. package/test/abc.pyj +291 -0
  73. package/test/aes_vectors.pyj +421 -421
  74. package/test/annotations.pyj +80 -80
  75. package/test/arithmetic_nostrict.pyj +88 -0
  76. package/test/arithmetic_types.pyj +169 -0
  77. package/test/baselib.pyj +91 -0
  78. package/test/bytes.pyj +467 -0
  79. package/test/classes.pyj +1 -0
  80. package/test/comparison_ops.pyj +173 -0
  81. package/test/dataclasses.pyj +253 -0
  82. package/test/decorators.pyj +77 -77
  83. package/test/docstrings.pyj +39 -39
  84. package/test/elementmaker_test.pyj +45 -45
  85. package/test/enum.pyj +134 -0
  86. package/test/eval_exec.pyj +56 -0
  87. package/test/format.pyj +148 -0
  88. package/test/functions.pyj +151 -151
  89. package/test/generators.pyj +41 -41
  90. package/test/generic.pyj +370 -370
  91. package/test/imports.pyj +72 -72
  92. package/test/internationalization.pyj +73 -73
  93. package/test/lint.pyj +164 -164
  94. package/test/loops.pyj +85 -85
  95. package/test/numpy.pyj +734 -734
  96. package/test/object.pyj +64 -0
  97. package/test/omit_function_metadata.pyj +20 -20
  98. package/test/python_compat.pyj +17 -15
  99. package/test/python_features.pyj +70 -15
  100. package/test/regexp.pyj +83 -55
  101. package/test/repl.pyj +121 -121
  102. package/test/scoped_flags.pyj +76 -76
  103. package/test/tuples.pyj +96 -0
  104. package/test/typing.pyj +469 -0
  105. package/test/unit/index.js +116 -7
  106. package/test/unit/language-service-dts.js +543 -543
  107. package/test/unit/language-service-hover.js +455 -455
  108. package/test/unit/language-service.js +84 -0
  109. package/test/unit/web-repl.js +804 -1
  110. package/test/vars_locals_globals.pyj +94 -0
  111. package/tools/cli.js +558 -547
  112. package/tools/compile.js +224 -219
  113. package/tools/completer.js +131 -131
  114. package/tools/embedded_compiler.js +262 -251
  115. package/tools/gettext.js +185 -185
  116. package/tools/ini.js +65 -65
  117. package/tools/lint.js +16 -19
  118. package/tools/msgfmt.js +187 -187
  119. package/tools/repl.js +223 -223
  120. package/tools/test.js +118 -118
  121. package/tools/utils.js +128 -128
  122. package/tools/web_repl.js +95 -95
  123. package/try +41 -41
  124. package/web-repl/env.js +196 -196
  125. package/web-repl/index.html +163 -163
  126. package/web-repl/main.js +252 -252
  127. package/web-repl/prism.css +139 -139
  128. package/web-repl/prism.js +113 -113
  129. package/web-repl/rapydscript.js +224 -224
  130. package/web-repl/sha1.js +25 -25
  131. package/PYTHON_DIFFERENCES_REPORT.md +0 -291
  132. package/PYTHON_FEATURE_COVERAGE.md +0 -200
package/test/bytes.pyj ADDED
@@ -0,0 +1,467 @@
1
+ # vim:fileencoding=utf-8
2
+ # globals: assrt
3
+ from __python__ import overload_operators, truthiness
4
+
5
+ ae = assrt.equal
6
+ ade = assrt.deepEqual
7
+ ok = assrt.ok
8
+
9
+ # ---------------------------------------------------------------------------
10
+ # Construction
11
+ # ---------------------------------------------------------------------------
12
+
13
+ # Empty bytes
14
+ b = bytes()
15
+ ae(len(b), 0)
16
+ ok(isinstance(b, bytes))
17
+
18
+ # From integer — n zero bytes
19
+ b = bytes(4)
20
+ ae(len(b), 4)
21
+ ae(b[0], 0)
22
+ ae(b[3], 0)
23
+
24
+ # From list of ints
25
+ b = bytes([72, 101, 108, 108, 111])
26
+ ae(len(b), 5)
27
+ ae(b[0], 72)
28
+ ae(b[4], 111)
29
+
30
+ # From string with encoding
31
+ b = bytes('Hello', 'utf-8')
32
+ ae(len(b), 5)
33
+ ae(b[0], 72) # H
34
+ ae(b[1], 101) # e
35
+
36
+ # From another bytes object (copy)
37
+ b2 = bytes(b)
38
+ ok(b2 == b)
39
+ ok(b2 is not b)
40
+
41
+ # ---------------------------------------------------------------------------
42
+ # bytearray construction
43
+ # ---------------------------------------------------------------------------
44
+
45
+ ba = bytearray()
46
+ ae(len(ba), 0)
47
+ ok(isinstance(ba, bytearray))
48
+
49
+ ba = bytearray(3)
50
+ ae(len(ba), 3)
51
+ ae(ba[0], 0)
52
+
53
+ ba = bytearray([1, 2, 3])
54
+ ae(ba[0], 1)
55
+ ae(ba[2], 3)
56
+
57
+ ba = bytearray('Hi', 'utf-8')
58
+ ae(ba[0], 72) # H
59
+ ae(ba[1], 105) # i
60
+
61
+ # From bytes (copy)
62
+ src = bytes([10, 20, 30])
63
+ ba = bytearray(src)
64
+ ok(ba == src)
65
+ ok(ba is not src)
66
+
67
+ # ---------------------------------------------------------------------------
68
+ # isinstance checks
69
+ # ---------------------------------------------------------------------------
70
+
71
+ ok(isinstance(bytes([1, 2]), bytes))
72
+ ok(isinstance(bytearray([1, 2]), bytearray))
73
+ ok(isinstance(bytearray([1, 2]), bytes)) # bytearray is subclass of bytes
74
+
75
+ # ---------------------------------------------------------------------------
76
+ # Indexing and slicing
77
+ # ---------------------------------------------------------------------------
78
+
79
+ b = bytes([10, 20, 30, 40, 50])
80
+
81
+ # Integer index
82
+ ae(b[0], 10)
83
+ ae(b[-1], 50)
84
+ ae(b[2], 30)
85
+
86
+ # Slice returns bytes
87
+ s = b[1:4]
88
+ ok(isinstance(s, bytes))
89
+ ae(len(s), 3)
90
+ ae(s[0], 20)
91
+ ae(s[2], 40)
92
+
93
+ # Slice with step
94
+ s = b[::2]
95
+ ae(len(s), 3)
96
+ ae(s[0], 10)
97
+ ae(s[1], 30)
98
+ ae(s[2], 50)
99
+
100
+ # Negative slice
101
+ s = b[-2:]
102
+ ae(len(s), 2)
103
+ ae(s[0], 40)
104
+ ae(s[1], 50)
105
+
106
+ # ---------------------------------------------------------------------------
107
+ # bytearray item assignment
108
+ # ---------------------------------------------------------------------------
109
+
110
+ ba = bytearray([1, 2, 3, 4, 5])
111
+ ba[0] = 99
112
+ ae(ba[0], 99)
113
+
114
+ ba[-1] = 88
115
+ ae(ba[4], 88)
116
+
117
+ # Slice assignment via __setitem__
118
+ ba.__setitem__(slice(1, 3), bytes([20, 30]))
119
+ ae(ba[1], 20)
120
+ ae(ba[2], 30)
121
+
122
+ # ---------------------------------------------------------------------------
123
+ # Equality
124
+ # ---------------------------------------------------------------------------
125
+
126
+ ok(bytes([1, 2, 3]) == bytes([1, 2, 3]))
127
+ ok(not (bytes([1, 2, 3]) == bytes([1, 2, 4])))
128
+ ok(bytes([1, 2]) == bytearray([1, 2]))
129
+ ok(bytearray([1, 2]) == bytes([1, 2]))
130
+
131
+ # ---------------------------------------------------------------------------
132
+ # Concatenation and repetition
133
+ # ---------------------------------------------------------------------------
134
+
135
+ b1 = bytes([1, 2])
136
+ b2 = bytes([3, 4])
137
+ b3 = b1 + b2
138
+ ae(len(b3), 4)
139
+ ae(b3[0], 1)
140
+ ae(b3[3], 4)
141
+
142
+ b4 = bytes([7]) * 3
143
+ ae(len(b4), 3)
144
+ ae(b4[0], 7)
145
+ ae(b4[2], 7)
146
+
147
+ ba = bytearray([1, 2])
148
+ ba += bytearray([3, 4])
149
+ ae(len(ba), 4)
150
+ ae(ba[2], 3)
151
+
152
+ # ---------------------------------------------------------------------------
153
+ # Containment
154
+ # ---------------------------------------------------------------------------
155
+
156
+ b = bytes([10, 20, 30, 40])
157
+ ok(20 in b)
158
+ ok(not (99 in b))
159
+ ok(bytes([20, 30]) in b)
160
+ ok(not (bytes([20, 40]) in b))
161
+
162
+ # ---------------------------------------------------------------------------
163
+ # Iteration
164
+ # ---------------------------------------------------------------------------
165
+
166
+ b = bytes([5, 10, 15])
167
+ vals = [x for x in b]
168
+ ade(vals, [5, 10, 15])
169
+
170
+ total = 0
171
+ for byte in bytes([1, 2, 3, 4]):
172
+ total += byte
173
+ ae(total, 10)
174
+
175
+ # ---------------------------------------------------------------------------
176
+ # hex() and fromhex()
177
+ # ---------------------------------------------------------------------------
178
+
179
+ b = bytes([0, 15, 255])
180
+ ae(b.hex(), '000fff')
181
+
182
+ ae(bytes([72, 101, 108, 108, 111]).hex(), '48656c6c6f')
183
+
184
+ b2 = bytes.fromhex('48656c6c6f')
185
+ ok(b2 == bytes([72, 101, 108, 108, 111]))
186
+
187
+ # hex() with separator
188
+ b = bytes([1, 2, 3])
189
+ ae(b.hex(':', 1), '01:02:03')
190
+
191
+ # ---------------------------------------------------------------------------
192
+ # decode()
193
+ # ---------------------------------------------------------------------------
194
+
195
+ b = bytes([72, 101, 108, 108, 111])
196
+ ae(b.decode('utf-8'), 'Hello')
197
+
198
+ b = bytes('café', 'utf-8')
199
+ ae(b.decode('utf-8'), 'café')
200
+
201
+ b = bytes([65, 66, 67])
202
+ ae(b.decode('ascii'), 'ABC')
203
+
204
+ # ---------------------------------------------------------------------------
205
+ # count(), find(), index(), rfind(), rindex()
206
+ # ---------------------------------------------------------------------------
207
+
208
+ b = bytes([1, 2, 1, 2, 1])
209
+ ae(b.count(1), 3)
210
+ ae(b.count(bytes([1, 2])), 2)
211
+
212
+ ae(b.find(1), 0)
213
+ ae(b.find(2), 1)
214
+ ae(b.find(bytes([1, 2])), 0)
215
+ ae(b.find(99), -1)
216
+
217
+ ae(b.index(2), 1)
218
+
219
+ ae(b.rfind(1), 4)
220
+ ae(b.rindex(2), 3)
221
+
222
+ # ---------------------------------------------------------------------------
223
+ # startswith() / endswith()
224
+ # ---------------------------------------------------------------------------
225
+
226
+ b = bytes([1, 2, 3, 4, 5])
227
+ ok(b.startswith(bytes([1, 2])))
228
+ ok(not b.startswith(bytes([2, 3])))
229
+ ok(b.endswith(bytes([4, 5])))
230
+ ok(not b.endswith(bytes([3, 4])))
231
+
232
+ # ---------------------------------------------------------------------------
233
+ # join()
234
+ # ---------------------------------------------------------------------------
235
+
236
+ sep = bytes([0])
237
+ parts = [bytes([1]), bytes([2]), bytes([3])]
238
+ result = sep.join(parts)
239
+ ade(list(result), [1, 0, 2, 0, 3])
240
+
241
+ # Empty separator
242
+ result = bytes().join([bytes([1, 2]), bytes([3, 4])])
243
+ ade(list(result), [1, 2, 3, 4])
244
+
245
+ # ---------------------------------------------------------------------------
246
+ # split()
247
+ # ---------------------------------------------------------------------------
248
+
249
+ b = bytes([1, 0, 2, 0, 3])
250
+ parts = b.split(bytes([0]))
251
+ ae(len(parts), 3)
252
+ ok(parts[0] == bytes([1]))
253
+ ok(parts[1] == bytes([2]))
254
+ ok(parts[2] == bytes([3]))
255
+
256
+ # Split with maxsplit
257
+ parts = b.split(bytes([0]), 1)
258
+ ae(len(parts), 2)
259
+ ok(parts[0] == bytes([1]))
260
+ ok(parts[1] == bytes([2, 0, 3]))
261
+
262
+ # Whitespace split
263
+ b = bytes([32, 65, 32, 66, 32])
264
+ parts = b.split()
265
+ ae(len(parts), 2)
266
+ ok(parts[0] == bytes([65]))
267
+ ok(parts[1] == bytes([66]))
268
+
269
+ # ---------------------------------------------------------------------------
270
+ # replace()
271
+ # ---------------------------------------------------------------------------
272
+
273
+ b = bytes([1, 2, 3, 1, 2])
274
+ r = b.replace(bytes([1, 2]), bytes([9]))
275
+ ade(list(r), [9, 3, 9])
276
+
277
+ r = b.replace(bytes([1, 2]), bytes([9]), 1)
278
+ ade(list(r), [9, 3, 1, 2])
279
+
280
+ # ---------------------------------------------------------------------------
281
+ # strip() / lstrip() / rstrip()
282
+ # ---------------------------------------------------------------------------
283
+
284
+ b = bytes([32, 32, 65, 66, 32])
285
+ ok(b.strip() == bytes([65, 66]))
286
+ ok(b.lstrip() == bytes([65, 66, 32]))
287
+ ok(b.rstrip() == bytes([32, 32, 65, 66]))
288
+
289
+ b = bytes([1, 2, 65, 66, 2, 1])
290
+ ok(b.strip(bytes([1, 2])) == bytes([65, 66]))
291
+
292
+ # ---------------------------------------------------------------------------
293
+ # upper() / lower()
294
+ # ---------------------------------------------------------------------------
295
+
296
+ b = bytes([104, 101, 108, 108, 111]) # hello
297
+ ok(b.upper() == bytes([72, 69, 76, 76, 79])) # HELLO
298
+
299
+ b = bytes([72, 69, 76, 76, 79]) # HELLO
300
+ ok(b.lower() == bytes([104, 101, 108, 108, 111]))
301
+
302
+ # ---------------------------------------------------------------------------
303
+ # bytearray mutation methods
304
+ # ---------------------------------------------------------------------------
305
+
306
+ ba = bytearray([1, 2, 3])
307
+
308
+ ba.append(4)
309
+ ade(list(ba), [1, 2, 3, 4])
310
+
311
+ ba.extend([5, 6])
312
+ ade(list(ba), [1, 2, 3, 4, 5, 6])
313
+
314
+ ba.insert(0, 0)
315
+ ae(ba[0], 0)
316
+ ae(len(ba), 7)
317
+
318
+ popped = ba.pop()
319
+ ae(popped, 6)
320
+ ae(len(ba), 6)
321
+
322
+ popped = ba.pop(0)
323
+ ae(popped, 0)
324
+ ae(ba[0], 1)
325
+
326
+ ba.remove(3)
327
+ ok(not (3 in ba))
328
+
329
+ ba2 = bytearray([10, 20, 30])
330
+ ba2.reverse()
331
+ ade(list(ba2), [30, 20, 10])
332
+
333
+ ba3 = bytearray([1, 2, 3])
334
+ ba3.clear()
335
+ ae(len(ba3), 0)
336
+
337
+ # ---------------------------------------------------------------------------
338
+ # copy()
339
+ # ---------------------------------------------------------------------------
340
+
341
+ b = bytes([1, 2, 3])
342
+ b2 = b.copy()
343
+ ok(b == b2)
344
+ ok(b is not b2)
345
+
346
+ ba = bytearray([1, 2, 3])
347
+ ba2 = ba.copy()
348
+ ok(ba == ba2)
349
+ ok(ba is not ba2)
350
+ ok(isinstance(ba2, bytearray))
351
+
352
+ # ---------------------------------------------------------------------------
353
+ # repr() / str()
354
+ # ---------------------------------------------------------------------------
355
+
356
+ b = bytes([72, 101, 108, 108, 111])
357
+ ae(repr(b), "b'Hello'")
358
+ ae(str(b), "b'Hello'")
359
+
360
+ b = bytes([0, 1, 255])
361
+ ae(repr(b), "b'\\x00\\x01\\xff'")
362
+
363
+ b = bytes([10, 13, 9, 39, 92])
364
+ ae(repr(b), "b'\\n\\r\\t\\'\\\\'")
365
+
366
+ ba = bytearray([72, 105])
367
+ ok(repr(ba).startsWith('bytearray('))
368
+
369
+ # ---------------------------------------------------------------------------
370
+ # bool / truthiness
371
+ # ---------------------------------------------------------------------------
372
+
373
+ ok(not bytes())
374
+ ok(bytes([0]))
375
+ ok(not bytearray())
376
+ ok(bytearray([0]))
377
+
378
+ # ---------------------------------------------------------------------------
379
+ # hash()
380
+ # ---------------------------------------------------------------------------
381
+
382
+ b1 = bytes([1, 2, 3])
383
+ b2 = bytes([1, 2, 3])
384
+ ae(hash(b1), hash(b2))
385
+
386
+ # ---------------------------------------------------------------------------
387
+ # Uint8Array interop
388
+ # ---------------------------------------------------------------------------
389
+
390
+ ua = v'new Uint8Array([10, 20, 30])'
391
+ b = bytes(ua)
392
+ ae(len(b), 3)
393
+ ae(b[0], 10)
394
+ ae(b[2], 30)
395
+
396
+ # ---------------------------------------------------------------------------
397
+ # b'...' bytes literal syntax
398
+ # ---------------------------------------------------------------------------
399
+
400
+ # Basic ASCII literal
401
+ b = b'Hello'
402
+ ok(isinstance(b, bytes))
403
+ ae(len(b), 5)
404
+ ae(b[0], 72) # H
405
+ ae(b[1], 101) # e
406
+ ae(b[4], 111) # o
407
+ ok(b == bytes([72, 101, 108, 108, 111]))
408
+
409
+ # Uppercase B prefix
410
+ b = B'ABC'
411
+ ok(isinstance(b, bytes))
412
+ ae(len(b), 3)
413
+ ae(b[0], 65) # A
414
+
415
+ # Empty bytes literal
416
+ b = b''
417
+ ae(len(b), 0)
418
+ ok(isinstance(b, bytes))
419
+
420
+ # Hex escape sequences
421
+ b = b'\x48\x65\x6c\x6c\x6f' # Hello
422
+ ae(len(b), 5)
423
+ ae(b[0], 72)
424
+ ok(b == bytes([72, 101, 108, 108, 111]))
425
+
426
+ # Control character escapes
427
+ b = b'\n\t\r'
428
+ ae(len(b), 3)
429
+ ae(b[0], 10) # \n
430
+ ae(b[1], 9) # \t
431
+ ae(b[2], 13) # \r
432
+
433
+ # Null byte and max Latin-1 byte
434
+ b = b'\x00\xff'
435
+ ae(len(b), 2)
436
+ ae(b[0], 0)
437
+ ae(b[1], 255)
438
+
439
+ # Adjacent bytes literal concatenation
440
+ b = b'foo' b'bar'
441
+ ae(len(b), 6)
442
+ ok(b == bytes([102, 111, 111, 98, 97, 114])) # foobar
443
+
444
+ # Raw bytes literal - backslash sequences not interpreted
445
+ b = rb'\n\t'
446
+ ae(len(b), 4)
447
+ ae(b[0], 92) # backslash
448
+ ae(b[1], 110) # n
449
+ ae(b[2], 92) # backslash
450
+ ae(b[3], 116) # t
451
+
452
+ # Double-quoted bytes literal
453
+ b = b"World"
454
+ ae(len(b), 5)
455
+ ae(b[0], 87) # W
456
+
457
+ # bytes literal behaves like bytes constructed from equivalent list
458
+ b1 = b'Hello'
459
+ b2 = bytes([72, 101, 108, 108, 111])
460
+ ok(b1 == b2)
461
+ ok(b1.decode('utf-8') is 'Hello')
462
+
463
+ # Operations on bytes from literal
464
+ b = b'hello'
465
+ ok(b.upper() == bytes([72, 69, 76, 76, 79]))
466
+ ae(len(b + b'!'), 6)
467
+ ok(b'\x00\x01' + b'\x02' == bytes([0, 1, 2]))
package/test/classes.pyj CHANGED
@@ -69,6 +69,7 @@ assrt.equal(bound(), angela.how_long())
69
69
  # function methods
70
70
  assrt.deepEqual(sorted(dir(angela)), [
71
71
  'HAIRS',
72
+ '__format__',
72
73
  "__init__",
73
74
  '__repr__',
74
75
  '__str__',
@@ -0,0 +1,173 @@
1
+ from __python__ import overload_operators
2
+
3
+ # ── helpers ──────────────────────────────────────────────────────────────────
4
+
5
+ def _raises(fn, exc_type):
6
+ """Return True if fn() raises exc_type, False otherwise."""
7
+ try:
8
+ fn()
9
+ except exc_type:
10
+ return True
11
+ return False
12
+
13
+ # ── 1. Numeric comparisons (should still work correctly) ─────────────────────
14
+
15
+ assert 1 < 2
16
+ assert not (2 < 1)
17
+ assert 2 > 1
18
+ assert not (1 > 2)
19
+ assert 1 <= 1
20
+ assert 2 <= 3
21
+ assert not (3 <= 2)
22
+ assert 3 >= 3
23
+ assert 3 >= 2
24
+ assert not (2 >= 3)
25
+
26
+ # ── 2. String comparisons ────────────────────────────────────────────────────
27
+
28
+ assert 'abc' < 'abd'
29
+ assert 'abc' <= 'abc'
30
+ assert 'z' > 'a'
31
+ assert 'abc' >= 'abc'
32
+ assert not ('b' < 'a')
33
+
34
+ # ── 3. List lexicographic ordering ───────────────────────────────────────────
35
+
36
+ # First differing element determines order
37
+ assert [1, 2] < [1, 3]
38
+ assert not ([1, 3] < [1, 2])
39
+
40
+ # Prefix rule: shorter list with equal prefix is smaller
41
+ assert [1, 2] < [1, 2, 0]
42
+ assert not ([1, 2, 0] < [1, 2])
43
+
44
+ # First element dominates
45
+ assert [2] > [1, 99]
46
+ assert not ([1, 99] > [2])
47
+
48
+ # Equal lists
49
+ assert [1, 2] <= [1, 2]
50
+ assert [1, 2] >= [1, 2]
51
+ assert not ([1, 2] < [1, 2])
52
+ assert not ([1, 2] > [1, 2])
53
+
54
+ # Empty lists
55
+ assert [] < [1]
56
+ assert [] <= []
57
+ assert [1] > []
58
+ assert not ([] > [])
59
+
60
+ # ── 4. Nested list lexicographic ordering ────────────────────────────────────
61
+
62
+ assert [[1, 2], [3]] < [[1, 2], [4]]
63
+ assert [[1], [2]] < [[1], [2], []]
64
+
65
+ # ── 5. Bool operands (bool is int in Python) ─────────────────────────────────
66
+
67
+ assert not (True < True)
68
+ assert False < True
69
+ assert True > False
70
+ assert True >= True
71
+
72
+ # ── 6. Custom __lt__ / __le__ / __gt__ / __ge__ dispatch ────────────────────
73
+
74
+ class Vec:
75
+ def __init__(self, x):
76
+ self.x = x
77
+ def __lt__(self, other):
78
+ return self.x < other.x
79
+ def __le__(self, other):
80
+ return self.x <= other.x
81
+ def __gt__(self, other):
82
+ return self.x > other.x
83
+ def __ge__(self, other):
84
+ return self.x >= other.x
85
+
86
+ v1 = Vec(1)
87
+ v2 = Vec(2)
88
+ v3 = Vec(2)
89
+
90
+ assert v1 < v2
91
+ assert not (v2 < v1)
92
+ assert v2 > v1
93
+ assert not (v1 > v2)
94
+ assert v1 <= v2
95
+ assert v2 <= v3
96
+ assert v2 >= v3
97
+ assert v2 >= v1
98
+ assert not (v1 >= v2)
99
+
100
+ # ── 7. Reflected dunder dispatch ─────────────────────────────────────────────
101
+ # When left has no __gt__, Python calls right.__lt__
102
+
103
+ class LtOnly:
104
+ """Only defines __lt__; reflected ops depend on the right-hand operand."""
105
+ def __init__(self, x):
106
+ self.x = x
107
+ def __lt__(self, other):
108
+ return self.x < other.x
109
+
110
+ a = LtOnly(1)
111
+ b = LtOnly(2)
112
+
113
+ assert a < b # a.__lt__(b)
114
+ assert b > a # b.__gt__ absent → ρσ_op_gt falls back → ρσ_op_lt(a, b) → a.__lt__(b)
115
+
116
+ # ── 8. TypeError for incompatible types ──────────────────────────────────────
117
+
118
+ assert _raises(def(): return 1 < 'x';, TypeError)
119
+ assert _raises(def(): return 'x' < 1;, TypeError)
120
+ assert _raises(def(): return [1] < 1;, TypeError)
121
+ assert _raises(def(): return 1 < [1];, TypeError)
122
+ assert _raises(def(): return 1 > 'x';, TypeError)
123
+ assert _raises(def(): return 1 <= 'x';, TypeError)
124
+ assert _raises(def(): return 1 >= 'x';, TypeError)
125
+
126
+ # ── 9. TypeError message contains operator symbol ────────────────────────────
127
+
128
+ def _err_msg(fn):
129
+ try:
130
+ fn()
131
+ except TypeError as e:
132
+ return str(e)
133
+ return ''
134
+
135
+ msg = _err_msg(def(): return 1 < 'x';)
136
+ assert "'<'" in msg, msg
137
+ assert 'int' in msg, msg
138
+ assert 'str' in msg, msg
139
+
140
+ msg = _err_msg(def(): return 1 > [1];)
141
+ assert "'>'" in msg, msg
142
+
143
+ msg = _err_msg(def(): return 1 <= {};)
144
+ assert "'<='" in msg, msg
145
+
146
+ msg = _err_msg(def(): return 1 >= {};)
147
+ assert "'>='" in msg, msg
148
+
149
+ # ── 10. Chained comparisons with overloaded ops ───────────────────────────────
150
+
151
+ assert 1 < 2 < 3
152
+ assert not (1 < 2 < 2)
153
+ assert 3 > 2 > 1
154
+ assert 1 <= 1 <= 2
155
+ assert [1] < [2] < [3]
156
+ assert [3] > [2] > [1]
157
+
158
+ # Mixed direction chain
159
+ assert 1 < 2 > 0
160
+ assert not (1 < 2 > 3)
161
+
162
+ # ── 11. Chained comparison: middle expression evaluated once ─────────────────
163
+
164
+ counter = [0]
165
+ def inc_and_return(val):
166
+ counter[0] += 1
167
+ return val
168
+
169
+ # a < inc_and_return(b) < c — middle must be evaluated exactly once
170
+ assert 1 < inc_and_return(2) < 3
171
+ assert counter[0] == 1, counter[0]
172
+
173
+ print('All comparison_ops tests passed.')