hoodscript 1.1.0__tar.gz → 1.2.0__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.
- {hoodscript-1.1.0 → hoodscript-1.2.0}/CHANGELOG.md +27 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/PKG-INFO +10 -1
- {hoodscript-1.1.0 → hoodscript-1.2.0}/README.md +2 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/SECURITY.md +4 -2
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/onboarding.md +30 -2
- hoodscript-1.2.0/examples/quickstart.ipynb +142 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/pyproject.toml +5 -1
- hoodscript-1.2.0/src/hoodscript/__init__.py +16 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/_version.py +2 -2
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/cli.py +31 -1
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/errors/translator.py +4 -1
- hoodscript-1.2.0/src/hoodscript/kernel/__init__.py +12 -0
- hoodscript-1.2.0/src/hoodscript/kernel/__main__.py +13 -0
- hoodscript-1.2.0/src/hoodscript/kernel/installer.py +54 -0
- hoodscript-1.2.0/src/hoodscript/kernel/kernel.py +292 -0
- hoodscript-1.2.0/src/hoodscript/kernel/magics.py +104 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/traceback_handler.py +1 -1
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/test_exec_sites.py +1 -1
- hoodscript-1.2.0/tests/test_kernel.py +159 -0
- hoodscript-1.2.0/tests/test_kernel_zmq.py +88 -0
- hoodscript-1.1.0/src/hoodscript/__init__.py +0 -9
- {hoodscript-1.1.0 → hoodscript-1.2.0}/.gitignore +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/CODE_OF_CONDUCT.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/CONTRIBUTING.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/LICENSE +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/SPRINT_PLAN.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/adr/0001-token-pipeline-over-parser.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/adr/0002-keyword-reconciliation.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/adr/0003-inclusive-ranges.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/adr/README.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/archive/HOODSCRIPT_COMPLETE_MASTER_SYSTEM.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/archive/HOODSCRIPT_FULL_ENGINEERING_SUITE.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/archive/HOODSCRIPT_UNSPRED_FEATURES_ROADMAP.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/curriculum.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/docs/keywords.md +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/out.txt +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/playground/app.js +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/playground/bundle.js +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/playground/examples.js +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/playground/hoodscript-latest-py3-none-any.whl +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/playground/index.html +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/playground/style.css +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/playground/worker.js +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/scripts/build_playground.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/scripts/gen_keywords.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/__main__.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/cache.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/constants.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/debugger.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/errors/__init__.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/errors/catalog.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/errors/renderer.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/formatter.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/importer.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/linter.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/lsp.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/migrator.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/patterns.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/repl.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/sandbox.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/stubs.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/transpiler.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/src/hoodscript/tutor.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/conftest.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/deep_nesting.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/fork_bomb.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/huge_literal.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/import_escapes.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/infinite_recursion.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/open_file.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/pathological_indent.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/runaway_output.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/corpus/runaway_time.hs +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/test_corpus.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/test_fuzz.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/security/test_sandbox.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_cli.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_conformance.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_debugger.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_docs.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_errors.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_fmt.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_grammar_canonical.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_importer.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_keywords_doc.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_learn.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_lint.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_lsp_features.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_patterns.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_playground.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_release.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_repl.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_transpiler.py +0 -0
- {hoodscript-1.1.0 → hoodscript-1.2.0}/tests/test_vscode_extension.py +0 -0
|
@@ -3,6 +3,32 @@
|
|
|
3
3
|
All notable changes to HoodScript. Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
4
4
|
Versioning: the keyword set is the public API; changing it is at least a minor bump.
|
|
5
5
|
|
|
6
|
+
## [1.2.0] — 2026-09-11
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **Interactive Jupyter Notebook Kernel & IPython Magics** (`src/hoodscript/kernel/`, `examples/quickstart.ipynb`):
|
|
11
|
+
- Dedicated standalone Jupyter kernel (`hoodscript-kernel` / `HoodScriptKernel`) subclassing `ipykernel.kernelbase.Kernel`.
|
|
12
|
+
- Automatic 1:1 transpilation of notebook cells to Python prior to execution in the kernel's persistent namespace.
|
|
13
|
+
- Rich HTML plain-English JPE error cards rendered in-cell with collapsible raw Python tracebacks.
|
|
14
|
+
- Dynamic tab autocompletion over HoodScript keywords, patterns, exception names, and namespace variables.
|
|
15
|
+
- Cell and line inspection magics: `%hood_transpile` (preview generated Python without executing) and `%hood_tb` (toggle raw traceback view).
|
|
16
|
+
- IPython extension (`%load_ext hoodscript`) providing `%%hood` and `%%hood_transpile` for hybrid Python/HoodScript notebooks and Google Colab.
|
|
17
|
+
- CLI installer subcommand: `hoodscript kernel install [--user] [--prefix PREFIX]`.
|
|
18
|
+
- Interactive starter notebook: `examples/quickstart.ipynb`.
|
|
19
|
+
- Optional dependency extra: `pip install hoodscript[jupyter]`.
|
|
20
|
+
- QA (audited end to end over ZMQ with `jupyter_client` before acceptance; four
|
|
21
|
+
defects fixed): `holla` output never reached the cell (the base `Kernel`
|
|
22
|
+
never tells ipykernel's stdout stream which cell is running — `set_parent`
|
|
23
|
+
now does); a trailing bare expression displayed nothing (now shown as the
|
|
24
|
+
result, like IPython); crash cards showed the *Python* line (`def f()`) and,
|
|
25
|
+
for syntax errors, a stdlib `ast.py` frame (cells are registered in
|
|
26
|
+
`linecache` as `<notebook>`, a program pseudo-file; syntax errors carry no
|
|
27
|
+
frames); `%load_ext hoodscript` as documented did not work (only
|
|
28
|
+
`hoodscript.kernel` did) and `examples/quickstart.ipynb` had no kernelspec
|
|
29
|
+
metadata. `tests/test_kernel_zmq.py` drives the real kernel process.
|
|
30
|
+
|
|
31
|
+
|
|
6
32
|
## [1.1.0] — 2026-09-11
|
|
7
33
|
|
|
8
34
|
The reconciled language. Every keyword is now either cited in
|
|
@@ -179,5 +205,6 @@ PEP 552 bytecode cache, CLI, REPL, crash reports with `*Trip` names,
|
|
|
179
205
|
`py2hood` / `hood2py`, stub generator, pygls language server (diagnostics,
|
|
180
206
|
hover, completion). Keyword set later found to be uncited — see v1.1.0.
|
|
181
207
|
|
|
208
|
+
[1.2.0]: https://github.com/khaoticdev62/hoodscript/compare/v1.1.0...v1.2.0
|
|
182
209
|
[1.1.0]: https://github.com/khaoticdev62/hoodscript/compare/bf801ab...v1.1.0
|
|
183
210
|
[1.0.0]: https://github.com/khaoticdev62/hoodscript/commits/bf801ab
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hoodscript
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: A production-grade Python 3 conlang based on AAVE with 1:1 AST parity.
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Requires-Python: >=3.10
|
|
8
8
|
Provides-Extra: all
|
|
9
|
+
Requires-Dist: ipykernel>=6.0.0; extra == 'all'
|
|
10
|
+
Requires-Dist: ipython>=8.0.0; extra == 'all'
|
|
9
11
|
Requires-Dist: jedi>=0.19.1; extra == 'all'
|
|
10
12
|
Requires-Dist: mypy>=1.9.0; extra == 'all'
|
|
11
13
|
Requires-Dist: prompt-toolkit>=3.0.40; extra == 'all'
|
|
@@ -16,6 +18,8 @@ Provides-Extra: dev
|
|
|
16
18
|
Requires-Dist: build>=1.1.0; extra == 'dev'
|
|
17
19
|
Requires-Dist: debugpy>=1.8.0; extra == 'dev'
|
|
18
20
|
Requires-Dist: hatch-vcs>=0.4.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: ipykernel>=6.0.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: ipython>=8.0.0; extra == 'dev'
|
|
19
23
|
Requires-Dist: jedi>=0.19.1; extra == 'dev'
|
|
20
24
|
Requires-Dist: mypy>=1.9.0; extra == 'dev'
|
|
21
25
|
Requires-Dist: prompt-toolkit>=3.0.40; extra == 'dev'
|
|
@@ -24,6 +28,9 @@ Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
|
|
|
24
28
|
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
25
29
|
Requires-Dist: rich>=13.7; extra == 'dev'
|
|
26
30
|
Requires-Dist: ruff>=0.3.0; extra == 'dev'
|
|
31
|
+
Provides-Extra: jupyter
|
|
32
|
+
Requires-Dist: ipykernel>=6.0.0; extra == 'jupyter'
|
|
33
|
+
Requires-Dist: ipython>=8.0.0; extra == 'jupyter'
|
|
27
34
|
Provides-Extra: lsp
|
|
28
35
|
Requires-Dist: jedi>=0.19.1; extra == 'lsp'
|
|
29
36
|
Requires-Dist: pygls<2,>=1.3.1; extra == 'lsp'
|
|
@@ -96,6 +103,8 @@ with `PYTHONPATH=src` and use `python3 -m hoodscript` instead of `hoodscript`.
|
|
|
96
103
|
hoodscript hello.hs # transpile + execute
|
|
97
104
|
hoodscript -c hello.hs # print the Python it becomes
|
|
98
105
|
hoodscript repl --mirror # interactive REPL (hood> prompt; chill to exit; --mirror shows the Python)
|
|
106
|
+
hoodscript playground # launch in-browser Pyodide WebAssembly playground
|
|
107
|
+
hoodscript kernel install # Jupyter kernel (pip install "hoodscript[jupyter]"); or %load_ext hoodscript
|
|
99
108
|
hoodscript fmt|lint <file.hs> # formatter / linter (pip install "hoodscript[tools]")
|
|
100
109
|
hoodscript learn [topic] # interactive tutor driving docs/curriculum.md
|
|
101
110
|
hoodscript # a short tour of all commands
|
|
@@ -58,6 +58,8 @@ with `PYTHONPATH=src` and use `python3 -m hoodscript` instead of `hoodscript`.
|
|
|
58
58
|
hoodscript hello.hs # transpile + execute
|
|
59
59
|
hoodscript -c hello.hs # print the Python it becomes
|
|
60
60
|
hoodscript repl --mirror # interactive REPL (hood> prompt; chill to exit; --mirror shows the Python)
|
|
61
|
+
hoodscript playground # launch in-browser Pyodide WebAssembly playground
|
|
62
|
+
hoodscript kernel install # Jupyter kernel (pip install "hoodscript[jupyter]"); or %load_ext hoodscript
|
|
61
63
|
hoodscript fmt|lint <file.hs> # formatter / linter (pip install "hoodscript[tools]")
|
|
62
64
|
hoodscript learn [topic] # interactive tutor driving docs/curriculum.md
|
|
63
65
|
hoodscript # a short tour of all commands
|
|
@@ -50,14 +50,16 @@ To protect host environments against runaway workloads, the sandbox enforces thr
|
|
|
50
50
|
|
|
51
51
|
## 4. Code Execution Audit
|
|
52
52
|
|
|
53
|
-
`exec`/`eval` appear in exactly
|
|
53
|
+
`exec`/`eval` appear in exactly six places, all on code objects produced by
|
|
54
54
|
`compile()` from the transpiler's output of the user's own source — never on
|
|
55
55
|
text from anywhere else:
|
|
56
56
|
1. `src/hoodscript/cli.py` — running a file
|
|
57
57
|
2. `src/hoodscript/repl.py` — the interactive session (`eval` first, `exec` fallback)
|
|
58
58
|
3. `src/hoodscript/debugger.py` — running a file under debugpy
|
|
59
59
|
4. `src/hoodscript/tutor.py` — running a curriculum lesson
|
|
60
|
-
`
|
|
60
|
+
5. `src/hoodscript/kernel/kernel.py` — executing notebook cells in the HoodScript kernel
|
|
61
|
+
6. `src/hoodscript/kernel/magics.py` — executing `%%hood` cells in IPython / Google Colab
|
|
62
|
+
`tests/security/test_exec_sites.py` fails if a seventh appears.
|
|
61
63
|
|
|
62
64
|
### Why this is safe and equivalent to `compile()`:
|
|
63
65
|
- `transpile()` performs strictly lexical substitution over Python's `tokenize.tokenize` stream and deterministic character-preserving pattern transforms (Rules R1–R12).
|
|
@@ -219,14 +219,42 @@ Speaks the Language Server Protocol over stdio. Provides:
|
|
|
219
219
|
Point any LSP-capable editor at that command for the `hoodscript` language ID.
|
|
220
220
|
A VS Code extension manifest lives in `editors/vscode/`.
|
|
221
221
|
|
|
222
|
-
## 11.
|
|
222
|
+
## 11. Jupyter Notebooks & Google Colab
|
|
223
|
+
|
|
224
|
+
Use HoodScript interactively inside JupyterLab, classic Notebooks, or Google Colab:
|
|
225
|
+
|
|
226
|
+
### Option A: Dedicated Jupyter Kernel
|
|
227
|
+
```bash
|
|
228
|
+
pip install hoodscript[jupyter]
|
|
229
|
+
hoodscript kernel install
|
|
230
|
+
jupyter lab
|
|
231
|
+
```
|
|
232
|
+
Select the **HoodScript** kernel from the launcher. Every cell executes native HoodScript with tab completion and rich plain-English JPE error cards.
|
|
233
|
+
|
|
234
|
+
### Option B: Google Colab & Existing Python Notebooks
|
|
235
|
+
In the first cell:
|
|
236
|
+
```python
|
|
237
|
+
!pip install hoodscript[jupyter]
|
|
238
|
+
%load_ext hoodscript
|
|
239
|
+
```
|
|
240
|
+
Now write HoodScript in any cell using `%%hood`:
|
|
241
|
+
```ipython
|
|
242
|
+
%%hood
|
|
243
|
+
bet calculate(x):
|
|
244
|
+
dip x * 10
|
|
245
|
+
|
|
246
|
+
holla "Result:", calculate(4.2)
|
|
247
|
+
```
|
|
248
|
+
Preview the generated Python anytime with `%%hood_transpile`.
|
|
249
|
+
|
|
250
|
+
## 12. Run the tests
|
|
223
251
|
|
|
224
252
|
```bash
|
|
225
253
|
pytest # with the venv
|
|
226
254
|
PYTHONPATH=src pytest tests/ # without an editable install
|
|
227
255
|
```
|
|
228
256
|
|
|
229
|
-
##
|
|
257
|
+
## 13. Where to go next
|
|
230
258
|
|
|
231
259
|
- [`curriculum.md`](curriculum.md) — ten lessons covering the whole language
|
|
232
260
|
- [`../agents.md`](../agents.md) — how the transpiler, importer, cache, and
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"metadata": {},
|
|
6
|
+
"source": [
|
|
7
|
+
"# HoodScript Interactive Quickstart Notebook\n",
|
|
8
|
+
"\n",
|
|
9
|
+
"Welcome to **HoodScript** in Jupyter! HoodScript maps authentic AAVE keywords **1:1 to Python 3** and explains every error in **plain conversational English**.\n",
|
|
10
|
+
"\n",
|
|
11
|
+
"### Two Ways to Use HoodScript in Notebooks:\n",
|
|
12
|
+
"1. **Native HoodScript Kernel**: Select `HoodScript` from the kernel dropdown.\n",
|
|
13
|
+
"2. **IPython Magic**: In a standard Python notebook or Google Colab, run `%load_ext hoodscript` and use `%%hood` at the top of cells."
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"cell_type": "code",
|
|
18
|
+
"execution_count": null,
|
|
19
|
+
"metadata": {},
|
|
20
|
+
"outputs": [],
|
|
21
|
+
"source": [
|
|
22
|
+
"# Lesson 1: Values, Booleans, and holla\n",
|
|
23
|
+
"name = \"Khris\"\n",
|
|
24
|
+
"age = 28\n",
|
|
25
|
+
"verified = no cap # True\n",
|
|
26
|
+
"fake = cap # False\n",
|
|
27
|
+
"\n",
|
|
28
|
+
"holla \"User:\", name, \"Age:\", age, \"Verified:\", verified"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"cell_type": "markdown",
|
|
33
|
+
"metadata": {},
|
|
34
|
+
"source": [
|
|
35
|
+
"### Live Transpilation Inspection\n",
|
|
36
|
+
"HoodScript adheres strictly to the **1:1 Law**: every line of HoodScript corresponds to valid Python with preserved line numbers.\n",
|
|
37
|
+
"Use `%hood_transpile` to inspect the generated Python code:"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"cell_type": "code",
|
|
42
|
+
"execution_count": null,
|
|
43
|
+
"metadata": {},
|
|
44
|
+
"outputs": [],
|
|
45
|
+
"source": [
|
|
46
|
+
"%hood_transpile\n",
|
|
47
|
+
"be i in 1..5:\n",
|
|
48
|
+
" if i == 3:\n",
|
|
49
|
+
" skip\n",
|
|
50
|
+
" holla \"Lap:\", i"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"cell_type": "markdown",
|
|
55
|
+
"metadata": {},
|
|
56
|
+
"source": [
|
|
57
|
+
"### Loops and Inclusive Ranges: `be` and `1..n`\n",
|
|
58
|
+
"`be x in xs` represents habitual action (Python's `for x in xs`). `1..5` is an inclusive range (1, 2, 3, 4, 5)."
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"cell_type": "code",
|
|
63
|
+
"execution_count": null,
|
|
64
|
+
"metadata": {},
|
|
65
|
+
"outputs": [],
|
|
66
|
+
"source": [
|
|
67
|
+
"total = 0\n",
|
|
68
|
+
"be i in 1..10:\n",
|
|
69
|
+
" total = total + i\n",
|
|
70
|
+
"\n",
|
|
71
|
+
"holla \"Sum of 1..10 is:\", total"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"cell_type": "markdown",
|
|
76
|
+
"metadata": {},
|
|
77
|
+
"source": [
|
|
78
|
+
"### Functions and Classes: `bet`, `dip`, and `fam`\n",
|
|
79
|
+
"`bet` defines a function; `dip` returns with a value; `fam` defines a class."
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"cell_type": "code",
|
|
84
|
+
"execution_count": null,
|
|
85
|
+
"metadata": {},
|
|
86
|
+
"outputs": [],
|
|
87
|
+
"source": [
|
|
88
|
+
"bet apply_discount(price, pct=0.15):\n",
|
|
89
|
+
" dip price * (1.0 - pct)\n",
|
|
90
|
+
"\n",
|
|
91
|
+
"fam Shopper:\n",
|
|
92
|
+
" bet __init__(self, name, wallet):\n",
|
|
93
|
+
" self.name = name\n",
|
|
94
|
+
" self.wallet = wallet\n",
|
|
95
|
+
"\n",
|
|
96
|
+
" bet purchase(self, item_name, original_price):\n",
|
|
97
|
+
" final_price = apply_discount(original_price)\n",
|
|
98
|
+
" self.wallet = self.wallet - final_price\n",
|
|
99
|
+
" holla self.name, \"bought\", item_name, \"for\", final_price, \"| Balance remaining:\", self.wallet\n",
|
|
100
|
+
"\n",
|
|
101
|
+
"buyer = Shopper(\"Sam\", 150.0)\n",
|
|
102
|
+
"buyer.purchase(\"Sneakers\", 80.0)"
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"cell_type": "markdown",
|
|
107
|
+
"metadata": {},
|
|
108
|
+
"source": [
|
|
109
|
+
"### Plain-English Error Handling: `tryna`, `catch`, and `ZeroSplitTrip`\n",
|
|
110
|
+
"Exceptions are never dumped as raw Python tracebacks; they are rendered with plain-English explanations, causes, and suggestions."
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"cell_type": "code",
|
|
115
|
+
"execution_count": null,
|
|
116
|
+
"metadata": {},
|
|
117
|
+
"outputs": [],
|
|
118
|
+
"source": [
|
|
119
|
+
"tryna:\n",
|
|
120
|
+
" result = 100 / 0\n",
|
|
121
|
+
"catch ZeroSplitTrip as err:\n",
|
|
122
|
+
" holla \"Caught expected error:\", err\n",
|
|
123
|
+
"regardless:\n",
|
|
124
|
+
" holla \"Execution completed clean.\""
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"metadata": {
|
|
129
|
+
"language_info": {
|
|
130
|
+
"name": "hoodscript",
|
|
131
|
+
"file_extension": ".hs",
|
|
132
|
+
"mimetype": "text/x-hoodscript"
|
|
133
|
+
},
|
|
134
|
+
"kernelspec": {
|
|
135
|
+
"name": "hoodscript",
|
|
136
|
+
"display_name": "HoodScript",
|
|
137
|
+
"language": "hoodscript"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"nbformat": 4,
|
|
141
|
+
"nbformat_minor": 2
|
|
142
|
+
}
|
|
@@ -16,7 +16,8 @@ repl = ["prompt-toolkit>=3.0.40"]
|
|
|
16
16
|
lsp = ["pygls>=1.3.1,<2", "jedi>=0.19.1"]
|
|
17
17
|
tools = ["ruff>=0.3.0", "mypy>=1.9.0"]
|
|
18
18
|
pretty = ["rich>=13.7"]
|
|
19
|
-
|
|
19
|
+
jupyter = ["ipykernel>=6.0.0", "ipython>=8.0.0"]
|
|
20
|
+
all = ["prompt-toolkit>=3.0.40", "pygls>=1.3.1,<2", "jedi>=0.19.1", "rich>=13.7", "ruff>=0.3.0", "mypy>=1.9.0", "ipykernel>=6.0.0", "ipython>=8.0.0"]
|
|
20
21
|
dev = [
|
|
21
22
|
"rich>=13.7",
|
|
22
23
|
"pytest>=8.0.0",
|
|
@@ -29,11 +30,14 @@ dev = [
|
|
|
29
30
|
"pygls>=1.3.1,<2",
|
|
30
31
|
"jedi>=0.19.1",
|
|
31
32
|
"hatch-vcs>=0.4.0",
|
|
33
|
+
"ipykernel>=6.0.0",
|
|
34
|
+
"ipython>=8.0.0",
|
|
32
35
|
]
|
|
33
36
|
|
|
34
37
|
[project.scripts]
|
|
35
38
|
hoodscript = "hoodscript.cli:main"
|
|
36
39
|
hoodscript-lsp = "hoodscript.lsp:run_lsp"
|
|
40
|
+
hoodscript-kernel = "hoodscript.kernel.__main__:main"
|
|
37
41
|
py2hood = "hoodscript.migrator:py2hood_main"
|
|
38
42
|
hood2py = "hoodscript.migrator:hood2py_main"
|
|
39
43
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from hoodscript.importer import install, uninstall
|
|
2
|
+
from hoodscript.transpiler import transpile
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
from hoodscript._version import __version__
|
|
6
|
+
except ImportError:
|
|
7
|
+
__version__ = "1.1.0"
|
|
8
|
+
|
|
9
|
+
__all__ = ["transpile", "install", "uninstall", "__version__", "load_ipython_extension"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_ipython_extension(ipython):
|
|
13
|
+
"""`%load_ext hoodscript` in IPython/Jupyter: registers the %%hood and
|
|
14
|
+
%hood_transpile magics. Imported lazily so the core stays dependency-free."""
|
|
15
|
+
from hoodscript.kernel.magics import load_ipython_extension as _load
|
|
16
|
+
_load(ipython)
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.
|
|
22
|
-
__version_tuple__ = version_tuple = (1,
|
|
21
|
+
__version__ = version = '1.2.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 2, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -25,6 +25,7 @@ Usage:
|
|
|
25
25
|
hoodscript debug <file.hs> Debug program under debugpy / DAP
|
|
26
26
|
hoodscript tokens Show all keywords and mappings
|
|
27
27
|
hoodscript playground [--port] Launch Web Playground in browser
|
|
28
|
+
hoodscript kernel install Register HoodScript Jupyter kernel
|
|
28
29
|
hoodscript lsp Start Language Server
|
|
29
30
|
hoodscript version Show version information
|
|
30
31
|
hoodscript completion [bash|zsh] Generate shell autocompletion
|
|
@@ -86,7 +87,8 @@ _hoodscript_completion() {
|
|
|
86
87
|
local cur prev words cword
|
|
87
88
|
_init_completion || return
|
|
88
89
|
|
|
89
|
-
local commands="run build check fmt lint repl tokens learn lsp version
|
|
90
|
+
local commands="run build check fmt lint repl tokens learn lsp version"
|
|
91
|
+
commands="$commands completion make-stubs debug playground kernel"
|
|
90
92
|
local topics="basics flow functions classes errors async mirror all"
|
|
91
93
|
|
|
92
94
|
if [[ $cword -eq 1 ]]; then
|
|
@@ -348,6 +350,32 @@ def playground_command(args: list[str]) -> int:
|
|
|
348
350
|
return 1
|
|
349
351
|
|
|
350
352
|
|
|
353
|
+
def kernel_command(args: list[str]) -> int:
|
|
354
|
+
parser = argparse.ArgumentParser(prog="hoodscript kernel", description="Manage HoodScript Jupyter kernel")
|
|
355
|
+
subparsers = parser.add_subparsers(dest="subcommand")
|
|
356
|
+
install_parser = subparsers.add_parser("install", help="Install Jupyter kernelspec")
|
|
357
|
+
install_parser.add_argument("--user", action="store_true", default=True, help="Install for current user (default)")
|
|
358
|
+
install_parser.add_argument("--sys-prefix", action="store_true", help="Install to sys.prefix")
|
|
359
|
+
install_parser.add_argument("--prefix", default=None, help="Install to specified prefix")
|
|
360
|
+
pargs = parser.parse_args(args)
|
|
361
|
+
|
|
362
|
+
if pargs.subcommand == "install":
|
|
363
|
+
try:
|
|
364
|
+
from hoodscript.kernel.installer import install_kernelspec
|
|
365
|
+
except ImportError as exc:
|
|
366
|
+
sys.stderr.write(f"Jupyter dependencies not installed: {exc}\nRun: pip install hoodscript[jupyter]\n")
|
|
367
|
+
return 1
|
|
368
|
+
|
|
369
|
+
prefix = sys.prefix if pargs.sys_prefix else pargs.prefix
|
|
370
|
+
user = not pargs.sys_prefix and pargs.prefix is None
|
|
371
|
+
path = install_kernelspec(user=user, prefix=prefix)
|
|
372
|
+
sys.stdout.write(f"Installed HoodScript kernel spec to {path}\n")
|
|
373
|
+
return 0
|
|
374
|
+
|
|
375
|
+
parser.print_help()
|
|
376
|
+
return 0
|
|
377
|
+
|
|
378
|
+
|
|
351
379
|
def main(argv=None) -> int:
|
|
352
380
|
if argv is None:
|
|
353
381
|
argv = sys.argv[1:]
|
|
@@ -397,6 +425,8 @@ def main(argv=None) -> int:
|
|
|
397
425
|
return debug_command(argv[1:])
|
|
398
426
|
if cmd == "playground":
|
|
399
427
|
return playground_command(argv[1:])
|
|
428
|
+
if cmd == "kernel":
|
|
429
|
+
return kernel_command(argv[1:])
|
|
400
430
|
if cmd == "build":
|
|
401
431
|
# build <file> transpiles to stdout (alias for -c)
|
|
402
432
|
if len(argv) < 2:
|
|
@@ -167,7 +167,8 @@ def _fill(template, facts):
|
|
|
167
167
|
# --------------------------------------------------------------------------- entry point
|
|
168
168
|
|
|
169
169
|
def diagnose(exc_type, exc, tb, filename=None) -> Diagnostic:
|
|
170
|
-
frames
|
|
170
|
+
# a SyntaxError is compile-time: the frames belong to whoever called compile(), never to the program
|
|
171
|
+
frames = user_frames(tb) if tb is not None and not isinstance(exc, SyntaxError) else []
|
|
171
172
|
entry, caught = find(exc)
|
|
172
173
|
suggestion = _suggest(exc, tb, filename or (frames[-1].filename if frames else None))
|
|
173
174
|
|
|
@@ -176,6 +177,8 @@ def diagnose(exc_type, exc, tb, filename=None) -> Diagnostic:
|
|
|
176
177
|
col = (exc.offset - 1) if exc.offset else None
|
|
177
178
|
end_col = (exc.end_offset - 1) if getattr(exc, "end_offset", None) else None
|
|
178
179
|
source_line = (exc.text or "").rstrip("\n")
|
|
180
|
+
if fname and fname.startswith("<") and lineno: # pseudo-file: exc.text is the Python; show the HoodScript
|
|
181
|
+
source_line = linecache.getline(fname, lineno).rstrip("\n") or source_line
|
|
179
182
|
elif frames:
|
|
180
183
|
last = frames[-1]
|
|
181
184
|
fname, lineno = last.filename, last.lineno
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""HoodScript Jupyter and IPython Kernel Integration.
|
|
2
|
+
|
|
3
|
+
Provides:
|
|
4
|
+
- HoodScriptKernel: Dedicated standalone Jupyter kernel.
|
|
5
|
+
- HoodScriptMagics: IPython extension for %%hood and %%hood_transpile.
|
|
6
|
+
- install_kernelspec: Programmatic and CLI installer for the kernelspec.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from hoodscript.kernel.kernel import HoodScriptKernel
|
|
10
|
+
from hoodscript.kernel.magics import load_ipython_extension
|
|
11
|
+
|
|
12
|
+
__all__ = ["HoodScriptKernel", "load_ipython_extension"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Entry point for launching the HoodScript Jupyter Kernel."""
|
|
2
|
+
|
|
3
|
+
from ipykernel.kernelapp import IPKernelApp
|
|
4
|
+
|
|
5
|
+
from hoodscript.kernel.kernel import HoodScriptKernel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
IPKernelApp.launch_instance(kernel_class=HoodScriptKernel)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
main()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Kernelspec installer for the HoodScript Jupyter Kernel."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
import tempfile
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from jupyter_client.kernelspec import KernelSpecManager
|
|
10
|
+
|
|
11
|
+
ROOT = Path(__file__).resolve().parents[3]
|
|
12
|
+
ICON_PATH = ROOT / "editors" / "vscode" / "icon.png"
|
|
13
|
+
|
|
14
|
+
KERNEL_SPEC = {
|
|
15
|
+
"argv": [
|
|
16
|
+
sys.executable,
|
|
17
|
+
"-m",
|
|
18
|
+
"hoodscript.kernel",
|
|
19
|
+
"-f",
|
|
20
|
+
"{connection_file}",
|
|
21
|
+
],
|
|
22
|
+
"display_name": "HoodScript",
|
|
23
|
+
"language": "hoodscript",
|
|
24
|
+
"metadata": {
|
|
25
|
+
"debugger": False,
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def install_kernelspec(user: bool = True, prefix: str | None = None) -> str:
|
|
31
|
+
"""Install the HoodScript kernelspec into Jupyter.
|
|
32
|
+
|
|
33
|
+
Returns the directory path where the kernelspec was installed.
|
|
34
|
+
"""
|
|
35
|
+
with tempfile.TemporaryDirectory() as td:
|
|
36
|
+
dest_dir = Path(td) / "hoodscript"
|
|
37
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
38
|
+
|
|
39
|
+
# Write kernel.json
|
|
40
|
+
(dest_dir / "kernel.json").write_text(json.dumps(KERNEL_SPEC, indent=2), encoding="utf-8")
|
|
41
|
+
|
|
42
|
+
# Copy icons if available
|
|
43
|
+
if ICON_PATH.exists():
|
|
44
|
+
shutil.copy2(ICON_PATH, dest_dir / "logo-64x64.png")
|
|
45
|
+
shutil.copy2(ICON_PATH, dest_dir / "logo-32x32.png")
|
|
46
|
+
|
|
47
|
+
manager = KernelSpecManager()
|
|
48
|
+
installed_path = manager.install_kernel_spec(
|
|
49
|
+
str(dest_dir),
|
|
50
|
+
kernel_name="hoodscript",
|
|
51
|
+
user=user,
|
|
52
|
+
prefix=prefix,
|
|
53
|
+
)
|
|
54
|
+
return installed_path
|