pll-python 0.5.1 → 0.6.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.
- package/README.md +5 -4
- package/cli.cjs +30 -15
- package/package.json +1 -1
- package/worker.cjs +17 -15
package/README.md
CHANGED
|
@@ -34,9 +34,9 @@ print(greeting)
|
|
|
34
34
|
| Line in the file | What it does |
|
|
35
35
|
| --- | --- |
|
|
36
36
|
| `#level raw` | Nothing checked. Plain Python plus PLL's libraries. This is what you get with no line at all. |
|
|
37
|
-
| `#level beginner` | Warns about reassigning a variable, hiding another name (a built-in like `list`, or one of PLL's own like `circle`),
|
|
37
|
+
| `#level beginner` | Warns about reassigning a variable, hiding another name (a built-in like `list`, or one of PLL's own like `circle`), `global` / `nonlocal`, and removing a name with `del` (not an item: `del d[key]` is fine). Type annotations are checked as the program runs. If it finds a problem, the file does **not** run. |
|
|
38
38
|
| `#level intermediate` | Same, but reassignment is allowed inside a function. |
|
|
39
|
-
| `#level advanced` |
|
|
39
|
+
| `#level advanced` | One check before the run: names used where they have no value, which every level but `raw` makes. Annotations still checked, by Python's own rules. |
|
|
40
40
|
|
|
41
41
|
There is deliberately **no flag to override the level**. A file behaves the
|
|
42
42
|
same way everywhere, which is the point of putting it in the file.
|
|
@@ -46,7 +46,8 @@ same way everywhere, which is the point of putting it in the file.
|
|
|
46
46
|
`test_*` functions in the same file run once the program finishes, against
|
|
47
47
|
what it defined, as they do in the editor. A test that prints shows what it
|
|
48
48
|
printed under its result; `@pytest.mark.skip`, `skipif` and `xfail` work as
|
|
49
|
-
in pytest:
|
|
49
|
+
in pytest. A test written with parameters is not run: what is wrong with it
|
|
50
|
+
is said above `Tests:`, apart from the tests that ran.
|
|
50
51
|
|
|
51
52
|
```bash
|
|
52
53
|
pll hw.py # the program, then its tests
|
|
@@ -203,7 +204,7 @@ be fast and honest rather than secret.
|
|
|
203
204
|
| 0 | Ran, and any tests passed |
|
|
204
205
|
| 1 | The program raised, or Ctrl+C stopped it (even if it caught the `KeyboardInterrupt`; its tests are then not run) |
|
|
205
206
|
| 2 | Level checks found problems, so it was not run |
|
|
206
|
-
| 3 | A test failed |
|
|
207
|
+
| 3 | A test failed, or could not be run (it takes parameters) |
|
|
207
208
|
| 64 | Bad usage, or Python could not start (it is given two minutes) |
|
|
208
209
|
| 130 | A second Ctrl+C gave up waiting for the program to stop |
|
|
209
210
|
| 141 | Its output could no longer be read - `pll hw.py \| head` |
|
package/cli.cjs
CHANGED
|
@@ -137,19 +137,17 @@ var HEADER_RE = /^#\s*level\s+([a-z]+)\s*$/;
|
|
|
137
137
|
function parseLevel(source) {
|
|
138
138
|
const lines = source.split(/\r?\n/);
|
|
139
139
|
for (const raw of lines) {
|
|
140
|
-
|
|
141
|
-
if (line.length === 0) {
|
|
140
|
+
if (raw.trim().length === 0) {
|
|
142
141
|
continue;
|
|
143
142
|
}
|
|
144
|
-
|
|
145
|
-
if (!match) {
|
|
146
|
-
return DEFAULT_LEVEL;
|
|
147
|
-
}
|
|
148
|
-
const name = match[1];
|
|
149
|
-
return isLevel(name) ? name : DEFAULT_LEVEL;
|
|
143
|
+
return headerLevel(raw) ?? DEFAULT_LEVEL;
|
|
150
144
|
}
|
|
151
145
|
return DEFAULT_LEVEL;
|
|
152
146
|
}
|
|
147
|
+
function headerLevel(line) {
|
|
148
|
+
const match = HEADER_RE.exec(line.trim());
|
|
149
|
+
return match !== null && isLevel(match[1]) ? match[1] : null;
|
|
150
|
+
}
|
|
153
151
|
function levelHeaderProblem(source) {
|
|
154
152
|
const lines = source.split(/\r?\n/);
|
|
155
153
|
const valid = new RegExp(`^#\\s*level\\s+(?:${LEVEL_NAMES.join("|")})\\s*$`);
|
|
@@ -274,7 +272,7 @@ function closestLevel(named) {
|
|
|
274
272
|
return best !== null && bestDistance <= Math.max(2, Math.floor(best.length / 3)) ? best : null;
|
|
275
273
|
}
|
|
276
274
|
function levelHasStaticChecks(level) {
|
|
277
|
-
return level
|
|
275
|
+
return level !== LEVEL_RAW;
|
|
278
276
|
}
|
|
279
277
|
|
|
280
278
|
// src/run/finding.ts
|
|
@@ -303,11 +301,13 @@ function findingLocation(finding) {
|
|
|
303
301
|
};
|
|
304
302
|
}
|
|
305
303
|
function formatFriendlyError(finding) {
|
|
304
|
+
return serializedFindingLines(serializeFinding(finding));
|
|
305
|
+
}
|
|
306
|
+
function serializedFindingLines(finding) {
|
|
306
307
|
const lines = [];
|
|
307
308
|
lines.push(`${finding.errorType}: ${finding.headline}`);
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
lines.push(` at ${location.label}`);
|
|
309
|
+
if (finding.location) {
|
|
310
|
+
lines.push(` at ${finding.location.label}`);
|
|
311
311
|
}
|
|
312
312
|
if (finding.howToFix.length > 0) {
|
|
313
313
|
lines.push("");
|
|
@@ -345,7 +345,12 @@ function explainTestReport(event, fileName, level) {
|
|
|
345
345
|
...event,
|
|
346
346
|
tests: event.tests.map(
|
|
347
347
|
({ error, ...test }) => error ? { ...test, finding: serializeFinding(findRuntimeFinding(fileName, level, error)) } : test
|
|
348
|
-
)
|
|
348
|
+
),
|
|
349
|
+
...event.malformed ? {
|
|
350
|
+
malformed: event.malformed.map(
|
|
351
|
+
({ problem, ...test }) => problem ? { ...test, finding: serializeFinding({ ...problem, fileName: problem.fileName ?? fileName, level }) } : test
|
|
352
|
+
)
|
|
353
|
+
} : {}
|
|
349
354
|
};
|
|
350
355
|
}
|
|
351
356
|
|
|
@@ -1273,7 +1278,7 @@ var Tally = class {
|
|
|
1273
1278
|
} else if (event.kind === "testReport") {
|
|
1274
1279
|
this.testsRan = true;
|
|
1275
1280
|
this.testsStopped = event.stopped === true;
|
|
1276
|
-
this.testFailures += event.failed + event.errors;
|
|
1281
|
+
this.testFailures += event.failed + event.errors + (event.malformed?.length ?? 0);
|
|
1277
1282
|
} else if (event.kind === "done") {
|
|
1278
1283
|
if (event.exitCode !== void 0) this.exitCode = event.exitCode;
|
|
1279
1284
|
if (event.stopped) this.stopReached = true;
|
|
@@ -2338,6 +2343,16 @@ var CliView = class {
|
|
|
2338
2343
|
}
|
|
2339
2344
|
}
|
|
2340
2345
|
testReport(event) {
|
|
2346
|
+
for (const test of event.malformed ?? []) {
|
|
2347
|
+
if (test.finding) {
|
|
2348
|
+
const lines = serializedFindingLines(test.finding);
|
|
2349
|
+
this.problem(this.red(lines[0]));
|
|
2350
|
+
for (const line of lines.slice(1)) {
|
|
2351
|
+
this.problem(line);
|
|
2352
|
+
}
|
|
2353
|
+
this.problem("");
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2341
2356
|
const bad = event.failed + event.errors;
|
|
2342
2357
|
const parts = [
|
|
2343
2358
|
...event.passed ? [`${event.passed} passed`] : [],
|
|
@@ -2566,7 +2581,7 @@ ${USAGE_HINT}
|
|
|
2566
2581
|
return EXIT.ok;
|
|
2567
2582
|
}
|
|
2568
2583
|
if (args.version) {
|
|
2569
|
-
process.stdout.write("0.
|
|
2584
|
+
process.stdout.write("0.6.0\n");
|
|
2570
2585
|
return EXIT.ok;
|
|
2571
2586
|
}
|
|
2572
2587
|
if (args.error !== void 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pll-python",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Run Python with PLL's language levels from the command line: level checks, in-file tests, friendly errors and the built-in image and table libraries, all on Pyodide. No Python install needed.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|