rapydscript-ns 0.8.4 → 0.9.1
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.
- package/.agignore +1 -1
- package/.github/workflows/ci.yml +38 -38
- package/=template.pyj +5 -5
- package/CHANGELOG.md +26 -0
- package/HACKING.md +103 -103
- package/LICENSE +24 -24
- package/README.md +716 -169
- package/TODO.md +7 -2
- package/add-toc-to-readme +2 -2
- package/bin/export +75 -75
- package/bin/rapydscript +70 -70
- package/bin/web-repl-export +102 -102
- package/build +2 -2
- package/language-service/index.js +36 -27
- package/package.json +1 -1
- package/publish.py +37 -37
- package/release/baselib-plain-pretty.js +2358 -168
- package/release/baselib-plain-ugly.js +73 -3
- package/release/compiler.js +6283 -3093
- package/release/signatures.json +31 -30
- package/session.vim +4 -4
- package/setup.cfg +2 -2
- package/src/ast.pyj +1 -0
- package/src/baselib-builtins.pyj +340 -2
- package/src/baselib-bytes.pyj +664 -0
- package/src/baselib-errors.pyj +1 -1
- package/src/baselib-internal.pyj +267 -60
- package/src/baselib-itertools.pyj +110 -97
- package/src/baselib-str.pyj +22 -4
- package/src/compiler.pyj +36 -36
- package/src/errors.pyj +30 -30
- package/src/lib/abc.pyj +317 -0
- package/src/lib/aes.pyj +646 -646
- package/src/lib/contextlib.pyj +379 -0
- package/src/lib/copy.pyj +120 -120
- package/src/lib/dataclasses.pyj +532 -0
- package/src/lib/datetime.pyj +712 -0
- package/src/lib/elementmaker.pyj +83 -83
- package/src/lib/encodings.pyj +126 -126
- package/src/lib/enum.pyj +125 -0
- package/src/lib/gettext.pyj +569 -569
- package/src/lib/io.pyj +500 -0
- package/src/lib/itertools.pyj +580 -580
- package/src/lib/json.pyj +227 -0
- package/src/lib/math.pyj +193 -193
- package/src/lib/operator.pyj +11 -11
- package/src/lib/pythonize.pyj +20 -20
- package/src/lib/random.pyj +118 -118
- package/src/lib/re.pyj +504 -470
- package/src/lib/react.pyj +74 -74
- package/src/lib/traceback.pyj +63 -63
- package/src/lib/typing.pyj +577 -0
- package/src/lib/uuid.pyj +77 -77
- package/src/monaco-language-service/builtins.js +14 -4
- package/src/monaco-language-service/diagnostics.js +19 -20
- package/src/monaco-language-service/dts.js +550 -550
- package/src/output/classes.pyj +62 -26
- package/src/output/comments.pyj +45 -45
- package/src/output/exceptions.pyj +201 -201
- package/src/output/functions.pyj +78 -5
- package/src/output/jsx.pyj +164 -164
- package/src/output/loops.pyj +5 -2
- package/src/output/operators.pyj +100 -34
- package/src/output/treeshake.pyj +182 -182
- package/src/output/utils.pyj +72 -72
- package/src/parse.pyj +80 -16
- package/src/string_interpolation.pyj +72 -72
- package/src/tokenizer.pyj +10 -5
- package/src/unicode_aliases.pyj +576 -576
- package/src/utils.pyj +192 -192
- package/test/_import_one.pyj +37 -37
- package/test/_import_two/__init__.pyj +11 -11
- package/test/_import_two/level2/deep.pyj +4 -4
- package/test/_import_two/other.pyj +6 -6
- package/test/_import_two/sub.pyj +13 -13
- package/test/abc.pyj +291 -0
- package/test/aes_vectors.pyj +421 -421
- package/test/annotations.pyj +80 -80
- package/test/arithmetic_nostrict.pyj +88 -0
- package/test/arithmetic_types.pyj +169 -0
- package/test/baselib.pyj +91 -0
- package/test/bytes.pyj +467 -0
- package/test/classes.pyj +1 -0
- package/test/comparison_ops.pyj +173 -0
- package/test/contextlib.pyj +362 -0
- package/test/dataclasses.pyj +253 -0
- package/test/datetime.pyj +500 -0
- package/test/debugger_stmt.pyj +41 -0
- package/test/decorators.pyj +77 -77
- package/test/docstrings.pyj +39 -39
- package/test/elementmaker_test.pyj +45 -45
- package/test/enum.pyj +134 -0
- package/test/eval_exec.pyj +56 -0
- package/test/format.pyj +148 -0
- package/test/functions.pyj +151 -151
- package/test/generators.pyj +41 -41
- package/test/generic.pyj +370 -370
- package/test/imports.pyj +72 -72
- package/test/internationalization.pyj +73 -73
- package/test/io.pyj +316 -0
- package/test/json.pyj +196 -0
- package/test/lint.pyj +164 -164
- package/test/loops.pyj +85 -85
- package/test/numpy.pyj +734 -734
- package/test/object.pyj +64 -0
- package/test/omit_function_metadata.pyj +20 -20
- package/test/python_compat.pyj +17 -15
- package/test/python_features.pyj +70 -15
- package/test/regexp.pyj +83 -55
- package/test/repl.pyj +121 -121
- package/test/scoped_flags.pyj +76 -76
- package/test/tuples.pyj +96 -0
- package/test/typing.pyj +469 -0
- package/test/unit/index.js +116 -7
- package/test/unit/language-service-dts.js +543 -543
- package/test/unit/language-service-hover.js +455 -455
- package/test/unit/language-service.js +84 -0
- package/test/unit/web-repl.js +1337 -1
- package/test/vars_locals_globals.pyj +94 -0
- package/tools/cli.js +558 -547
- package/tools/compile.js +224 -219
- package/tools/completer.js +131 -131
- package/tools/embedded_compiler.js +262 -251
- package/tools/gettext.js +185 -185
- package/tools/ini.js +65 -65
- package/tools/lint.js +16 -19
- package/tools/msgfmt.js +187 -187
- package/tools/repl.js +223 -223
- package/tools/test.js +118 -118
- package/tools/utils.js +128 -128
- package/tools/web_repl.js +95 -95
- package/try +41 -41
- package/web-repl/env.js +196 -196
- package/web-repl/index.html +163 -163
- package/web-repl/main.js +252 -252
- package/web-repl/prism.css +139 -139
- package/web-repl/prism.js +113 -113
- package/web-repl/rapydscript.js +224 -224
- package/web-repl/sha1.js +25 -25
- package/PYTHON_DIFFERENCES_REPORT.md +0 -291
- package/PYTHON_FEATURE_COVERAGE.md +0 -200
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')
|