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
89 changes: 27 additions & 62 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,90 +15,55 @@ 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
```

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

## Getting Started

1. **Clone the repository**
```bash
git clone <repo-url>
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
Expand All @@ -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/
Expand All @@ -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

Expand Down
91 changes: 33 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,57 @@
# 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
```
Here's how to write your own Python WSGI app and run it on Fastly's edge network:

Visit http://127.0.0.1:7676/hello/world or http://127.0.0.1:7676/info
1. Install the package that provides the Fastly Python build tool and gives you access to the Fastly API:

### Available Examples
`pip install fastly-compute`
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`
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"
```

```bash
make list-examples # List all examples
make build-all # Build all examples
```
8. `fastly compute build`
9. `fastly compute deploy`

### Testing
```bash
make test # Run integration tests
```
## Run Some Examples on Your Own Machine

## Development

### Build Tool Development

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):
```bash
make DEV_MODE=0 # Uses `uv run fastly-compute-py` instead of `cargo run`
```

### Code Quality
```bash
make format # Format code (Python + Rust)
make lint # Run linter (Python + Rust)
make lint-fix # Auto-fix linting issues (Python + Rust)
```

### Building Examples
```bash
make build/my-app.wasm # Build specific example
make clean # Clean all build artifacts
```
We ship [a few simple examples](examples/README.md) you can run locally to get a taste of what's possible.

## 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

- 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.
- 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.)
- Third-party C extension modules are not yet supported.
- Our in-Python API may change backward-incompatibly during this beta period.

## Contributing

Expand Down
77 changes: 23 additions & 54 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -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/<name>` - 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.)
make list-examples # List all examples
make build-all # Build all examples
```
2 changes: 1 addition & 1 deletion examples/backend-requests/backend-requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading