From 9d515fab2310825e367c8eedbaafe144aa4fb45e Mon Sep 17 00:00:00 2001 From: Erik Rose Date: Wed, 27 May 2026 11:27:40 -0400 Subject: [PATCH 1/3] Focus readme on people trying out the SDK with their own Python code. De-emphasize the SDK-demoing-itself use case. * Remove redundancy between readme and CONTRIBUTING.md. Merge the build-tool-specific instructions from readme into CONTRIBUTING.md. * Add a warning about deferred imports. * Improve concision. * Shorten an unnecessarily long import people shouldn't copy. * Make clear we may break backward-compat while in beta. * Remove now-unnecessary submodule and manual `uv sync` instructions from CONTRIBUTING. Also, `make help` doesn't verify anything. Perhaps it once did. --- CONTRIBUTING.md | 85 ++++++------------ README.md | 90 +++++++++---------- examples/backend-requests/backend-requests.py | 2 +- 3 files changed, 67 insertions(+), 110 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b98f651..0a944b7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ The build process requires several tools to be installed: 2. **uv** - Python package manager 3. **Rust toolchain** (stable) -4. **wasm32-unknown-unknown target** (required by build.rs) +4. **wasm32-unknown-unknown Rust target** (required by build.rs) ```bash rustup target add wasm32-unknown-unknown ``` @@ -23,82 +23,47 @@ The build process requires several tools to be installed: 5. **wasm-tools** (required by build.rs for WIT merging and componentization) 6. **Viceroy** - Fastly's local testing server -## Getting Started - -1. **Clone the repository** - ```bash - git clone - cd compute-sdk-python/build-tool-impl - ``` - -2. **Initialize submodules** (if applicable) - ```bash - git submodule update --init --recursive - ``` - -3. **Install Python dependencies** - ```bash - uv sync --extra dev --extra test - ``` +## Development Workflow -4. **Verify setup** - ```bash - make help # Should show available commands - ``` +The `fastly-compute-py` build tool is written in Rust. By default, the Makefile uses `cargo run` (DEV_MODE=1), which means: +- **No installation needed** for testing or use against examples; the tool runs directly via cargo +- **Always up-to-date.** Changes to Rust code are automatically picked up. +- **Fast incremental builds.** Cargo handles recompilation efficiently. -## Development Workflow +To work on the build tool, edit the Rust code in `crates/fastly-compute-py/`, then run `make` to build it. -### Building Examples +### Making Changes to the Build Tool -The default development workflow uses `cargo run` which automatically picks up Rust changes: +The build tool is written in Rust and lives in `crates/fastly-compute-py/`. After you make changes, the Makefile automatically rebuilds via `cargo run` when you build an example service, like this: ```bash -# Build an example make build/bottle-app.composed.wasm - -# Build all examples -make - -# Serve an example for testing -make serve EXAMPLE=bottle-app ``` -### Making Changes to the Build Tool - -The build tool is in `crates/fastly-compute-py/`. When you make changes: +You can also test the installed entry point, which lets Python code call the build tool: ```bash -# The build system automatically rebuilds via `cargo run` -make build/bottle-app.composed.wasm - -# Or test the installed entry point make DEV_MODE=0 build/bottle-app.composed.wasm ``` ### Code Quality -```bash -# Format code (Python + Rust) -make format - -# Check formatting -make format-check - -# Run linters (Python + Rust) -make lint +These will spruce up spelling in both Python and Rust code: -# Auto-fix linting issues -make lint-fix +```bash +make format # Format code +make format-check # Check formatting +make lint # Run linters +make lint-fix # Auto-fix linting issues ``` ### Testing -```bash -# Run all tests -make test +The SDK has comprehensive tests, with integration tests running via Viceroy: -# Update snapshot tests -make test-update-snapshots +```bash +make test # Run all tests +make test-update-snapshots # Update snapshot tests ``` ## Project Structure @@ -109,7 +74,7 @@ make test-update-snapshots │ ├── fastly-compute-py/ # Rust build tool │ │ ├── build.rs # Build script (requires wasm-tools) │ │ └── src/ -│ └── wasiless/ # WASM component for WASI removal +│ └── wasiless/ # Wasm component for WASI stubbing ├── examples/ # Example applications │ ├── bottle-app/ │ ├── flask-app/ @@ -123,15 +88,15 @@ make test-update-snapshots Understanding the build process helps when debugging issues: -1. **build.rs runs** (during Rust compilation): +1. **build.rs** (during Rust compilation)... - Calls `wasm-tools component wit` to merge WIT files - Builds `wasiless` crate for wasm32-unknown-unknown - Calls `wasm-tools component new` to componentize wasiless -2. **fastly-compute-py runs**: +2. **fastly-compute-py**... - Resolves Python dependencies from virtualenv - - Calls `componentize-py` to build Python WASM component - - Composes with wasiless using WAC + - Calls `componentize-py` to build Python Wasm component + - Composes with wasiless using `wac` ## Continuous Integration diff --git a/README.md b/README.md index 3d27967..0197681 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,74 @@ # Fastly Compute Python SDK -Experimental Python SDK for [Fastly Compute](https://www.fastly.com/products/edge-compute) services. +Experimental Python SDK for [Fastly Compute](https://www.fastly.com/products/edge-compute) services -## Features +## Highlights -- **Multiple Framework Support**: Examples with Bottle, Flask, and more -- **WIT Bindings**: Auto-generated Python bindings from Fastly's WIT files -- **WSGI Compatibility**: Host any WSGI-compatible web framework -- **Testing Framework**: Comprehensive viceroy-based integration testing -- **Type Safety**: Full type hints and IDE support +- **Support for WSGI Frameworks**. Flask and Bottle examples are included for reference. +- Access from Python to **Fastly's API** +- Full **type hints** and IDE support ## Quick Start -### Build and Run -```bash -make serve # Serve default example (Bottle) -make serve EXAMPLE=flask-app # Serve Flask example -``` - -Visit http://127.0.0.1:7676/hello/world or http://127.0.0.1:7676/info - -### Available Examples +Here's how to write your own Python WSGI app and run it on Fastly's edge network: -```bash -make list-examples # List all examples -make build-all # Build all examples -``` +1. Install the package that provides the Fastly Python build tool and gives you access to the Fastly API: -### Testing -```bash -make test # Run integration tests -``` + `pip install fastly-compute` +2. Make a project shaped like [our Flask example](https://github.com/fastly/compute-sdk-python/tree/main/examples/flask-app). You may find it easiest to clone the [repository](https://github.com/fastly/compute-sdk-python), copy the `examples/flask-app` folder, and modify it. If you change the name of the top-level `.py` file, be sure to also update the entrypoint (`entry = "your_top_level_module_name"`) in `pyproject.toml`. +3. `cd your-project` +4. Install the [Fastly CLI](https://www.fastly.com/documentation/reference/tools/cli/) if you don't already have it. +5. `fastly compute init` +6. Say yes when warned "The current directory isn't empty." Answer "[4] Other" when it asks for Language. +7. Add this to the bottom of `fastly.toml`: + ``` + [scripts] + build = "fastly-compute-py build" + ``` -## Development +8. `fastly compute build` +9. `fastly compute deploy` -### Build Tool Development +## Run Our Examples on Your Own Machine -The `fastly-compute-py` build tool is written in Rust. By default, the Makefile uses `cargo run` (DEV_MODE=1), which means: -- **No installation needed** - the tool runs directly via cargo -- **Always up-to-date** - changes to Rust code are automatically picked up -- **Fast incremental builds** - cargo handles recompilation efficiently - -Simply edit the Rust code in `crates/fastly-compute-py/` and run `make` - that's it! - -**Alternative: Using the Python Entry Point** - -To test the installed `fastly-compute-py` command (how end users will invoke it): +### Hello World in Flask ```bash -make DEV_MODE=0 # Uses `uv run fastly-compute-py` instead of `cargo run` +make serve # Serve default example (Bottle) +make serve EXAMPLE=flask-app # Serve Flask example +make serve EXAMPLE=game-of-life # Serve Conway's Game of Life example ``` -### Code Quality -```bash -make format # Format code (Python + Rust) -make lint # Run linter (Python + Rust) -make lint-fix # Auto-fix linting issues (Python + Rust) -``` +Visit http://127.0.0.1:7676/hello/world or http://127.0.0.1:7676/info to see them work. + +### Other Examples -### Building Examples ```bash -make build/my-app.wasm # Build specific example -make clean # Clean all build artifacts -``` +make list-examples # List all examples +make build-all # Build all examples +``` ## Status -Currently demonstrates: +Currently supports... - Building pure Python into WebAssembly components - Creating Python bindings from Fastly's WIT files - Hosting web frameworks by adapting Fastly's API to WSGI -- Comprehensive testing with viceroy integration +- Hosting non-WSGI applications by writing directly against Fastly's API ## Caveats +- So our memory-snapshotting build process can retain them, all the packages + needed at runtime must get imported when your entrypoint (e.g. `flask-app.py`) + is imported. This can happen transitively. But beware of deferred imports like + non-top-level ones; if they aren't triggered by importing your entrypoint, + they will fail at runtime. (If you have third-party code that uses + non-top-level imports, you can ensure they work by importing them at the top + level in your own code.) - Any native Python modules need to be compiled against WASI. Few are at the moment. However, [Joel has done some](https://github.com/dicej/wasi-wheels/releases/), and the changes needed aren't extensive. +- Our in-Python API may change backward-incompatibly during this beta period. ## Contributing diff --git a/examples/backend-requests/backend-requests.py b/examples/backend-requests/backend-requests.py index 6e92cb3..611d95b 100644 --- a/examples/backend-requests/backend-requests.py +++ b/examples/backend-requests/backend-requests.py @@ -7,7 +7,7 @@ from bottle import Bottle, request -import fastly_compute.requests as requests +from fastly_compute import requests from fastly_compute.wsgi import WsgiHttpIncoming app = Bottle() From 5ce6366e2e4c41d33c54689e3952decdd07fe0b5 Mon Sep 17 00:00:00 2001 From: Erik Rose Date: Wed, 27 May 2026 12:52:51 -0400 Subject: [PATCH 2/3] Use relative links. Don't promise any extension module support. --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0197681..746b5b5 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Here's how to write your own Python WSGI app and run it on Fastly's edge network 1. Install the package that provides the Fastly Python build tool and gives you access to the Fastly API: `pip install fastly-compute` -2. Make a project shaped like [our Flask example](https://github.com/fastly/compute-sdk-python/tree/main/examples/flask-app). You may find it easiest to clone the [repository](https://github.com/fastly/compute-sdk-python), copy the `examples/flask-app` folder, and modify it. If you change the name of the top-level `.py` file, be sure to also update the entrypoint (`entry = "your_top_level_module_name"`) in `pyproject.toml`. +2. Make a project shaped like [our Flask example](/examples/flask-app). You may find it easiest to clone the [repository](/), copy the `examples/flask-app` folder, and modify it. If you change the name of the top-level `.py` file, be sure to also update the entrypoint (`entry = "your_top_level_module_name"`) in `pyproject.toml`. 3. `cd your-project` 4. Install the [Fastly CLI](https://www.fastly.com/documentation/reference/tools/cli/) if you don't already have it. 5. `fastly compute init` @@ -64,10 +64,7 @@ Currently supports... they will fail at runtime. (If you have third-party code that uses non-top-level imports, you can ensure they work by importing them at the top level in your own code.) -- Any native Python modules need to be compiled against WASI. Few are at the - moment. However, [Joel has done - some](https://github.com/dicej/wasi-wheels/releases/), and the changes needed - aren't extensive. +- Third-party C extension modules are not yet supported. - Our in-Python API may change backward-incompatibly during this beta period. ## Contributing From d9d62963bc4e23c94e1c5700b833f013cbe121f5 Mon Sep 17 00:00:00 2001 From: Erik Rose Date: Wed, 27 May 2026 15:22:55 -0400 Subject: [PATCH 3/3] Banish examples to the examples folder's readme, and clean it up. * Merge talk of examples from root-level readme into examples-dir readme. * Link to where to get wasm-tools and Viceroy. Running examples is still woefully heavyweight, and we should do something about that. * Remove .py suffixes from headings, as the examples folder is now full of folders, not modules. * Remove talk of running a fixed set of integration tests against an arbitrary example, which is no longer supported, if it ever was. --- CONTRIBUTING.md | 4 +-- README.md | 18 ++--------- examples/README.md | 77 ++++++++++++++-------------------------------- 3 files changed, 27 insertions(+), 72 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a944b7..e0e1f86 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,8 +20,8 @@ The build process requires several tools to be installed: rustup target add wasm32-unknown-unknown ``` -5. **wasm-tools** (required by build.rs for WIT merging and componentization) -6. **Viceroy** - Fastly's local testing server +5. **[wasm-tools](https://github.com/bytecodealliance/wasm-tools)** (required by build.rs for WIT merging and componentization) +6. **[Viceroy](https://github.com/fastly/Viceroy/releases)** - Fastly's local testing server ## Development Workflow diff --git a/README.md b/README.md index 746b5b5..ff75c2d 100644 --- a/README.md +++ b/README.md @@ -29,23 +29,9 @@ Here's how to write your own Python WSGI app and run it on Fastly's edge network 8. `fastly compute build` 9. `fastly compute deploy` -## Run Our Examples on Your Own Machine +## Run Some Examples on Your Own Machine -### Hello World in Flask -```bash -make serve # Serve default example (Bottle) -make serve EXAMPLE=flask-app # Serve Flask example -make serve EXAMPLE=game-of-life # Serve Conway's Game of Life example -``` - -Visit http://127.0.0.1:7676/hello/world or http://127.0.0.1:7676/info to see them work. - -### Other Examples - -```bash -make list-examples # List all examples -make build-all # Build all examples -``` +We ship [a few simple examples](examples/README.md) you can run locally to get a taste of what's possible. ## Status diff --git a/examples/README.md b/examples/README.md index efbbf89..25e323c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,80 +1,49 @@ # Fastly Compute Python Examples -This directory contains example applications demonstrating different approaches to building Fastly Compute services with Python. +This directory contains small examples of Fastly Compute services built with Python. ## Available Examples -### `bottle-app.py` +### `bottle-app` - **Framework**: Bottle (lightweight WSGI framework) -- **Shows**: Basic routing, JSON responses, WIT API integration +- **Demonstrates**: Basic routing, JSON responses, WIT API integration - **Use Case**: Simple services, proof-of-concept applications -### `flask-app.py` +### `flask-app` - **Framework**: Flask (popular Python web framework) -- **Shows**: Flask routing, request handling, error handling +- **Demonstrates**: Flask routing, request handling, error handling - **Use Case**: More complex applications, familiar Flask patterns -### `game-of-life.py` -A server-side implementation of Conway’s Game of Life, with a server round trip per frame. - -- **Shows**: Raw requests-per-second performance; Fastly's session-reuse +### `game-of-life` +- **Shows**: A server-side implementation of Conway’s Game of Life, with a server round trip per frame. +- **Demonstrates**: Raw requests-per-second performance; Fastly's session-reuse feature, which saves spin-up time in busy services +### `backend-requests` +This is actually a piece of the test harness; please ignore it. + ## Building and Running Examples -### Build a Specific Example -```bash -make build/flask-app.wasm # Build Flask example -make build/bottle-app.wasm # Build Bottle example -make build/game-of-life.wasm # Build Conway's Game of Life example -``` +Before you use `make`, please [install the prerequisites](../CONTRIBUTING.md#prerequisites). -### Serve an Example +### Hello World in Flask or Bottle ```bash -make serve # Serve default (bottle-app) -make serve EXAMPLE=flask-app # Serve Flask example +make serve # Serve default example (Bottle) +make serve EXAMPLE=flask-app # Serve Flask example ``` -### Build All Examples -```bash -make build-all -``` +Visit http://127.0.0.1:7676/hello/world or http://127.0.0.1:7676/info. -### List Available Examples +### Conway's Game of Life ```bash -make list-examples +make serve EXAMPLE=game-of-life # Serve Conway's Game of Life example ``` -## Testing Examples +Visit http://127.0.0.1:7676/. -The integration tests use the default example (bottle-app). To test other examples: +### Other Invocations ```bash -# Update the test to use a different example -EXAMPLE=flask-app make test -``` - -## Creating New Examples - -1. Create a new `.py` file in this directory -2. Implement your WSGI application -3. Include the `serve_wsgi_request` function and `HttpIncoming` class -4. Build with `make build/your-example.wasm` -5. Test with `make serve EXAMPLE=your-example` - -## Framework Requirements - -All examples must: -- Be WSGI-compatible applications -- Include the WIT integration boilerplate (`serve_wsgi_request`, `HttpIncoming`) -- Handle the standard test endpoints for integration tests: - - `/hello/` - Returns "Hello {name}!" - - `/info` - Returns JSON with service info and WIT data - - `/error` - Raises an exception for error testing - -## Dependencies - -Examples may use different web frameworks, but they all rely on: -- `wit_world` - Generated WIT bindings -- `componentize-py` - Python to WebAssembly compilation -- Framework-specific dependencies (bottle, flask, etc.) \ No newline at end of file +make list-examples # List all examples +make build-all # Build all examples +```