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
package/test/json.pyj ADDED
@@ -0,0 +1,196 @@
1
+ # globals: assrt
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # json.pyj
5
+ # Tests for the json standard library module.
6
+
7
+ from json import dumps, loads, dump, load, JSONDecodeError
8
+
9
+ ae = assrt.equal
10
+ ade = assrt.deepEqual
11
+ ok = assrt.ok
12
+ throws = assrt.throws
13
+
14
+ # ── 1. dumps — basic types ────────────────────────────────────────────────────
15
+
16
+ ae(dumps(None), 'null')
17
+ ae(dumps(True), 'true')
18
+ ae(dumps(False), 'false')
19
+ ae(dumps(42), '42')
20
+ ae(dumps(3.14), '3.14')
21
+ ae(dumps('hello'), '"hello"')
22
+ ae(dumps('with "quotes"'), '"with \\"quotes\\""')
23
+
24
+ # ── 2. dumps — collections ────────────────────────────────────────────────────
25
+
26
+ ae(dumps([]), '[]')
27
+ ae(dumps([1, 2, 3]), '[1,2,3]')
28
+ ae(dumps({}), '{}')
29
+
30
+ # Object with single key (no ordering ambiguity)
31
+ _d1 = dumps({'a': 1})
32
+ ae(_d1, '{"a":1}')
33
+
34
+ # ── 3. dumps — indent ─────────────────────────────────────────────────────────
35
+
36
+ _pretty = dumps([1, 2], indent=2)
37
+ ok(_pretty.indexOf('\n') >= 0, 'indented output should contain newlines')
38
+ ok(_pretty.indexOf(' ') >= 0, 'indented output should contain spaces')
39
+
40
+ # ── 4. dumps — sort_keys ──────────────────────────────────────────────────────
41
+
42
+ _sk = dumps({'b': 2, 'a': 1}, sort_keys=True)
43
+ ae(_sk, '{"a":1,"b":2}')
44
+
45
+ # Nested sort_keys
46
+ _sk2 = dumps({'z': {'y': 3, 'x': 4}, 'a': 1}, sort_keys=True)
47
+ ae(_sk2, '{"a":1,"z":{"x":4,"y":3}}')
48
+
49
+ # ── 5. dumps — separators ─────────────────────────────────────────────────────
50
+
51
+ # Compact form used in Python: separators=(',', ':')
52
+ _compact = dumps({'a': 1, 'b': 2}, sort_keys=True, separators=(',', ':'))
53
+ ae(_compact, '{"a":1,"b":2}')
54
+
55
+ # ── 6. dumps — default callback ───────────────────────────────────────────────
56
+
57
+ class _Point:
58
+ def __init__(self, x, y):
59
+ self.x = x
60
+ self.y = y
61
+
62
+ def _point_default(obj):
63
+ if isinstance(obj, _Point):
64
+ return {'x': obj.x, 'y': obj.y}
65
+ raise TypeError('not serializable')
66
+
67
+ _pt_json = dumps(_Point(3, 4), dflt=_point_default)
68
+ _pt_obj = loads(_pt_json)
69
+ ae(_pt_obj.x, 3)
70
+ ae(_pt_obj.y, 4)
71
+
72
+ # ── 7. dumps — allow_nan ──────────────────────────────────────────────────────
73
+
74
+ _nan_raised = False
75
+ try:
76
+ dumps(v'NaN')
77
+ except ValueError:
78
+ _nan_raised = True
79
+ ok(_nan_raised, 'dumps(NaN) should raise ValueError by default')
80
+
81
+ _inf_raised = False
82
+ try:
83
+ dumps(v'Infinity')
84
+ except ValueError:
85
+ _inf_raised = True
86
+ ok(_inf_raised, 'dumps(Infinity) should raise ValueError by default')
87
+
88
+ # allow_nan=True should not raise
89
+ _nan_str = dumps(v'NaN', allow_nan=True)
90
+ ok(_nan_str.length > 0, 'allow_nan=True should return a string')
91
+
92
+ # ── 8. loads — basic types ────────────────────────────────────────────────────
93
+
94
+ ae(loads('null'), None)
95
+ ae(loads('true'), True)
96
+ ae(loads('false'), False)
97
+ ae(loads('42'), 42)
98
+ ae(loads('3.14'), 3.14)
99
+ ae(loads('"hello"'), 'hello')
100
+
101
+ # ── 9. loads — collections ────────────────────────────────────────────────────
102
+
103
+ _arr = loads('[1, 2, 3]')
104
+ ade(_arr, [1, 2, 3])
105
+
106
+ _obj = loads('{"a": 1, "b": 2}')
107
+ ae(_obj.a, 1)
108
+ ae(_obj.b, 2)
109
+
110
+ # ── 10. loads — nested structures ─────────────────────────────────────────────
111
+
112
+ _nested = loads('{"users": [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]}')
113
+ ae(_nested.users.length, 2)
114
+ ae(_nested.users[0].name, 'Alice')
115
+ ae(_nested.users[1].age, 25)
116
+
117
+ # ── 11. loads — object_hook ───────────────────────────────────────────────────
118
+
119
+ class _NameAge:
120
+ def __init__(self, d):
121
+ self.name = d.name if d.name else ''
122
+ self.age = d.age if d.age else 0
123
+
124
+ def _obj_hook(d):
125
+ if d.name is not None:
126
+ return _NameAge(d)
127
+ return d
128
+
129
+ _h = loads('{"name": "Alice", "age": 30}', object_hook=_obj_hook)
130
+ ok(isinstance(_h, _NameAge), 'object_hook should produce a _NameAge instance')
131
+ ae(_h.name, 'Alice')
132
+ ae(_h.age, 30)
133
+
134
+ # ── 12. loads — object_pairs_hook ─────────────────────────────────────────────
135
+
136
+ _pairs_result = []
137
+ def _pairs_hook(pairs):
138
+ _pairs_result.push(pairs.length)
139
+ return pairs
140
+
141
+ loads('{"x": 1, "y": 2}', object_pairs_hook=_pairs_hook)
142
+ ae(_pairs_result[0], 2, 'object_pairs_hook should receive 2 pairs')
143
+
144
+ # ── 13. loads — parse_float / parse_int ───────────────────────────────────────
145
+
146
+ _floats = []
147
+ def _capture_float(s):
148
+ _floats.push(s)
149
+ return float(s)
150
+
151
+ loads('3.14', parse_float=_capture_float)
152
+ ae(_floats.length, 1)
153
+ ae(_floats[0], '3.14')
154
+
155
+ _ints = []
156
+ def _capture_int(s):
157
+ _ints.push(s)
158
+ return int(s)
159
+
160
+ loads('42', parse_int=_capture_int)
161
+ ae(_ints.length, 1)
162
+ ae(_ints[0], '42')
163
+
164
+ # ── 14. loads — JSONDecodeError ───────────────────────────────────────────────
165
+
166
+ _err_raised = False
167
+ try:
168
+ loads('{invalid json}')
169
+ except JSONDecodeError as e:
170
+ _err_raised = True
171
+ ok(isinstance(e, JSONDecodeError), 'should be JSONDecodeError')
172
+ ok(isinstance(e, ValueError), 'JSONDecodeError should be a ValueError')
173
+ ok(_err_raised, 'invalid JSON should raise JSONDecodeError')
174
+
175
+ # ── 15. round-trip ────────────────────────────────────────────────────────────
176
+
177
+ _original = {'name': 'test', 'values': [1, 2, 3], 'nested': {'ok': True}}
178
+ _rt = loads(dumps(_original))
179
+ ae(_rt.name, _original.name)
180
+ ade(_rt.values, _original.values)
181
+ ae(_rt.nested.ok, _original.nested.ok)
182
+
183
+ # ── 16. dump / load via file-like object ──────────────────────────────────────
184
+
185
+ class _StringIO:
186
+ def __init__(self):
187
+ self._buf = ''
188
+ def write(self, s):
189
+ self._buf += s
190
+ def read(self):
191
+ return self._buf
192
+
193
+ _sio = _StringIO()
194
+ dump({'key': 'value'}, _sio)
195
+ _loaded = load(_sio)
196
+ ae(_loaded.key, 'value')
package/test/lint.pyj CHANGED
@@ -1,164 +1,164 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD
3
- # Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
4
-
5
- linter = require('../tools/lint.js')
6
-
7
- def lint(code):
8
- return linter.lint_code(code, {'filename':'<test>', 'report':def():
9
- pass
10
- })
11
-
12
- def err_test(code, ident, line, name, other_line):
13
- msgs = lint(code)
14
- assrt.ok(len(msgs) > 0, 'failed to find error in: ' + code)
15
- assrt.equal(len(msgs), 1, 'found ' + (len(msgs) - 1) + ' extra errors in: ' + code)
16
- assrt.equal(msgs[0].ident, ident, 'incorrect ident: ' + msgs[0].ident + ' for: ' + code)
17
- if line != undefined:
18
- assrt.equal(msgs[0].start_line, line, 'incorrect line: ' + msgs[0].start_line + ' for: ' + code)
19
- if name != undefined:
20
- assrt.equal(msgs[0].name, name, 'incorrect name: ' + msgs[0].name + ' for: ' + code)
21
- if other_line != undefined:
22
- assrt.equal(msgs[0].other_line, other_line, 'incorrect other_line: ' + msgs[0].other_line + ' for: ' + code)
23
-
24
- def ok_test(code):
25
- msgs = lint(code)
26
- assrt.equal(msgs.length, 0, 'Got unexpected msg: ' + (msgs[0] or {}).message + ' for code: ' + code)
27
-
28
- # Imports
29
- err_test('import foo', 'unused-import', 1, 'foo')
30
- err_test('import foo.boo', 'unused-import', 1, 'foo')
31
- err_test('import foo as boo', 'unused-import', 1, 'boo')
32
- err_test('from x import foo', 'unused-import', 1, 'foo')
33
- err_test('from x import foo as boo', 'unused-import', 1, 'boo')
34
- ok_test('import foo\nfoo')
35
-
36
- # Function arguments
37
- ok_test('def f(a):\n return a')
38
- ok_test('def f(a=1):\n return a')
39
- ok_test('def f(*a):\n return a')
40
- ok_test('def f(**a):\n return a')
41
- ok_test('def f(a):\n return 1')
42
-
43
- # Extended slices
44
- ok_test('a = []; a[::2], a[1:-1]')
45
-
46
- # Top level unused ignored
47
- ok_test('a=1\ndef f():\n pass')
48
-
49
- # Destructuring assignment
50
- ok_test('def f():\n a, b = 1, 2; a, b')
51
- ok_test('def f():\n a = 1; b, c = a, 2; return b, c')
52
- ok_test('for x, (y, z) in [ [1, [2, 3]] ]:\n x + y + z')
53
- err_test('def f():\n a, b = 1, 1; return a', 'unused-local', 2, 'b')
54
-
55
- # Compound assignment
56
- err_test('a += 1', 'undef', 1, 'a')
57
- ok_test('def f():\n a = 1; a += 1')
58
-
59
- # Unused bindings
60
- err_test('def f():\n a=1', 'unused-local', 2, 'a')
61
- err_test('def f():\n def a():\n pass', 'unused-local', 2, 'a')
62
-
63
- # Undefined references
64
- err_test('f()', 'undef', 1, 'f')
65
- err_test('a', 'undef', 1, 'a')
66
- err_test('def f():\n a=1; return a\na', 'undef', 3, 'a')
67
-
68
- # Comprehensions
69
- ok_test('[x for x in [1,2]]')
70
- ok_test('[1 for x in [1,2] if x]')
71
- ok_test('[1 for x in [1,2]]')
72
- ok_test('def f():\n l=[1,2];[x for x in l]')
73
- ok_test('def f():\n l=[1,2];{x:True for x in l}')
74
- err_test('def f():\n [x for x in [1,2]]; return x', 'undef', 2, 'x')
75
-
76
- # Loops
77
- ok_test('def f():\n for x in "":\n pass\n return x')
78
- ok_test('def f():\n for x in "":\n x += 1\n')
79
- ok_test('def f():\n for x, y in "":\n pass\n return x, y')
80
- ok_test('for v"var i = 0; i < 1; i++":\n print(i)')
81
- err_test('def f():\n a = 1\n for a in "":\n a', 'loop-shadowed', 3, 'a', 2)
82
-
83
- # Semi-colons
84
- err_test('a=1;;a', 'extra-semicolon', 1, ';')
85
- err_test('a=1;', 'eol-semicolon', 1, ';')
86
-
87
- # Builtins
88
- for k in 'String Symbol this self window Map arguments print len range dir undefined'.split(' '):
89
- ok_test(k)
90
-
91
- # noqa
92
- ok_test('f() # noqa')
93
- ok_test('f() # noqa:undef')
94
- err_test('f() # noqa:xxx', 'undef')
95
-
96
- # Named func in branch
97
- err_test('if 1:\n def f():\n pass', 'func-in-branch', 2, 'f')
98
- err_test('if 1:\n pass\nelse:\n def f():\n pass', 'func-in-branch', 4, 'f')
99
- err_test('try:\n def f():\n pass\nexcept:\n pass', 'func-in-branch', 2, 'f')
100
- ok_test('if 1:\n a = def():\n pass')
101
-
102
- # Syntax errors
103
- err_test('def f(:\n pass', 'syntax-err', 1)
104
-
105
- # Functions
106
- ok_test('def f():\n pass\nf()')
107
-
108
- # Non-locals
109
- err_test('def a():\n x = 1\n def b():\n nonlocal x\n b()', 'unused-local', 2, 'x')
110
- ok_test('def a():\n x = 1\n def b():\n nonlocal x\n x\n b()')
111
- ok_test('def a():\n x = 1\n def b():\n nonlocal x\n x\n x = 2\n b()')
112
- ok_test('def a():\n x = 1\n def ():\n nonlocal x\n x = 1\n x')
113
- ok_test('nonlocal a\na()')
114
-
115
- # Define after use
116
- err_test('def g():\n f()\n f()\n def f():\n pass', 'def-after-use', 3, 'f')
117
-
118
- # Decorators
119
- ok_test('from x import y\n@y\ndef f():\n pass')
120
-
121
- # try/except
122
- ok_test('try:\n 1\nexcept Error as e:\n e')
123
-
124
- # Classes
125
- ok_test('''
126
- class A:
127
-
128
- h = j = 1
129
- x = h + j
130
- if True:
131
- k = 1
132
- else:
133
- k = 2
134
-
135
- def __init__(self, a):
136
- self.a = a
137
-
138
- def unused(self):
139
- pass
140
- other = unused
141
-
142
- class B(A):
143
-
144
- def __init__(self):
145
- A.__init__(self, 'b')
146
- ''')
147
- err_test('class A:\n def a(self):\n a()', 'undef', 3, 'a')
148
- err_test('class A:\n def a(self):\n pass\n def a(self):\n pass', 'dup-method', 4, 'a')
149
-
150
- # Object literals
151
- err_test('{"a":1, "a":2}', 'dup-key', 1, 'a')
152
-
153
- # keyword arg values
154
- ok_test('def f():\n a=1\n f(b=a)')
155
- ok_test('def f():\n a={}\n f(**a)')
156
-
157
- # with statement
158
- ok_test('''
159
- def f():
160
- a = 1
161
- with a as b:
162
- b()
163
- ''')
164
- err_test('with a:\n pass', 'undef', '1', 'a')
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD
3
+ # Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
4
+
5
+ linter = require('../tools/lint.js')
6
+
7
+ def lint(code):
8
+ return linter.lint_code(code, {'filename':'<test>', 'report':def():
9
+ pass
10
+ })
11
+
12
+ def err_test(code, ident, line, name, other_line):
13
+ msgs = lint(code)
14
+ assrt.ok(len(msgs) > 0, 'failed to find error in: ' + code)
15
+ assrt.equal(len(msgs), 1, 'found ' + (len(msgs) - 1) + ' extra errors in: ' + code)
16
+ assrt.equal(msgs[0].ident, ident, 'incorrect ident: ' + msgs[0].ident + ' for: ' + code)
17
+ if line != undefined:
18
+ assrt.equal(msgs[0].start_line, line, 'incorrect line: ' + msgs[0].start_line + ' for: ' + code)
19
+ if name != undefined:
20
+ assrt.equal(msgs[0].name, name, 'incorrect name: ' + msgs[0].name + ' for: ' + code)
21
+ if other_line != undefined:
22
+ assrt.equal(msgs[0].other_line, other_line, 'incorrect other_line: ' + msgs[0].other_line + ' for: ' + code)
23
+
24
+ def ok_test(code):
25
+ msgs = lint(code)
26
+ assrt.equal(msgs.length, 0, 'Got unexpected msg: ' + (msgs[0] or {}).message + ' for code: ' + code)
27
+
28
+ # Imports
29
+ err_test('import foo', 'unused-import', 1, 'foo')
30
+ err_test('import foo.boo', 'unused-import', 1, 'foo')
31
+ err_test('import foo as boo', 'unused-import', 1, 'boo')
32
+ err_test('from x import foo', 'unused-import', 1, 'foo')
33
+ err_test('from x import foo as boo', 'unused-import', 1, 'boo')
34
+ ok_test('import foo\nfoo')
35
+
36
+ # Function arguments
37
+ ok_test('def f(a):\n return a')
38
+ ok_test('def f(a=1):\n return a')
39
+ ok_test('def f(*a):\n return a')
40
+ ok_test('def f(**a):\n return a')
41
+ ok_test('def f(a):\n return 1')
42
+
43
+ # Extended slices
44
+ ok_test('a = []; a[::2], a[1:-1]')
45
+
46
+ # Top level unused ignored
47
+ ok_test('a=1\ndef f():\n pass')
48
+
49
+ # Destructuring assignment
50
+ ok_test('def f():\n a, b = 1, 2; a, b')
51
+ ok_test('def f():\n a = 1; b, c = a, 2; return b, c')
52
+ ok_test('for x, (y, z) in [ [1, [2, 3]] ]:\n x + y + z')
53
+ err_test('def f():\n a, b = 1, 1; return a', 'unused-local', 2, 'b')
54
+
55
+ # Compound assignment
56
+ err_test('a += 1', 'undef', 1, 'a')
57
+ ok_test('def f():\n a = 1; a += 1')
58
+
59
+ # Unused bindings
60
+ err_test('def f():\n a=1', 'unused-local', 2, 'a')
61
+ err_test('def f():\n def a():\n pass', 'unused-local', 2, 'a')
62
+
63
+ # Undefined references
64
+ err_test('f()', 'undef', 1, 'f')
65
+ err_test('a', 'undef', 1, 'a')
66
+ err_test('def f():\n a=1; return a\na', 'undef', 3, 'a')
67
+
68
+ # Comprehensions
69
+ ok_test('[x for x in [1,2]]')
70
+ ok_test('[1 for x in [1,2] if x]')
71
+ ok_test('[1 for x in [1,2]]')
72
+ ok_test('def f():\n l=[1,2];[x for x in l]')
73
+ ok_test('def f():\n l=[1,2];{x:True for x in l}')
74
+ err_test('def f():\n [x for x in [1,2]]; return x', 'undef', 2, 'x')
75
+
76
+ # Loops
77
+ ok_test('def f():\n for x in "":\n pass\n return x')
78
+ ok_test('def f():\n for x in "":\n x += 1\n')
79
+ ok_test('def f():\n for x, y in "":\n pass\n return x, y')
80
+ ok_test('for v"var i = 0; i < 1; i++":\n print(i)')
81
+ err_test('def f():\n a = 1\n for a in "":\n a', 'loop-shadowed', 3, 'a', 2)
82
+
83
+ # Semi-colons
84
+ err_test('a=1;;a', 'extra-semicolon', 1, ';')
85
+ err_test('a=1;', 'eol-semicolon', 1, ';')
86
+
87
+ # Builtins
88
+ for k in 'String Symbol this self window Map arguments print len range dir undefined'.split(' '):
89
+ ok_test(k)
90
+
91
+ # noqa
92
+ ok_test('f() # noqa')
93
+ ok_test('f() # noqa:undef')
94
+ err_test('f() # noqa:xxx', 'undef')
95
+
96
+ # Named func in branch
97
+ err_test('if 1:\n def f():\n pass', 'func-in-branch', 2, 'f')
98
+ err_test('if 1:\n pass\nelse:\n def f():\n pass', 'func-in-branch', 4, 'f')
99
+ err_test('try:\n def f():\n pass\nexcept:\n pass', 'func-in-branch', 2, 'f')
100
+ ok_test('if 1:\n a = def():\n pass')
101
+
102
+ # Syntax errors
103
+ err_test('def f(:\n pass', 'syntax-err', 1)
104
+
105
+ # Functions
106
+ ok_test('def f():\n pass\nf()')
107
+
108
+ # Non-locals
109
+ err_test('def a():\n x = 1\n def b():\n nonlocal x\n b()', 'unused-local', 2, 'x')
110
+ ok_test('def a():\n x = 1\n def b():\n nonlocal x\n x\n b()')
111
+ ok_test('def a():\n x = 1\n def b():\n nonlocal x\n x\n x = 2\n b()')
112
+ ok_test('def a():\n x = 1\n def ():\n nonlocal x\n x = 1\n x')
113
+ ok_test('nonlocal a\na()')
114
+
115
+ # Define after use
116
+ err_test('def g():\n f()\n f()\n def f():\n pass', 'def-after-use', 3, 'f')
117
+
118
+ # Decorators
119
+ ok_test('from x import y\n@y\ndef f():\n pass')
120
+
121
+ # try/except
122
+ ok_test('try:\n 1\nexcept Error as e:\n e')
123
+
124
+ # Classes
125
+ ok_test('''
126
+ class A:
127
+
128
+ h = j = 1
129
+ x = h + j
130
+ if True:
131
+ k = 1
132
+ else:
133
+ k = 2
134
+
135
+ def __init__(self, a):
136
+ self.a = a
137
+
138
+ def unused(self):
139
+ pass
140
+ other = unused
141
+
142
+ class B(A):
143
+
144
+ def __init__(self):
145
+ A.__init__(self, 'b')
146
+ ''')
147
+ err_test('class A:\n def a(self):\n a()', 'undef', 3, 'a')
148
+ err_test('class A:\n def a(self):\n pass\n def a(self):\n pass', 'dup-method', 4, 'a')
149
+
150
+ # Object literals
151
+ err_test('{"a":1, "a":2}', 'dup-key', 1, 'a')
152
+
153
+ # keyword arg values
154
+ ok_test('def f():\n a=1\n f(b=a)')
155
+ ok_test('def f():\n a={}\n f(**a)')
156
+
157
+ # with statement
158
+ ok_test('''
159
+ def f():
160
+ a = 1
161
+ with a as b:
162
+ b()
163
+ ''')
164
+ err_test('with a:\n pass', 'undef', '1', 'a')