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
@@ -1,80 +1,80 @@
1
- def add(a: int, b: float):
2
- return a + b
3
-
4
- assrt.ok(add.__annotations__)
5
- assrt.equal(add.__annotations__['a'], int)
6
- assrt.equal(add.__annotations__['b'], float)
7
- assrt.equal(add.__annotations__['return'], undefined)
8
-
9
- def sum(ls: list) -> int:
10
- pass
11
-
12
- assrt.ok(not (sum.__annotations__ == undefined))
13
- assrt.deepEqual(sum.__annotations__, {
14
- 'ls': list,
15
- 'return': int
16
- })
17
-
18
- def optional(a:int=10):
19
- return a
20
-
21
- assrt.ok(not (optional.__annotations__ == undefined))
22
- assrt.equal(optional.__annotations__.a, int)
23
- assrt.equal(optional.__defaults__.a, 10)
24
-
25
- def otherexpr(a:3+4) -> [1, 2]:
26
- pass
27
-
28
- assrt.ok(not (otherexpr.__annotations__ == undefined))
29
- assrt.equal(otherexpr.__annotations__['a'], 7)
30
- assrt.deepEqual(otherexpr.__annotations__['return'], [1, 2])
31
-
32
- def basic(x:float):
33
- pass
34
-
35
- assrt.deepEqual(basic.__annotations__, {
36
- 'x': float
37
- })
38
-
39
- def kwstarargs(*args:list, **kwargs:dict) -> int:
40
- pass
41
-
42
- assrt.equal(kwstarargs.__annotations__['return'], int)
43
-
44
- def nothing():
45
- pass
46
-
47
- assrt.ok(nothing.__annotations__ == undefined)
48
- assrt.throws(def():
49
- nothing.__annotations__['return']
50
- )
51
-
52
- test = def(x: int):
53
- pass
54
-
55
- assrt.deepEqual(test.__annotations__, {
56
- 'x': int
57
- })
58
-
59
- anonreturn = def() -> 'test':
60
- pass
61
-
62
- assrt.equal(anonreturn.__annotations__['return'], 'test')
63
-
64
- assrt.equal(def asexpr(a: int):
65
- a
66
- .__annotations__['a'], int)
67
-
68
- assrt.deepEqual(def(a: int) -> float:
69
- a + 10.0
70
- .__annotations__, {
71
- 'a': int,
72
- 'return': float
73
- })
74
-
75
- class A:
76
-
77
- def f(self, a : int, b: 'x') -> float:
78
- pass
79
-
80
- assrt.deepEqual(A.prototype.f.__annotations__, {'a':int, 'b':'x', 'return': float})
1
+ def add(a: int, b: float):
2
+ return a + b
3
+
4
+ assrt.ok(add.__annotations__)
5
+ assrt.equal(add.__annotations__['a'], int)
6
+ assrt.equal(add.__annotations__['b'], float)
7
+ assrt.equal(add.__annotations__['return'], undefined)
8
+
9
+ def sum(ls: list) -> int:
10
+ pass
11
+
12
+ assrt.ok(not (sum.__annotations__ == undefined))
13
+ assrt.deepEqual(sum.__annotations__, {
14
+ 'ls': list,
15
+ 'return': int
16
+ })
17
+
18
+ def optional(a:int=10):
19
+ return a
20
+
21
+ assrt.ok(not (optional.__annotations__ == undefined))
22
+ assrt.equal(optional.__annotations__.a, int)
23
+ assrt.equal(optional.__defaults__.a, 10)
24
+
25
+ def otherexpr(a:3+4) -> [1, 2]:
26
+ pass
27
+
28
+ assrt.ok(not (otherexpr.__annotations__ == undefined))
29
+ assrt.equal(otherexpr.__annotations__['a'], 7)
30
+ assrt.deepEqual(otherexpr.__annotations__['return'], [1, 2])
31
+
32
+ def basic(x:float):
33
+ pass
34
+
35
+ assrt.deepEqual(basic.__annotations__, {
36
+ 'x': float
37
+ })
38
+
39
+ def kwstarargs(*args:list, **kwargs:dict) -> int:
40
+ pass
41
+
42
+ assrt.equal(kwstarargs.__annotations__['return'], int)
43
+
44
+ def nothing():
45
+ pass
46
+
47
+ assrt.ok(nothing.__annotations__ == undefined)
48
+ assrt.throws(def():
49
+ nothing.__annotations__['return']
50
+ )
51
+
52
+ test = def(x: int):
53
+ pass
54
+
55
+ assrt.deepEqual(test.__annotations__, {
56
+ 'x': int
57
+ })
58
+
59
+ anonreturn = def() -> 'test':
60
+ pass
61
+
62
+ assrt.equal(anonreturn.__annotations__['return'], 'test')
63
+
64
+ assrt.equal(def asexpr(a: int):
65
+ a
66
+ .__annotations__['a'], int)
67
+
68
+ assrt.deepEqual(def(a: int) -> float:
69
+ a + 10.0
70
+ .__annotations__, {
71
+ 'a': int,
72
+ 'return': float
73
+ })
74
+
75
+ class A:
76
+
77
+ def f(self, a : int, b: 'x') -> float:
78
+ pass
79
+
80
+ assrt.deepEqual(A.prototype.f.__annotations__, {'a':int, 'b':'x', 'return': float})
@@ -0,0 +1,88 @@
1
+ # globals: assrt
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # arithmetic_nostrict.pyj
5
+ # Tests for no_strict_arithmetic: when strict_arithmetic is disabled, incompatible
6
+ # operand types fall back to JavaScript's native coercion instead of raising TypeError.
7
+ # overload_operators must be active for the ρσ_op_*_ns helpers to be dispatched.
8
+
9
+ from __python__ import overload_operators, no_strict_arithmetic
10
+
11
+ ae = assrt.equal
12
+ ade = assrt.deepEqual
13
+ ok = assrt.ok
14
+
15
+ def _no_error(fn):
16
+ try:
17
+ fn()
18
+ return True
19
+ except:
20
+ return False
21
+
22
+ # ── 1. Valid numeric arithmetic still works ───────────────────────────────────
23
+
24
+ ae(1 + 2, 3)
25
+ ae(10 - 3, 7)
26
+ ae(3 * 4, 12)
27
+ ae(7 / 2, 3.5)
28
+ ae(7 // 2, 3)
29
+ ae(7 % 3, 1)
30
+ ae(2 ** 8, 256)
31
+
32
+ # ── 2. Valid string concatenation still works ─────────────────────────────────
33
+
34
+ ae('hello' + ' world', 'hello world')
35
+
36
+ # ── 3. Valid list concatenation still works ───────────────────────────────────
37
+
38
+ ade([1, 2] + [3, 4], [1, 2, 3, 4])
39
+
40
+ # ── 4. String / list repetition still works ──────────────────────────────────
41
+
42
+ ae('ha' * 3, 'hahaha')
43
+ ae(3 * 'ha', 'hahaha')
44
+ ade([0] * 3, [0, 0, 0])
45
+
46
+ # ── 5. Mixed types do NOT raise TypeError ─────────────────────────────────────
47
+
48
+ ok(_no_error(def(): return 1 + 'x';))
49
+ ok(_no_error(def(): return 'x' + 1;))
50
+ ok(_no_error(def(): return 1 - 'x';))
51
+ ok(_no_error(def(): return None + 1;))
52
+
53
+ # ── 6. JS coercion semantics for mixed types ──────────────────────────────────
54
+
55
+ # int + str coerces via JS (number becomes string)
56
+ ae(1 + 'x', '1x')
57
+ ae('x' + 2, 'x2')
58
+
59
+ # number - string coerces string to NaN
60
+ ok(isNaN(1 - 'x'))
61
+
62
+ # ── 7. Dunder methods still dispatch ──────────────────────────────────────────
63
+
64
+ class _Meter:
65
+ def __init__(self, n):
66
+ self.n = n
67
+ def __add__(self, other):
68
+ return _Meter(self.n + other.n)
69
+ def __mul__(self, scalar):
70
+ return _Meter(self.n * scalar)
71
+
72
+ m = _Meter(3) + _Meter(4)
73
+ ae(m.n, 7)
74
+ m2 = _Meter(5) * 2
75
+ ae(m2.n, 10)
76
+
77
+ # ── 8. Augmented assignment does not raise TypeError ──────────────────────────
78
+
79
+ ok(_no_error(def():
80
+ x = 1
81
+ x += 'oops'
82
+ ))
83
+
84
+ # ── 9. Comparison operators fall through to JS ────────────────────────────────
85
+
86
+ # JS comparisons with mixed types don't throw; they may produce surprising results
87
+ ok(_no_error(def(): return 1 < 'x';))
88
+ ok(_no_error(def(): return None >= 0;))
@@ -0,0 +1,169 @@
1
+ # globals: assrt
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # arithmetic_types.pyj
5
+ # Tests for Python-style arithmetic type coercion: incompatible operand types
6
+ # raise TypeError instead of silently coercing (as JavaScript would).
7
+ # overload_operators must be active for the ρσ_op_* helpers to be dispatched.
8
+
9
+ from __python__ import overload_operators, strict_arithmetic
10
+
11
+ ae = assrt.equal
12
+ ade = assrt.deepEqual
13
+ ok = assrt.ok
14
+
15
+ def _raises_type_error(fn):
16
+ try:
17
+ fn()
18
+ return False
19
+ except TypeError:
20
+ return True
21
+
22
+ # ── 1. Valid numeric arithmetic ──────────────────────────────────────────────
23
+
24
+ ae(1 + 2, 3)
25
+ ae(1.5 + 2.5, 4.0)
26
+ ae(10 - 3, 7)
27
+ ae(3 * 4, 12)
28
+ ae(7 / 2, 3.5)
29
+ ae(7 // 2, 3)
30
+ ae(7 % 3, 1)
31
+ ae(2 ** 8, 256)
32
+
33
+ # ── 2. Valid string concatenation ────────────────────────────────────────────
34
+
35
+ ae('hello' + ' world', 'hello world')
36
+ ae('a' + 'b' + 'c', 'abc')
37
+
38
+ # ── 3. Valid list concatenation ──────────────────────────────────────────────
39
+
40
+ ade([1, 2] + [3, 4], [1, 2, 3, 4])
41
+ ade([] + [1], [1])
42
+
43
+ # ── 4. Valid string/list repetition ──────────────────────────────────────────
44
+
45
+ ae('ha' * 3, 'hahaha')
46
+ ae(3 * 'ha', 'hahaha')
47
+ ade([0] * 3, [0, 0, 0])
48
+ ade(3 * [1, 2], [1, 2, 1, 2, 1, 2])
49
+
50
+ # ── 5. bool treated as int for arithmetic (Python semantics) ─────────────────
51
+
52
+ ae(True + 1, 2)
53
+ ae(False + 0, 0)
54
+ ae(True + True, 2)
55
+ ae(True * 5, 5)
56
+ ae(False * 100, 0)
57
+ ae(True + 1.5, 2.5)
58
+
59
+ # bool * str and bool * list repetition
60
+ ae(True * 'x', 'x')
61
+ ae(False * 'x', '')
62
+ ade(True * [1, 2], [1, 2])
63
+ ade(False * [1, 2], [])
64
+
65
+ # ── 6. int + str raises TypeError ────────────────────────────────────────────
66
+
67
+ ok(_raises_type_error(def(): return 1 + 'x';))
68
+ ok(_raises_type_error(def(): return 'x' + 1;))
69
+ ok(_raises_type_error(def(): return 1 + '1';))
70
+
71
+ # ── 7. numeric - non-numeric raises TypeError ────────────────────────────────
72
+
73
+ ok(_raises_type_error(def(): return 1 - 'x';))
74
+ ok(_raises_type_error(def(): return 'a' - 'b';))
75
+ ok(_raises_type_error(def(): return [1] - [2];))
76
+
77
+ # ── 8. numeric / non-numeric raises TypeError ────────────────────────────────
78
+
79
+ ok(_raises_type_error(def(): return 1 / 'x';))
80
+ ok(_raises_type_error(def(): return 'a' / 2;))
81
+
82
+ # ── 9. numeric // non-numeric raises TypeError ───────────────────────────────
83
+
84
+ ok(_raises_type_error(def(): return 5 // 'x';))
85
+ ok(_raises_type_error(def(): return 'a' // 2;))
86
+
87
+ # ── 10. numeric % non-numeric raises TypeError ───────────────────────────────
88
+
89
+ ok(_raises_type_error(def(): return 5 % 'x';))
90
+ ok(_raises_type_error(def(): return 'a' % 2;))
91
+
92
+ # ── 11. numeric ** non-numeric raises TypeError ──────────────────────────────
93
+
94
+ ok(_raises_type_error(def(): return 2 ** 'x';))
95
+ ok(_raises_type_error(def(): return 'a' ** 2;))
96
+
97
+ # ── 12. mixed str * non-numeric raises TypeError ─────────────────────────────
98
+
99
+ ok(_raises_type_error(def(): return 'ha' * 'ha';))
100
+ ok(_raises_type_error(def(): return 'ha' * [1];))
101
+
102
+ # ── 13. list + non-list raises TypeError ─────────────────────────────────────
103
+
104
+ ok(_raises_type_error(def(): return [1, 2] + 1;))
105
+ ok(_raises_type_error(def(): return [1, 2] + 'x';))
106
+ ok(_raises_type_error(def(): return 1 + [1, 2];))
107
+
108
+ # ── 14. None as operand raises TypeError ─────────────────────────────────────
109
+
110
+ ok(_raises_type_error(def(): return None + 1;))
111
+ ok(_raises_type_error(def(): return 1 + None;))
112
+ ok(_raises_type_error(def(): return None + 'x';))
113
+
114
+ # ── 15. TypeError message contains operand type names ────────────────────────
115
+
116
+ msg = ''
117
+ try:
118
+ v = 1 + 'x'
119
+ except TypeError as e:
120
+ msg = str(e)
121
+ ok(msg.indexOf('int') >= 0)
122
+ ok(msg.indexOf('str') >= 0)
123
+ ok(msg.indexOf('+') >= 0)
124
+
125
+ msg2 = ''
126
+ try:
127
+ v = 2.5 - 'y'
128
+ except TypeError as e:
129
+ msg2 = str(e)
130
+ ok(msg2.indexOf('float') >= 0)
131
+ ok(msg2.indexOf('str') >= 0)
132
+ ok(msg2.indexOf('-') >= 0)
133
+
134
+ # ── 16. augmented assignment also raises TypeError ───────────────────────────
135
+
136
+ ok(_raises_type_error(def():
137
+ x = 1
138
+ x += 'oops'
139
+ ))
140
+ ok(_raises_type_error(def():
141
+ x = 'hello'
142
+ x -= 1
143
+ ))
144
+
145
+ # ── 17. dunder methods still take priority over type checks ──────────────────
146
+
147
+ class _Meter:
148
+ def __init__(self, n):
149
+ self.n = n
150
+ def __add__(self, other):
151
+ return _Meter(self.n + other.n)
152
+ def __mul__(self, scalar):
153
+ return _Meter(self.n * scalar)
154
+
155
+ m = _Meter(3) + _Meter(4)
156
+ ae(m.n, 7)
157
+ m2 = _Meter(5) * 2
158
+ ae(m2.n, 10)
159
+
160
+ # ── 18. radd/rsub reflected methods still work ───────────────────────────────
161
+
162
+ class _Vec:
163
+ def __init__(self, x):
164
+ self.x = x
165
+ def __radd__(self, other):
166
+ return _Vec(other + self.x)
167
+
168
+ v = 10 + _Vec(5)
169
+ ae(v.x, 15)
package/test/baselib.pyj CHANGED
@@ -99,6 +99,20 @@ assrt.deepEqual(list(map(def(a):return a*2;, iter([1, 2]))), [2, 4])
99
99
  assrt.deepEqual(list(filter(def(a):return a > 1;, [1, 2])), [2])
100
100
  assrt.deepEqual(list(filter(def(a):return a > 1;, iter([1, 2]))), [2])
101
101
  assrt.deepEqual(list(zip([1,2], [3,4])), [[1,3], [2, 4]])
102
+ assrt.deepEqual(list(zip([1,2], [3,4], strict=True)), [[1,3], [2, 4]])
103
+ assrt.deepEqual(list(zip(strict=True)), [])
104
+ _zip_err = False
105
+ try:
106
+ list(zip([1,2], [3], strict=True))
107
+ except:
108
+ _zip_err = True
109
+ assrt.ok(_zip_err)
110
+ _zip_err2 = False
111
+ try:
112
+ list(zip([1], [3,4], strict=True))
113
+ except:
114
+ _zip_err2 = True
115
+ assrt.ok(_zip_err2)
102
116
 
103
117
  # lists
104
118
  a = [1, 2]
@@ -317,3 +331,80 @@ assrt.equal(all(iter([1, 2, 3])), True)
317
331
  assrt.equal(all(iter([1, 0, 3])), False)
318
332
  assrt.equal(all(range(1, 4)), True)
319
333
  assrt.equal(all(range(0, 3)), False)
334
+
335
+ # complex() builtin and j-literal syntax
336
+ c1 = complex(3, 4)
337
+ assrt.equal(c1.real, 3)
338
+ assrt.equal(c1.imag, 4)
339
+
340
+ # j literal syntax
341
+ c2 = 4j
342
+ assrt.equal(c2.real, 0)
343
+ assrt.equal(c2.imag, 4)
344
+
345
+ # 3+4j literal — + goes through ρσ_list_add which dispatches __add__
346
+ c3 = 3+4j
347
+ assrt.equal(c3.real, 3)
348
+ assrt.equal(c3.imag, 4)
349
+
350
+ # abs() dispatches to __abs__
351
+ assrt.equal(abs(complex(3, 4)), 5.0)
352
+ assrt.equal(abs(complex(-5, 0)), 5)
353
+
354
+ # arithmetic via dunder methods (no overload_operators needed)
355
+ assrt.ok(complex(1, 2).__add__(complex(3, 4)) == complex(4, 6))
356
+ assrt.ok(complex(5, 6).__sub__(complex(3, 4)) == complex(2, 2))
357
+ assrt.ok(complex(1, 2).__mul__(complex(3, 4)) == complex(-5, 10))
358
+ assrt.ok(complex(2, 0).__truediv__(complex(4, 0)) == complex(0.5, 0))
359
+
360
+ # mixed complex + number
361
+ assrt.ok(complex(3, 4) + 1 == complex(4, 4)) # ρσ_list_add → __add__
362
+ assrt.ok(complex(3, 4).__radd__(1) == complex(4, 4))
363
+ assrt.ok(complex(3, 4).__sub__(1) == complex(2, 4))
364
+ assrt.ok(complex(3, 4).__rmul__(2) == complex(6, 8))
365
+ assrt.ok(complex(6, 8).__truediv__(2) == complex(3, 4))
366
+
367
+ # 1 + complex — ρσ_list_add dispatches __radd__ when left has no __add__
368
+ assrt.ok(1 + complex(3, 4) == complex(4, 4))
369
+
370
+ # unary via dunder
371
+ assrt.ok(complex(3, 4).__neg__() == complex(-3, -4))
372
+ assrt.ok(complex(3, 4).__pos__() == complex(3, 4))
373
+
374
+ # conjugate
375
+ assrt.ok(complex(3, 4).conjugate() == complex(3, -4))
376
+
377
+ # zero-argument form
378
+ assrt.ok(complex() == complex(0, 0))
379
+
380
+ # single-argument number
381
+ assrt.ok(complex(5) == complex(5, 0))
382
+
383
+ # single-argument string
384
+ assrt.ok(complex('3+4j') == complex(3, 4))
385
+ assrt.ok(complex('3-4j') == complex(3, -4))
386
+ assrt.ok(complex('4j') == complex(0, 4))
387
+ assrt.ok(complex('3') == complex(3, 0))
388
+ assrt.ok(complex('j') == complex(0, 1))
389
+ assrt.ok(complex('-j') == complex(0, -1))
390
+
391
+ # isinstance
392
+ assrt.ok(isinstance(complex(1, 2), complex))
393
+ assrt.ok(not isinstance(42, complex))
394
+
395
+ # bool — __bool__ dispatch works, and truthiness is correct in conditions
396
+ assrt.ok(complex(0, 0).__bool__() is False)
397
+ assrt.ok(complex(1, 0).__bool__() is True)
398
+ assrt.ok(complex(0, 1).__bool__() is True)
399
+
400
+ # repr / str
401
+ assrt.equal(repr(complex(0, 0)), '0j')
402
+ assrt.equal(repr(complex(1, 0)), '(1+0j)')
403
+ assrt.equal(repr(complex(0, 1)), '1j')
404
+ assrt.equal(repr(complex(3, 4)), '(3+4j)')
405
+ assrt.equal(repr(complex(3, -4)), '(3-4j)')
406
+ assrt.equal(str(complex(3, 4)), '(3+4j)')
407
+
408
+ # abs() still works on numbers
409
+ assrt.equal(abs(-5), 5)
410
+ assrt.equal(abs(3.0), 3.0)