Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/windows-exe-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Windows EXE builder

on:
workflow_dispatch:
pull_request:
paths:
- "pyv2/**"
- "examples/software/**"
- "pyproject.toml"
- ".github/workflows/windows-exe-smoke.yml"
push:
branches: [main]
paths:
- "pyv2/**"
- "examples/software/**"
- "pyproject.toml"
- ".github/workflows/windows-exe-smoke.yml"

permissions:
contents: read

jobs:
build-and-run:
runs-on: windows-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Install Python v2 and native builder
run: python -m pip install . pyinstaller
- name: Validate the production app example
run: python -m pyv2 check examples/software/comet_notes.pyv2
- name: Build a real one-file Windows executable
run: python -m pyv2 build examples/software/comet_notes.pyv2 --native --output build/windows-smoke
- name: Run the packaged executable
shell: pwsh
run: |
$output = & ".\build\windows-smoke\dist\Comet-Notes.exe"
$output | Write-Host
if ($LASTEXITCODE -ne 0) { throw "Packaged app exited with $LASTEXITCODE" }
if (($output -join "`n") -notmatch "Use --add") { throw "Packaged app smoke output was incomplete" }
- uses: actions/upload-artifact@v4
with:
name: comet-notes-windows-exe
path: build/windows-smoke/dist/Comet-Notes.exe
if-no-files-found: error
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ __pycache__/
*.pyc
.DS_Store

# Python packaging outputs
# Python packaging and local app outputs
build/
dist/
*.egg-info/
.pyv2-data/
.builder/
16 changes: 16 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,22 @@
"presentation": { "reveal": "always", "panel": "new" },
"problemMatcher": []
},
{
"label": "Check current Python v2 app",
"type": "shell",
"command": "python3",
"args": ["-m", "pyv2", "check", "${file}"],
"options": { "cwd": "${workspaceFolder}" },
"problemMatcher": []
},
{
"label": "Build current app: Windows kit",
"type": "shell",
"command": "python3",
"args": ["-m", "pyv2", "build", "${file}", "--output", "${workspaceFolder}/build/windows"],
"options": { "cwd": "${workspaceFolder}" },
"problemMatcher": []
},
{
"label": "Run Python v2 tests",
"type": "shell",
Expand Down
50 changes: 45 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ The product is: 384
| `assert` is a keyword with moods | `assert(cond, msg)` is a function |
| trailing commas *sometimes* | trailing commas & multi-line everything |
| one runtime | two parity-tested runtimes — CLI **and** browser |
| ad-hoc file access | capability-based app data, atomic saves, and read-only assets |
| packaging guesswork | validated projects, reproducible kits, and real Windows `.exe` builds |

## 🚀 Quick start

Expand Down Expand Up @@ -79,13 +81,50 @@ $ python3 -m pyhope --demo # engine demo
$ python3 -m pyv2 examples/games/monster_arena.pyv2
```

## 🏗️ Build production Windows applications

Python v2 now includes the **Sudbury Build Tools**: app metadata, strict JSON,
command-line arguments, sandboxed UTF-8 files, atomic saves, read-only bundled
assets, native dialogs, validation, integrity manifests, and an inspectable
Windows packaging pipeline.

```console
# Create a complete application project
$ pyv2 new windows-app "Comet Tasks"

# Develop and validate it
$ pyv2 Comet-Tasks/main.pyv2 --add "Ship the app"
$ pyv2 check Comet-Tasks

# Create a reproducible Windows build kit from any operating system
$ pyv2 build Comet-Tasks

# On Windows: build the real one-file Comet-Tasks.exe
> pyv2 build Comet-Tasks --native
```

Each project includes `pyv2app.json`, VS Code tasks, a readable batch builder,
a PowerShell builder, app assets, and a GitHub Actions Windows workflow. Every
build kit vendors the exact Python v2 runtime and hashes its inputs. The actual
`.exe` is produced by PyInstaller **on Windows**; macOS and Linux create
the same reviewable build kit or can use the included Windows CI workflow.
Python v2 never disguises a non-Windows binary as an `.exe`. Generated files
are not Authenticode-signed automatically; public distributors should add their
own protected signing certificate in Windows CI.

Packaged apps store writable data under
`%LOCALAPPDATA%\\PythonV2Apps\\APP-ID`. Absolute paths, traversal, symlink
escapes, oversized text, and writes to bundled assets are blocked by default.
See [`examples/software/comet_notes.pyv2`](examples/software/comet_notes.pyv2).

## 🖥️ Python v2 Sudbury Launcher

Version 1.1 ships Python v2 as its own lightweight desktop application. The
workspace provides Home, Code Studio, a path-safe atomic file service, project
wizard, eight packaged CC0 assets, Games/GPU, detected editor connections,
local settings, docs, a polished offline personal/portfolio/game website
starter, and a preview server—all using the Python standard library. Open it with `pyv2-launcher`,
starter, Windows app project generation, and a preview server—all using the
Python standard library. Open it with `pyv2-launcher`,
`pyhope-studio`, or `pyhope --studio`.

## 🎮 PyHope game engine
Expand Down Expand Up @@ -167,8 +206,8 @@ The short version:
$ python3 -m unittest discover -s tests -t .
```

**92 tests pass:** 63 language tests, 9 PyHope engine tests, 12 workspace/Launcher tests,
7 arcade/Playground site tests, plus a parity harness that runs 21 programs (including error paths) through both the
**108 tests pass:** 63 language tests, 9 PyHope engine tests, 14 production-app/build tests,
13 workspace/Launcher tests, 8 arcade/Playground site tests, plus a parity harness that runs 25 programs (including error paths) through both the
Python and JavaScript runtimes and demands byte-identical output.

## 📦 Repo layout
Expand All @@ -184,7 +223,7 @@ tutorial.html 10 runnable language lessons + browser sandbox
guide.html 50 concise language/engine learning topics
games.html 10-game arcade, GPU lab, animated sprites, Python v2 source
arcade.js seven-game shared Canvas engine for Pocket Arcade
pyv2/ interpreter, CLI, desktop Launcher, packaged browser runtime
pyv2/ interpreter, safe app runtime, Windows builder, CLI, desktop Launcher
pyhope/ engine, CLI, and packaged offline CC0 asset library
pyv2.js twin language runtime in JavaScript
game.js CPU sprite raycaster (monsters + weapon)
Expand All @@ -196,7 +235,8 @@ install.bat Windows installer for pyv2 + PyHope
install.sh macOS/Linux installer for pyv2 + PyHope
editors/vscode/ VS Code syntax highlighting + snippets
examples/games/ playable Python v2 game/source examples
tests/ language, parity, and PyHope engine tests
examples/software/ persistent JSON and safe app-data examples
tests/ language, app builder, parity, site, workspace, and engine tests
docs/LANGUAGE.md full language reference & grammar
```

Expand Down
79 changes: 74 additions & 5 deletions docs.html
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ <h3>App layout</h3>
<tr><td>Home</td><td>Workspace overview and shortcuts to every main tool</td></tr>
<tr><td>Code Studio</td><td>Open, edit, save, and run <code>.pyv2</code>; output/errors stay in the app</td></tr>
<tr><td>Files</td><td>Safe local workspace service: create, read, atomically save, rename, and delete files without path traversal</td></tr>
<tr><td>New Project</td><td>Create Website, CLI app, or Game starters without overwriting files</td></tr>
<tr><td>New Project</td><td>Create Website, Windows app, CLI app, or Game starters without overwriting files</td></tr>
<tr><td>Assets</td><td>Browse and export eight packaged original CC0 PyHope SVGs offline</td></tr>
<tr><td>Games &amp; GPU</td><td>Open the 10-game arcade, animated sprites, and 9M GPU Lab</td></tr>
<tr><td>Connected Editors</td><td>Detect VS Code, VSCodium, Zed, Sublime Text, and PyCharm from PATH; no account or token</td></tr>
Expand Down Expand Up @@ -350,8 +350,71 @@ <h3>Build a website with Python v2</h3>
end
print("GAME|Comet Circuit|Racing|Three-lap AI racing.|games.html#comet-circuit")</code></pre>

<!-- ==================== WINDOWS APPS ==================== -->
<h2 id="windows-apps"><span class="badge">07</span> Production Apps &amp; Windows EXE Builder</h2>
<p>Sudbury Build Tools turn a <code>.pyv2</code> program into a validated,
inspectable application project and—when the native build runs on
Windows—a real one-file <code>.exe</code>. Python v2 does not rename a
Linux or macOS binary and pretend it is a Windows executable.</p>

<h3>Create, run, check, and build</h3>
<pre class="terminal"><code># Complete console application with JSON persistence
pyv2 new windows-app "Comet Tasks"

# Or create a dialog-based app with no terminal window
pyv2 new windows-app "Hello Window" --windowed

pyv2 Comet-Tasks/main.pyv2 --add "Ship the EXE"
pyv2 check Comet-Tasks
pyv2 build Comet-Tasks

# Run this final command on Windows with PyInstaller installed.
# The generated build-windows.bat handles that installation for you.
pyv2 build Comet-Tasks --native</code></pre>

<table class="ref-table">
<thead><tr><th>Generated file</th><th>Purpose</th></tr></thead>
<tbody>
<tr><td><code>main.pyv2</code></td><td>Readable application source using arguments, strict JSON, and persistent app data</td></tr>
<tr><td><code>pyv2app.json</code></td><td>Name, stable app ID, version, publisher, console/windowed mode, icon, and assets</td></tr>
<tr><td><code>build-windows.bat</code></td><td>Validates and builds the real EXE on Windows without administrator access</td></tr>
<tr><td><code>.github/workflows/windows-exe.yml</code></td><td>Optional Windows CI build and downloadable executable artifact</td></tr>
<tr><td><code>build/windows/manifest.json</code></td><td>SHA-256 source and build-input integrity record</td></tr>
<tr><td><code>runtime/pyv2</code></td><td>Exact vendored language runtime used for the build—no moving runtime dependency</td></tr>
<tr><td><code>app.spec</code> + <code>launcher.py</code></td><td>Reviewable PyInstaller recipe and embedded Python v2 host</td></tr>
</tbody>
</table>

<h3>Application APIs</h3>
<pre class="terminal"><code>info = app_info() # name, version, platform, safe data directory
commands = args() # values after the .pyv2 filename / EXE
settings = {theme: "night", zoom: 1.25}
write_text("settings.json", json_encode(settings))
loaded = json_decode(read_text("settings.json"))
print(loaded.theme)

# Other safe services:
# append_text, file_exists, list_dir, make_dir, delete_file
# read_asset, asset_exists, sleep_ms, ui_message, ui_ask</code></pre>
<p>During development, writable data stays in <code>.pyv2-data/</code>
beside the program. Packaged apps use
<code>%LOCALAPPDATA%\PythonV2Apps\APP-ID</code>. Paths are relative and
sandboxed; atomic writes, UTF-8 validation, an 8 MB text limit, asset
size validation, symlink-escape checks, and unmanaged-build-directory
protection are enabled by default.</p>

<div class="callout"><strong>Building from macOS or Linux:</strong>
<code>pyv2 build</code> still creates the complete Windows kit. Copy it
to Windows and run <code>build.bat</code>, or push the generated project
and run its GitHub Actions workflow on a Windows runner. PyInstaller
cannot cross-compile Windows PE files from another operating system.</div>
<p><strong>Signing note:</strong> generated executables are reproducible but
not Authenticode-signed automatically. Public distributors should add
their own protected code-signing certificate in Windows CI; never commit
a certificate or password to the project.</p>

<!-- ==================== PYHOPE ==================== -->
<h2 id="pyhope"><span class="badge">07</span> PyHope Game Engine</h2>
<h2 id="pyhope"><span class="badge">08</span> PyHope Game Engine</h2>
<p>PyHope is Python v2's own dependency-free game engine. It is not
pygame and it installs no native libraries. The portable Python module
handles game logic and terminal previews; the website adds Canvas and
Expand Down Expand Up @@ -403,7 +466,7 @@ <h3>Your first PyHope scene</h3>
<code>assets/sprites/</code>.</p>

<!-- ==================== LANGUAGE REFERENCE ==================== -->
<h2 id="language"><span class="badge">07</span> Language Quick Reference</h2>
<h2 id="language"><span class="badge">09</span> Language Quick Reference</h2>
<p>The full spec (grammar, semantics, error kinds) lives in
<a href="https://github.com/gefrus112/pythonv2/blob/main/docs/LANGUAGE.md">docs/LANGUAGE.md</a>.
Here is the day-to-day core.</p>
Expand Down Expand Up @@ -464,12 +527,17 @@ <h3>Builtins</h3>
<tr><td><code>keys values has get</code></td><td>Map access</td></tr>
<tr><td><code>sort sort_by join</code></td><td>Helpers</td></tr>
<tr><td><code>assert(cond, msg?)</code></td><td>Raises <code>AssertionError</code> when falsy</td></tr>
<tr><td><code>chr ord clock input</code></td><td>Misc (<code>input</code> is CLI-only)</td></tr>
<tr><td><code>json_encode json_decode</code></td><td>Strict JSON for persistent application data</td></tr>
<tr><td><code>args app_info</code></td><td>Application arguments, identity, platform, and capability details</td></tr>
<tr><td><code>read_text write_text append_text</code></td><td>Sandboxed UTF-8 files with atomic replacement</td></tr>
<tr><td><code>file_exists list_dir make_dir delete_file</code></td><td>Safe app-data management</td></tr>
<tr><td><code>read_asset asset_exists ui_message ui_ask</code></td><td>Packaged assets and native dialogs</td></tr>
<tr><td><code>chr ord clock input sleep_ms</code></td><td>Characters, timing, and desktop input</td></tr>
</tbody>
</table>

<!-- ==================== TRY IT ==================== -->
<h2 id="try"><span class="badge">08</span> Try It Right Here</h2>
<h2 id="try"><span class="badge">10</span> Try It Right Here</h2>
<p>No install needed to experiment — this is the real interpreter,
running in your browser. Edit and hit Run.</p>
<div class="try-grid">
Expand Down Expand Up @@ -516,6 +584,7 @@ <h4>Documentation</h4>
<a href="tutorial.html">Tutorial</a>
<a href="guide.html">50-topic guide</a>
<a href="#launcher">Sudbury Launcher</a>
<a href="#windows-apps">Windows EXE builder</a>
<a href="#pyhope">PyHope engine</a>
<a href="#install">Installation</a>
<a href="#vscode">VS Code setup</a>
Expand Down
48 changes: 38 additions & 10 deletions docs/LANGUAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,28 @@ hero.scores.push(30)
| `sort(list)` `sort_by(list, fn)` `join(list, sep)` | helpers |
| `assert(cond, msg?)` | raise `AssertionError` when falsy |
| `chr(n)` `ord(char)` | character codes |
| `clock()` | seconds on the wall clock |
| `clock()` | high-resolution elapsed seconds |
| `input(prompt?)` | read a line (CLI only; browser raises a friendly error) |

### 3.1 Methods
| `args()` | command-line arguments passed after the app filename |
| `app_info()` | app name, version, ID, platform, data directory, and asset capability |
| `json_encode(value)` / `json_decode(text)` | strict JSON serialization for maps and lists |
| `read_text(path)` / `write_text(path, text)` / `append_text(path, text)` | UTF-8 app-data files; writes are atomic by default |
| `file_exists(path)` / `list_dir(path?)` / `make_dir(path)` / `delete_file(path)` | sandboxed app-data management |
| `read_asset(path)` / `asset_exists(path)` | read-only files bundled with a packaged app |
| `sleep_ms(milliseconds)` | pause a desktop/CLI app for at most 60 seconds |
| `ui_message(title, text)` / `ui_ask(title, prompt, default?)` | native dialogs in packaged/desktop apps |

### 3.1 App capability safety

Desktop services are explicit capabilities. A CLI source file receives a
writable `.pyv2-data/` directory beside the source and optional read-only
`assets/`. A packaged Windows app stores data under
`%LOCALAPPDATA%\\PythonV2Apps\\APP-ID`. Absolute paths, `..` traversal, symlink
escapes, non-UTF-8 reads, and text larger than 8 MB are rejected with
`CapabilityError`. Browser programs keep JSON, `args()`, and `app_info()` but
cannot touch the visitor's filesystem.

### 3.2 Methods

**Strings:** `upper lower title trim chars reverse lines count slice(a, b?)
to_number repeat(n) split(sep) join(list) contains starts_with ends_with
Expand All @@ -217,7 +235,7 @@ Errors are `Kind: message at line N` with an optional call trace:

`SyntaxError`, `NameError`, `TypeError`, `IndexError`, `KeyError`,
`ZeroDivisionError`, `ValueError`, `OverflowError`, `AssertionError`,
`AttributeError`, `RuntimeError`.
`AttributeError`, `CapabilityError`, `RuntimeError`.

The CLI exits with status 1 on error; the playground prints the error in red
and keeps your code.
Expand Down Expand Up @@ -269,16 +287,26 @@ fnexpr := "fn" "(" params ")" ":" block "end"
## 7. CLI

```console
$ python3 -m pyv2 script.pyv2 # run a file
$ python3 -m pyv2 -c 'print(42)' # run a snippet
$ python3 -m pyv2 # REPL (... continues blocks)
$ python3 -m pyv2 --version
$ pyv2 script.pyv2 --list # run an app with arguments
$ pyv2 -c 'print(42)' # run a snippet
$ pyv2 # REPL (... continues blocks)
$ pyv2 check MyApp # syntax + metadata + path audit
$ pyv2 new windows-app "My App" # complete EXE-ready project
$ pyv2 build MyApp # build kit on any operating system
$ pyv2 build MyApp --native # real one-file .exe on Windows
$ pyv2 doctor # show local build readiness
```

A generated app contains readable source, `pyv2app.json`, VS Code tasks,
sandboxed-data examples, `build-windows.bat`, and a Windows GitHub Actions
workflow. PyInstaller must run on Windows to create a Windows PE executable;
macOS/Linux builds produce the honest reproducible kit rather than relabeling a
non-Windows binary.

## 8. Parity guarantee

The suite runs **92 tests**: 63 language tests, 9 PyHope engine tests, 7 arcade/Playground site tests,
12 workspace/Launcher tests, and one parity harness that sends 21 programs (including error paths) through
The suite runs **108 tests**: 63 language tests, 9 PyHope engine tests, 14 production-app/build tests,
8 arcade/Playground site tests, 13 workspace/Launcher tests, and one parity harness that sends 25 programs (including error paths) through
**both** language runtimes and compares outputs byte for byte. If the twins
ever disagree, the suite fails. That's the deal.

Expand Down
Loading
Loading