pll-python 0.1.2 → 0.4.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 (5) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +64 -14
  3. package/cli.cjs +4446 -1074
  4. package/package.json +5 -3
  5. package/worker.cjs +825 -1156
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2026 Daniel Patterson.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -11,11 +11,13 @@ Needs **Node 22 or newer** (the oldest Node still receiving support).
11
11
  npx pll-python hw.py
12
12
  ```
13
13
 
14
+ (Not `npx pll`, which is a different package.)
15
+
14
16
  Or install it:
15
17
 
16
18
  ```bash
17
19
  npm install -g pll-python
18
- pll hw.py
20
+ pll hw.py # or: pll-python hw.py
19
21
  ```
20
22
 
21
23
  ## Language levels
@@ -41,25 +43,31 @@ same way everywhere, which is the point of putting it in the file.
41
43
 
42
44
  ## Tests
43
45
 
44
- `test_*` functions in the same file run before the file does, as they do in
45
- the editor:
46
+ `test_*` functions in the same file run once the program finishes, against
47
+ what it defined, as they do in the editor. A test that prints shows what it
48
+ printed under its result; `@pytest.mark.skip`, `skipif` and `xfail` work as
49
+ in pytest:
46
50
 
47
51
  ```bash
48
- pll hw.py # tests, then the program
52
+ pll hw.py # the program, then its tests
49
53
  pll hw.py --no-tests # just the program
50
54
  ```
51
55
 
52
56
  ## Options
53
57
 
54
58
  ```
55
- --no-tests do not run the file's test_* functions first
59
+ --no-tests do not run the file's test_* functions, which
60
+ otherwise run once the program finishes
56
61
  --save-images <dir> write pictures there as .svg
57
- -q, --quiet only the program's own output
62
+ -q, --quiet only the program's own output and what went wrong:
63
+ errors, failed tests, files not loaded or not saved
58
64
  --no-color never use ANSI colour
59
65
  -h, --help
60
- -v, --version
66
+ -V, --version
61
67
  ```
62
68
 
69
+ `-v` is not an option: Python's `-v` means something else entirely.
70
+
63
71
  ## Authoring Examplar bundles
64
72
 
65
73
  Examplar assesses a *test suite* rather than an implementation: students
@@ -147,6 +155,11 @@ Publish the bundle at a URL and point students at it from their file:
147
155
  #examplar https://cs2000.example/hw3.json
148
156
  ```
149
157
 
158
+ The check runs wherever the file does - in the editor, and with `pll
159
+ hw3.py`, which prints the same cards to stderr. Fetched bundles are cached
160
+ (under `$PLL_CACHE_DIR`, `$XDG_CACHE_HOME` or `~/.cache`), so a run without a
161
+ network still gets its verdict. The verdict does not change the exit code.
162
+
150
163
  If any of your students use **vscode.dev** or a codespace, the extension host
151
164
  there is a browser, so serve the bundle with CORS
152
165
  (`samples/examplar_serve.mjs` in the repository is a dependency-free server
@@ -188,14 +201,22 @@ be fast and honest rather than secret.
188
201
  | Code | Meaning |
189
202
  | --- | --- |
190
203
  | 0 | Ran, and any tests passed |
191
- | 1 | The program raised |
204
+ | 1 | The program raised, or Ctrl+C stopped it (even if it caught the `KeyboardInterrupt`; its tests are then not run) |
192
205
  | 2 | Level checks found problems, so it was not run |
193
206
  | 3 | A test failed |
194
- | 64 | Bad usage, or PLL could not start |
207
+ | 64 | Bad usage, or Python could not start (it is given two minutes) |
208
+ | 130 | A second Ctrl+C gave up waiting for the program to stop |
209
+ | 141 | Its output could no longer be read - `pll hw.py \| head` |
210
+ | 143 | It was ended by SIGTERM |
195
211
 
196
212
  Distinct codes so an autograder can tell "the level rejected this" from
197
213
  "the tests failed" from "it crashed".
198
214
 
215
+ A program that ends itself with `sys.exit(n)` exits with `n` instead, as it
216
+ would under `python` - so a program can produce any of these codes itself.
217
+ `sys.exit()` is 0, and `sys.exit("message")` prints the message and is 1.
218
+ A status other than 0 outranks a failed test's 3.
219
+
199
220
  ## Piping
200
221
 
201
222
  The program's own stdout is the **only** thing on stdout. Everything
@@ -206,22 +227,29 @@ goes to stderr. So this captures exactly what the program printed:
206
227
  pll hw.py > output.txt
207
228
  ```
208
229
 
209
- `input()` reads stdin, so piping works too:
230
+ `input()` and `sys.stdin.read()` read stdin, exactly as given, so piping
231
+ works too:
210
232
 
211
233
  ```bash
212
234
  printf 'Ada\n' | pll greet.py
213
235
  ```
214
236
 
237
+ Ctrl+C stops the program wherever it is - waiting for input, in
238
+ `time.sleep`, or waiting for an address to answer - as it would under
239
+ `python`.
240
+
215
241
  ## What differs from the editor
216
242
 
217
243
  - **Pictures cannot be drawn in a terminal.** Each one prints a note with
218
- its size; `--save-images` writes them as `.svg` instead.
244
+ its size; `--save-images` writes them as `.svg` instead. A matplotlib
245
+ figure is a picture like any other: `plt.show()` prints the note.
219
246
  - **Reactors (`big_bang`, `animate`) do not run.** They need the editor's
220
247
  interactions panel to animate; here they print a note and the rest of the
221
248
  program continues. Their logic is still testable — `simulate_trace(n)`
222
249
  works fine and needs no clock.
223
250
  - **Tables do print**, as text. Their content is already text, so there is
224
- nothing to lose.
251
+ nothing to lose; a tab, a new line or an escape in a cell is written out,
252
+ as `\t`, `\n` and `\x1b`.
225
253
 
226
254
  Everything else is the same code: the same Pyodide worker, the same Python
227
255
  libraries, the same analyzers and the same wording for errors.
@@ -229,8 +257,30 @@ libraries, the same analyzers and the same wording for errors.
229
257
  ## Files next to your program
230
258
 
231
259
  `open("data.csv")` and `pd.read_csv("data.csv")` read files in the same
232
- folder as the script, and files the program writes appear there afterwards —
233
- the same as in the editor.
260
+ folder as the script or a folder inside it (`open("data/2024.csv")`), and
261
+ `__file__` is set, so `Path(__file__).parent` works. Files the program
262
+ writes appear there afterwards, and files it deletes are deleted — the same
263
+ as in the editor, with the same limits: at most 100 files, each at most
264
+ 2 MB and 8 MB in all, nearest first; hidden and tools' folders (`.git`,
265
+ `venv`, `node_modules`) are left out. Files move as bytes, so a CSV in
266
+ another encoding or a picture arrives exactly as it is.
267
+
268
+ What is not loaded or not saved is said, even with `-q`, with why. A
269
+ file is never saved over when the program was not given it (it was over a
270
+ limit, say: saving would replace it with only what the program wrote), when
271
+ it changed on disk while the program ran, or when it is an existing `.py`.
272
+
273
+ ## Packages
274
+
275
+ `import pandas`, `numpy`, `matplotlib`, `requests`, pytest (for the tests)
276
+ and the rest of Pyodide's packages are downloaded the first time they are
277
+ used, which needs the network; `pll` says so. They are found from the
278
+ program's imports wherever they are written, and from those of the files of
279
+ yours it imports. A URL read with `urllib`, `requests` or pandas arrives
280
+ byte for byte; an error page raises `HTTPError`, and an address that does
281
+ not answer gives up after 60 seconds, or the program's own `timeout`. They are kept beside Pyodide in the install, or in your cache
282
+ (`$XDG_CACHE_HOME/pll-python` or `~/.cache/pll-python`) when the install
283
+ cannot be written to.
234
284
 
235
285
  ## Licence
236
286