Skip to content

Commit 1250ba3

Browse files
authored
Merge pull request #1 from vdice/spin-4.0-py-api-and-code-updates
docs(v4): update Python code snippets/links/details
2 parents df70d5a + 35340db commit 1250ba3

14 files changed

Lines changed: 185 additions & 116 deletions

content/v4/http-outbound.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,18 @@ You can find a complete example of using outbound HTTP in the JavaScript SDK rep
176176

177177
{{ startTab "Python"}}
178178

179-
> [**Want to go straight to the reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v3/http/index.html)
179+
> [**Want to go straight to the reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v4/http/index.html)
180180
181-
HTTP functions and classes are available in the `http` module. The function name is [`send`](https://spinframework.github.io/spin-python-sdk/v3/http/index.html#spin_sdk.http.send). The [request type](https://spinframework.github.io/spin-python-sdk/http/index.html#spin_sdk.http.Request) is `Request`, and the [response type](https://spinframework.github.io/spin-python-sdk/v3/http/index.html#spin_sdk.http.Response) is `Response`. For example:
181+
HTTP functions and classes are available in the `http` module. The function name is [`send`](https://spinframework.github.io/spin-python-sdk/v4/http/index.html#spin_sdk.http.send). The [request type](https://spinframework.github.io/spin-python-sdk/v4/http/index.html#spin_sdk.http.Request) is `Request`, and the [response type](https://spinframework.github.io/spin-python-sdk/v4/http/index.html#spin_sdk.http.Response) is `Response`. For example:
182182

183183
```python
184+
from spin_sdk import http
184185
from spin_sdk.http import Request, Response, send
185-
response = send(Request("GET", "https://random-data-api.fermyon.app/animals/json", {}, None))
186+
187+
class HttpHandler(http.Handler):
188+
async def handle_request(self, request: Request) -> Response:
189+
response = await send(Request("GET", "https://random-data-api.fermyon.app/animals/json", {}, None))
190+
return response
186191
```
187192

188193
**Notes**

content/v4/http-trigger.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,23 +226,25 @@ addEventListener('fetch', async (event: FetchEvent) => {
226226

227227
{{ startTab "Python"}}
228228

229-
> [**Want to go straight to the reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v3/)
229+
> [**Want to go straight to the reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v4/)
230230
231-
In Python, the application must define a top-level class named IncomingHandler which inherits from [IncomingHandler](https://spinframework.github.io/spin-python-sdk/v3/http/index.html#spin_sdk.http.IncomingHandler), overriding the `handle_request` method.
231+
In Python, the application must define a top-level class named `HttpHandler` which inherits from [http.Handler](https://spinframework.github.io/spin-python-sdk/v4/http/index.html#spin_sdk.http.Handler), overriding the `handle_request` method.
232232

233233
```python
234234
from spin_sdk import http
235235
from spin_sdk.http import Request, Response
236236

237-
class IncomingHandler(http.IncomingHandler):
238-
def handle_request(self, request: Request) -> Response:
237+
class HttpHandler(http.Handler):
238+
async def handle_request(self, request: Request) -> Response:
239239
return Response(
240240
200,
241241
{"content-type": "text/plain"},
242242
bytes("Hello from Python!", "utf-8")
243243
)
244244
```
245245

246+
You can find a complete example for handling a HTTP request in the [Python SDK repository on GitHub](https://github.com/spinframework/spin-python-sdk/tree/main/examples/hello).
247+
246248
{{ blockEnd }}
247249

248250
{{ startTab "TinyGo"}}

content/v4/kv-store-api-guide.md

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,19 @@ addEventListener('fetch', async (event: FetchEvent) => {
123123

124124
{{ startTab "Python"}}
125125

126-
> [**Want to go straight to the reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v3/key_value.html)
126+
> [**Want to go straight to the reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v4/key_value.html)
127127
128-
The key value functions are provided through the `spin_key_value` module in the Python SDK. For example:
128+
The key value functions are provided through the `key_value` module in the Python SDK. For example:
129129

130130
```python
131131
from spin_sdk import http, key_value
132132
from spin_sdk.http import Request, Response
133133

134-
class IncomingHandler(http.IncomingHandler):
135-
def handle_request(self, request: Request) -> Response:
136-
with key_value.open_default() as store:
137-
store.set("test", bytes("hello world!", "utf-8"))
138-
val = store.get("test")
134+
class HttpHandler(http.Handler):
135+
async def handle_request(self, request: Request) -> Response:
136+
with await key_value.open_default() as store:
137+
await store.set("test", bytes("hello world!", "utf-8"))
138+
val = await store.get("test")
139139

140140
return Response(
141141
200,
@@ -148,8 +148,31 @@ class IncomingHandler(http.IncomingHandler):
148148
**General Notes**
149149
- The Python SDK doesn't surface the `close` operation. It automatically closes all stores at the end of the request; there's no way to close them early.
150150

151-
[`get` **Operation**](https://spinframework.github.io/spin-python-sdk/v3/wit/imports/key_value.html#spin_sdk.wit.imports.key_value.Store.get)
152-
- If a key does not exist, it returns `None`
151+
- To open the default key-value store, you can use the [`key_value.open_default`](https://spinframework.github.io/spin-python-sdk/v4/key_value.html#spin_sdk.key_value.open_default) function. You can use [`key_value.open`](https://spinframework.github.io/spin-python-sdk/v4/key_value.html#spin_sdk.key_value.open) to open any store by label.
152+
153+
- Below is a breakdown of the methods surfaced directly from the underlying [spin-key-value-3.0.0 WIT definition](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_key_value_key_value_3_0_0.html):
154+
155+
[`open` **Operation**](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_key_value_key_value_3_0_0.html#spin_sdk.wit.imports.spin_key_value_key_value_3_0_0.Store.open)
156+
- Open the store with the specified label
157+
158+
[`get` **Operation**](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_key_value_key_value_3_0_0.html#spin_sdk.wit.imports.spin_key_value_key_value_3_0_0.Store.get)
159+
- If a key does not exist, it returns `None`
160+
161+
[`set` **Operation**](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_key_value_key_value_3_0_0.html#spin_sdk.wit.imports.spin_key_value_key_value_3_0_0.Store.set)
162+
- Sets a value associated with the specified key, overwriting any existing value.
163+
164+
[`delete` **Operation**](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_key_value_key_value_3_0_0.html#spin_sdk.wit.imports.spin_key_value_key_value_3_0_0.Store.delete)
165+
- Deletes the specified item from the store
166+
167+
[`exists` **Operation**](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_key_value_key_value_3_0_0.html#spin_sdk.wit.imports.spin_key_value_key_value_3_0_0.Store.exists)
168+
- Return whether the specified key is present in the store
169+
170+
[`get_keys` **Operation**](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_key_value_key_value_3_0_0.html#spin_sdk.wit.imports.spin_key_value_key_value_3_0_0.Store.get_keys)
171+
- Returns a `Tuple` containing a [StreamReader](https://github.com/bytecodealliance/componentize-py/blob/1b3d2e936868307a48fb70941dcad71b54e844f8/bundled/componentize_py_async_support/streams.py#L101) and a [FutureReader](https://github.com/bytecodealliance/componentize-py/blob/1b3d2e936868307a48fb70941dcad71b54e844f8/bundled/componentize_py_async_support/futures.py#L11). You _must_ check when the stream ends, to determine if the stream ended normally, or was terminated prematurely due to an error.
172+
173+
> If you're familiar with previous versions of the Python SDK, note that `get_keys` no longer returns a list. To get the keys as a list, use `await util.collect(await store.get_keys())`. See [collect](https://spinframework.github.io/spin-python-sdk/v4/util.html#spin_sdk.util.collect) for more details.
174+
175+
You can find a complete Python code example using the Key Value store in the [Spin Python SDK repository on GitHub](https://github.com/spinframework/spin-python-sdk/tree/main/examples/spin-kv).
153176

154177
{{ blockEnd }}
155178

content/v4/language-support-overview.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ This page contains information about language support for Spin features:
6161

6262
{{ startTab "Python"}}
6363

64-
**[📄 Visit the Python Spin SDK reference documentation](https://spinframework.github.io/spin-python-sdk/v3) to see specific modules, functions, variables and syntax relating to the following Python SDK.**
64+
**[📄 Visit the Python Spin SDK reference documentation](https://spinframework.github.io/spin-python-sdk/v4) to see specific modules, functions, variables and syntax relating to the following Python SDK.**
6565

6666
| Feature | SDK Supported? |
6767
|-----|-----|
@@ -77,7 +77,7 @@ This page contains information about language support for Spin features:
7777
| PostgreSQL | Supported |
7878
| [Outbound Redis](./python-components#an-outbound-redis-example) | Supported |
7979
| [Serverless AI](./serverless-ai-api-guide) | Supported |
80-
| [MQTT Messaging](./mqtt-outbound) | Not Supported |
80+
| [MQTT Messaging](./mqtt-outbound) | Supported |
8181
| **Extensibility** |
8282
| Authoring Custom Triggers | Not Supported |
8383

content/v4/mqtt-outbound.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,24 @@ You can find a complete Rust code example for using outbound MQTT from an HTTP c
8282

8383
{{ startTab "Python"}}
8484

85-
MQTT is not available in the current version of the Python SDK.
85+
> [**Want to go straight to the reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v4/mqtt.html)
86+
87+
To access an MQTT server, use the `open` function. You can then call the `publish` method on the connection to send MQTT messages:
88+
89+
```python
90+
from spin_sdk import http, mqtt
91+
from spin_sdk.mqtt import Qos
92+
from spin_sdk.http import Request, Response
93+
94+
class HttpHandler(http.Handler):
95+
async def handle_request(self, request: Request) -> Response:
96+
with await mqtt.open("mqtt://localhost:1883?client_id=client001", "user", "password", 30) as conn:
97+
await conn.publish("telemetry", bytes("Eureka!", "utf-8"), Qos.AT_LEAST_ONCE)
98+
```
99+
100+
For full details of the MQTT API, see the [Spin SDK reference documentation](https://spinframework.github.io/spin-python-sdk/v4/mqtt.html)
101+
102+
You can find a complete Python code example for using outbound MQTT from an HTTP component in the [Spin Python SDK repository on GitHub](https://github.com/spinframework/spin-python-sdk/tree/main/examples/spin-outbound-mqtt).
86103

87104
{{ blockEnd }}
88105

content/v4/python-components.md

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ With <a href="https://www.python.org/" target="_blank">Python</a> being a very p
3535
3636
> This guide assumes you are familiar with the Python programming language, but if you are just getting started, be sure to check out <a href="https://docs.python.org/3/" target="_blank">the official Python documentation</a> and comprehensive <a href="https://docs.python.org/3/reference/" target="_blank">language reference</a>.
3737
38-
[**Want to go straight to the Spin SDK reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v3)
38+
[**Want to go straight to the Spin SDK reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v4)
3939

4040
## Prerequisite
4141

@@ -49,7 +49,7 @@ If you do not have Python 3.10 or later, you can install it by following the ins
4949

5050
## Spin's Python HTTP Request Handler Template
5151

52-
Spin's Python HTTP Request Handler Template can be installed from [spin-python-sdk repository](https://github.com/spinframework/spin-python-sdk/tree/main/) using the following command:
52+
Spin's Python HTTP Request Handler Template can be installed from [spin-python-sdk repository](https://github.com/spinframework/spin-python-sdk) using the following command:
5353

5454
<!-- @selectiveCpy -->
5555

@@ -170,22 +170,22 @@ component = "hello-world"
170170
[component.hello-world]
171171
source = "app.wasm"
172172
[component.hello-world.build]
173-
command = "componentize-py -w spin-http componentize app -o app.wasm"
173+
command = "componentize-py -w spin:up/http-trigger@4.0.0 componentize app -o app.wasm"
174174
```
175175

176176
## A Simple HTTP Components Example
177177

178178
In Spin, HTTP components are triggered by the occurrence of an HTTP request and must return an HTTP response at the end of their execution. Components can be built in any language that compiles to WASI. If you would like additional information about building HTTP applications you may find [the HTTP trigger page](./http-trigger.md) useful.
179179

180-
Building a Spin HTTP component using the Python SDK means defining a top-level class named IncomingHandler which inherits from [`IncomingHandler`](https://spinframework.github.io/spin-python-sdk/v3/wit/exports/index.html#spin_sdk.wit.exports.IncomingHandler), overriding the `handle_request` method. Here is an example of the default Python code which the previous `spin new` created for us; a simple example of a request/response:
180+
Building a Spin HTTP component using the Python SDK means defining a top-level class named HttpHandler which inherits from [`HttpHandler`](https://spinframework.github.io/spin-python-sdk/v4/wit/exports/index.html#spin_sdk.wit.exports.HttpHandler), overriding the `handle_request` method. Here is an example of the default Python code which the previous `spin new` created for us; a simple example of a request/response:
181181

182182
<!-- @nocpy -->
183183

184184
```python
185-
from spin_sdk.http import IncomingHandler, Request, Response
185+
from spin_sdk.http import Handler, Request, Response
186186

187-
class IncomingHandler(IncomingHandler):
188-
def handle_request(self, request: Request) -> Response:
187+
class HttpHandler(Handler):
188+
async def handle_request(self, request: Request) -> Response:
189189
return Response(
190190
200,
191191
{"content-type": "text/plain"},
@@ -241,8 +241,8 @@ import json
241241
from spin_sdk import http
242242
from spin_sdk.http import Request, Response
243243

244-
class IncomingHandler(http.IncomingHandler):
245-
def handle_request(self, request: Request) -> Response:
244+
class HttpHandler(http.Handler):
245+
async def handle_request(self, request: Request) -> Response:
246246
# Access the request.method
247247
if request.method == 'POST':
248248
# Read the request.body as a string
@@ -330,14 +330,15 @@ This next example will create an outbound request, to obtain a random fact about
330330
from spin_sdk import http
331331
from spin_sdk.http import Request, Response, send
332332

333-
class IncomingHandler(http.IncomingHandler):
334-
def handle_request(self, request: Request) -> Response:
335-
resp = send(Request("GET", "https://random-data-api.fermyon.app/animals/json", {}, None))
336-
337-
return Response(200,
338-
{"content-type": "text/plain"},
339-
bytes(f"Here is an animal fact: {str(resp.body, 'utf-8')}", "utf-8"))
333+
class HttpHandler(http.Handler):
334+
async def handle_request(self, request: Request) -> Response:
335+
resp = await send(Request("GET", "https://random-data-api.fermyon.app/animals/json", {}, None))
340336

337+
return Response(
338+
200,
339+
{"content-type": "text/plain"},
340+
bytes(f"Here is an animal fact: {str(resp.body, 'utf-8')}", "utf-8")
341+
)
341342
```
342343

343344
### Configuring Outbound Requests
@@ -363,7 +364,7 @@ component = "hello-world"
363364
source = "app.wasm"
364365
allowed_outbound_hosts = ["https://random-data-api.fermyon.app"]
365366
[component.hello-world.build]
366-
command = "componentize-py -w spin-http componentize app -o app.wasm"
367+
command = "componentize-py -w spin:up/http-trigger@4.0.0 componentize app -o app.wasm"
367368
watch = ["*.py", "requirements.txt"]
368369
```
369370

@@ -418,12 +419,11 @@ route = "/..."
418419
component = "hello-world"
419420

420421
[component.hello-world]
421-
id = "hello-world"
422422
source = "app.wasm"
423423
variables = { redis_address = "redis://127.0.0.1:6379" }
424424
allowed_outbound_hosts = ["redis://127.0.0.1:6379"]
425425
[component.hello-world.build]
426-
command = "spin py2wasm app -o app.wasm"
426+
command = "componentize-py -w spin:up/http-trigger@4.0.0 componentize app -o app.wasm"
427427
```
428428

429429
If you are still following along, please go ahead and update your `app.py` file one more time, as follows:
@@ -434,20 +434,22 @@ If you are still following along, please go ahead and update your `app.py` file
434434
from spin_sdk import http, redis, variables
435435
from spin_sdk.http import Request, Response
436436

437-
class IncomingHandler(http.IncomingHandler):
438-
def handle_request(self, request: Request) -> Response:
439-
with redis.open(variables.get("redis_address")) as db:
440-
db.set("foo", b"bar")
441-
value = db.get("foo")
442-
db.incr("testIncr")
443-
db.sadd("testSets", ["hello", "world"])
444-
content = db.smembers("testSets")
445-
db.srem("testSets", ["hello"])
437+
class HttpHandler(http.Handler):
438+
async def handle_request(self, request: Request) -> Response:
439+
with await redis.open(await variables.get("redis_address")) as db:
440+
await db.set("foo", b"bar")
441+
value = await db.get("foo")
442+
await db.incr("testIncr")
443+
await db.sadd("testSets", ["hello", "world"])
444+
content = await db.smembers("testSets")
445+
await db.srem("testSets", ["hello"])
446446
assert value == b"bar", f"expected \"bar\", got \"{str(value, 'utf-8')}\""
447447

448-
return Response(200,
449-
{"content-type": "text/plain"},
450-
bytes(f"Executed outbound Redis commands: {request.uri}", "utf-8"))
448+
return Response(
449+
200,
450+
{"content-type": "text/plain"},
451+
bytes(f"Executed outbound Redis commands: {request.uri}", "utf-8")
452+
)
451453
```
452454

453455
### Building and Running the Application

0 commit comments

Comments
 (0)