pureshellcheck 0.2.0__tar.gz → 0.2.1__tar.gz
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.
- {pureshellcheck-0.2.0/src/pureshellcheck.egg-info → pureshellcheck-0.2.1}/PKG-INFO +12 -11
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/README.md +11 -10
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/pyproject.toml +1 -1
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/__init__.py +1 -1
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/analyzer.py +2 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/cli.py +38 -3
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/shast.py +13 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1/src/pureshellcheck.egg-info}/PKG-INFO +12 -11
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/LICENSE +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/MANIFEST.in +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/setup.cfg +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/astlib.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/checks/__init__.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/checks/commands.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/checks/misc.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/checks/quoting.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/checks/variables.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/parser.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/varflow.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck/varscan.py +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck.egg-info/SOURCES.txt +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck.egg-info/dependency_links.txt +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck.egg-info/entry_points.txt +0 -0
- {pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pureshellcheck
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A pure Python reimplementation of ShellCheck's most common checks
|
|
5
5
|
Author: adam2go
|
|
6
6
|
License: MIT
|
|
@@ -157,24 +157,25 @@ no process spawn, no binary. A one-line snippet checks in **~40 µs**
|
|
|
157
157
|
(~25,000 checks/second); throughput on large scripts is ~57k lines/s. CLI
|
|
158
158
|
time is dominated by CPython interpreter startup (~20 ms).
|
|
159
159
|
|
|
160
|
-
**v0.2.
|
|
160
|
+
**v0.2.x vs v0.1.0** (controlled before/after,
|
|
161
161
|
`python tools/bench_compare.py`: baseline wheel from PyPI vs this tree in
|
|
162
162
|
the same interpreter, 25–200 in-process repeats, outputs verified
|
|
163
163
|
identical on every workload):
|
|
164
164
|
|
|
165
|
-
| workload | v0.1.0 | v0.2.
|
|
165
|
+
| workload | v0.1.0 | v0.2.1 | improvement |
|
|
166
166
|
|---|---|---|---|
|
|
167
|
-
| tiny (1 line) | 0.
|
|
168
|
-
| small (75 lines) | 2.
|
|
169
|
-
| medium (263 lines) |
|
|
170
|
-
| large (1216 lines) |
|
|
167
|
+
| tiny (1 line) | 0.058 ms | 0.036 ms | 1.6× |
|
|
168
|
+
| small (75 lines) | 2.44 ms | 1.21 ms | 2.0× |
|
|
169
|
+
| medium (263 lines) | 8.76 ms | 4.48 ms | 2.0× |
|
|
170
|
+
| large (1216 lines) | 46.2 ms | 20.0 ms | **2.3×** |
|
|
171
171
|
|
|
172
|
-
The
|
|
172
|
+
The speedups came from caching the AST child/parent structure and a
|
|
173
173
|
document-order node table (one traversal instead of dozens), making
|
|
174
174
|
variable states immutable tuples so branch snapshots are plain dict
|
|
175
|
-
copies, a banded Levenshtein for SC2153
|
|
176
|
-
reference implementation on 20,000 random
|
|
177
|
-
word/command resolution.
|
|
175
|
+
copies, a leaf-node fast path, a banded Levenshtein for SC2153
|
|
176
|
+
(fuzz-tested against the reference implementation on 20,000 random
|
|
177
|
+
pairs), and memoizing repeated word/command resolution. Package import is
|
|
178
|
+
3.6 ms; remaining CLI latency is CPython interpreter startup.
|
|
178
179
|
|
|
179
180
|
## Compatibility notes
|
|
180
181
|
|
|
@@ -130,24 +130,25 @@ no process spawn, no binary. A one-line snippet checks in **~40 µs**
|
|
|
130
130
|
(~25,000 checks/second); throughput on large scripts is ~57k lines/s. CLI
|
|
131
131
|
time is dominated by CPython interpreter startup (~20 ms).
|
|
132
132
|
|
|
133
|
-
**v0.2.
|
|
133
|
+
**v0.2.x vs v0.1.0** (controlled before/after,
|
|
134
134
|
`python tools/bench_compare.py`: baseline wheel from PyPI vs this tree in
|
|
135
135
|
the same interpreter, 25–200 in-process repeats, outputs verified
|
|
136
136
|
identical on every workload):
|
|
137
137
|
|
|
138
|
-
| workload | v0.1.0 | v0.2.
|
|
138
|
+
| workload | v0.1.0 | v0.2.1 | improvement |
|
|
139
139
|
|---|---|---|---|
|
|
140
|
-
| tiny (1 line) | 0.
|
|
141
|
-
| small (75 lines) | 2.
|
|
142
|
-
| medium (263 lines) |
|
|
143
|
-
| large (1216 lines) |
|
|
140
|
+
| tiny (1 line) | 0.058 ms | 0.036 ms | 1.6× |
|
|
141
|
+
| small (75 lines) | 2.44 ms | 1.21 ms | 2.0× |
|
|
142
|
+
| medium (263 lines) | 8.76 ms | 4.48 ms | 2.0× |
|
|
143
|
+
| large (1216 lines) | 46.2 ms | 20.0 ms | **2.3×** |
|
|
144
144
|
|
|
145
|
-
The
|
|
145
|
+
The speedups came from caching the AST child/parent structure and a
|
|
146
146
|
document-order node table (one traversal instead of dozens), making
|
|
147
147
|
variable states immutable tuples so branch snapshots are plain dict
|
|
148
|
-
copies, a banded Levenshtein for SC2153
|
|
149
|
-
reference implementation on 20,000 random
|
|
150
|
-
word/command resolution.
|
|
148
|
+
copies, a leaf-node fast path, a banded Levenshtein for SC2153
|
|
149
|
+
(fuzz-tested against the reference implementation on 20,000 random
|
|
150
|
+
pairs), and memoizing repeated word/command resolution. Package import is
|
|
151
|
+
3.6 ms; remaining CLI latency is CPython interpreter startup.
|
|
151
152
|
|
|
152
153
|
## Compatibility notes
|
|
153
154
|
|
|
@@ -382,6 +382,8 @@ def apply_directives(findings, directives, nodes, source, positions):
|
|
|
382
382
|
def run_checks(source, shell=None, include_optional=False,
|
|
383
383
|
filename="<stdin>"):
|
|
384
384
|
"""Parse and analyze a script. Returns (findings, parse_error|None)."""
|
|
385
|
+
if source and source[0] == chr(0xFEFF):
|
|
386
|
+
source = source[1:] # tolerate a UTF-8 BOM
|
|
385
387
|
parser = Parser(source)
|
|
386
388
|
try:
|
|
387
389
|
root = parser.parse()
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Command line interface, modeled on shellcheck's."""
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
-
import json
|
|
5
4
|
import sys
|
|
6
5
|
|
|
7
6
|
from . import __version__, run_checks
|
|
@@ -19,6 +18,38 @@ COLORS = {
|
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
|
|
21
|
+
_TAKES_ONE = {"-s", "--shell", "-f", "--format", "-e", "--exclude",
|
|
22
|
+
"-S", "--severity", "-o", "--enable"}
|
|
23
|
+
_COLOR_VALUES = {"auto", "always", "never"}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _reorder(argv):
|
|
27
|
+
"""Let options appear after files, like shellcheck: before Python 3.12,
|
|
28
|
+
argparse stops recognizing options once positionals begin, so
|
|
29
|
+
`pureshellcheck foo.sh -f gcc` would fail there. Deterministically sort
|
|
30
|
+
options to the front."""
|
|
31
|
+
opts, pos = [], []
|
|
32
|
+
i, n = 0, len(argv)
|
|
33
|
+
while i < n:
|
|
34
|
+
a = argv[i]
|
|
35
|
+
if a == "--":
|
|
36
|
+
pos.extend(argv[i + 1:])
|
|
37
|
+
break
|
|
38
|
+
if a.startswith("-") and a != "-":
|
|
39
|
+
take = 2 if a in _TAKES_ONE and i + 1 < n else 1
|
|
40
|
+
if a in ("-C", "--color") and i + 1 < n \
|
|
41
|
+
and argv[i + 1] in _COLOR_VALUES:
|
|
42
|
+
take = 2
|
|
43
|
+
opts.extend(argv[i:i + take])
|
|
44
|
+
i += take
|
|
45
|
+
else:
|
|
46
|
+
pos.append(a)
|
|
47
|
+
i += 1
|
|
48
|
+
if any(p.startswith("-") and p != "-" for p in pos):
|
|
49
|
+
pos.insert(0, "--")
|
|
50
|
+
return opts + pos
|
|
51
|
+
|
|
52
|
+
|
|
22
53
|
def parse_args(argv):
|
|
23
54
|
p = argparse.ArgumentParser(
|
|
24
55
|
prog="pureshellcheck",
|
|
@@ -45,7 +76,7 @@ def parse_args(argv):
|
|
|
45
76
|
help="use color (default: auto)")
|
|
46
77
|
p.add_argument("--version", action="version",
|
|
47
78
|
version="pureshellcheck %s" % __version__)
|
|
48
|
-
return p.parse_args(argv)
|
|
79
|
+
return p.parse_args(_reorder(argv))
|
|
49
80
|
|
|
50
81
|
|
|
51
82
|
def parse_excludes(items):
|
|
@@ -65,7 +96,9 @@ def check_file(path, args, excluded, min_rank):
|
|
|
65
96
|
source = sys.stdin.read()
|
|
66
97
|
name = "-"
|
|
67
98
|
else:
|
|
68
|
-
|
|
99
|
+
# utf-8-sig: tolerate a UTF-8 BOM, which would otherwise break
|
|
100
|
+
# shebang detection
|
|
101
|
+
with open(path, encoding="utf-8-sig", errors="replace") as f:
|
|
69
102
|
source = f.read()
|
|
70
103
|
name = path
|
|
71
104
|
shell = args.shell if args.shell != "busybox" else "ash"
|
|
@@ -148,9 +181,11 @@ def main(argv=None):
|
|
|
148
181
|
else:
|
|
149
182
|
json_items.extend(finding_json(name, f) for f in findings)
|
|
150
183
|
if args.format == "json":
|
|
184
|
+
import json
|
|
151
185
|
json.dump(json_items, out)
|
|
152
186
|
out.write("\n")
|
|
153
187
|
elif args.format == "json1":
|
|
188
|
+
import json
|
|
154
189
|
json.dump({"comments": json_items}, out)
|
|
155
190
|
out.write("\n")
|
|
156
191
|
if had_error:
|
|
@@ -82,15 +82,28 @@ def walk(node):
|
|
|
82
82
|
stack.extend(reversed(children))
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
# Node kinds whose fields can never contain child nodes.
|
|
86
|
+
LEAF_KINDS = frozenset({
|
|
87
|
+
"T_Literal", "T_SingleQuoted", "T_DollarSingleQuoted", "T_Glob",
|
|
88
|
+
"TA_Literal", "TA_Empty", "T_IoDuplicate", "TC_Empty",
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
_EMPTY = ()
|
|
92
|
+
|
|
93
|
+
|
|
85
94
|
def set_parents(root):
|
|
86
95
|
"""Link parents, cache children, and return all nodes in doc order."""
|
|
87
96
|
nodes = []
|
|
88
97
|
append = nodes.append
|
|
89
98
|
stack = [root]
|
|
90
99
|
pop = stack.pop
|
|
100
|
+
leaf = LEAF_KINDS
|
|
91
101
|
while stack:
|
|
92
102
|
n = pop()
|
|
93
103
|
append(n)
|
|
104
|
+
if n.kind in leaf:
|
|
105
|
+
n.children = _EMPTY
|
|
106
|
+
continue
|
|
94
107
|
children = []
|
|
95
108
|
add = children.append
|
|
96
109
|
for value in n.fields.values():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pureshellcheck
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A pure Python reimplementation of ShellCheck's most common checks
|
|
5
5
|
Author: adam2go
|
|
6
6
|
License: MIT
|
|
@@ -157,24 +157,25 @@ no process spawn, no binary. A one-line snippet checks in **~40 µs**
|
|
|
157
157
|
(~25,000 checks/second); throughput on large scripts is ~57k lines/s. CLI
|
|
158
158
|
time is dominated by CPython interpreter startup (~20 ms).
|
|
159
159
|
|
|
160
|
-
**v0.2.
|
|
160
|
+
**v0.2.x vs v0.1.0** (controlled before/after,
|
|
161
161
|
`python tools/bench_compare.py`: baseline wheel from PyPI vs this tree in
|
|
162
162
|
the same interpreter, 25–200 in-process repeats, outputs verified
|
|
163
163
|
identical on every workload):
|
|
164
164
|
|
|
165
|
-
| workload | v0.1.0 | v0.2.
|
|
165
|
+
| workload | v0.1.0 | v0.2.1 | improvement |
|
|
166
166
|
|---|---|---|---|
|
|
167
|
-
| tiny (1 line) | 0.
|
|
168
|
-
| small (75 lines) | 2.
|
|
169
|
-
| medium (263 lines) |
|
|
170
|
-
| large (1216 lines) |
|
|
167
|
+
| tiny (1 line) | 0.058 ms | 0.036 ms | 1.6× |
|
|
168
|
+
| small (75 lines) | 2.44 ms | 1.21 ms | 2.0× |
|
|
169
|
+
| medium (263 lines) | 8.76 ms | 4.48 ms | 2.0× |
|
|
170
|
+
| large (1216 lines) | 46.2 ms | 20.0 ms | **2.3×** |
|
|
171
171
|
|
|
172
|
-
The
|
|
172
|
+
The speedups came from caching the AST child/parent structure and a
|
|
173
173
|
document-order node table (one traversal instead of dozens), making
|
|
174
174
|
variable states immutable tuples so branch snapshots are plain dict
|
|
175
|
-
copies, a banded Levenshtein for SC2153
|
|
176
|
-
reference implementation on 20,000 random
|
|
177
|
-
word/command resolution.
|
|
175
|
+
copies, a leaf-node fast path, a banded Levenshtein for SC2153
|
|
176
|
+
(fuzz-tested against the reference implementation on 20,000 random
|
|
177
|
+
pairs), and memoizing repeated word/command resolution. Package import is
|
|
178
|
+
3.6 ms; remaining CLI latency is CPython interpreter startup.
|
|
178
179
|
|
|
179
180
|
## Compatibility notes
|
|
180
181
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pureshellcheck-0.2.0 → pureshellcheck-0.2.1}/src/pureshellcheck.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|