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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
run: |
python -m venv venv
source venv/bin/activate
pip install componentize-py==0.22.0 http-router==4.1.2 build==1.4.2
pip install componentize-py==0.22.0 http-router==4.1.2 build==1.4.2 mypy==1.13
python -m build
pip install dist/spin_sdk-4.0.0-py3-none-any.whl
bash run_tests.sh
3 changes: 2 additions & 1 deletion examples/external-lib-example/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import cast
from spin_sdk import http
from spin_sdk.http import Request, Response
import re
Expand Down Expand Up @@ -47,7 +48,7 @@ async def handle_request(self, request: Request) -> Response:
uri = urlparse(request.uri)
try:
handler = router(uri.path, request.method)
return handler.target(uri, request)
return cast(Response, handler.target(uri, request))
except exceptions.NotFoundError:
return Response(404, {}, None)

2 changes: 1 addition & 1 deletion examples/redis-trigger/app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from spin_sdk.wit import exports

class SpinRedisInboundRedis300(exports.SpinRedisInboundRedis300):
async def handle_message(self, message: bytes):
async def handle_message(self, message: bytes) -> None:
print(message)
24 changes: 12 additions & 12 deletions examples/spin-kv/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from typing import TypeVar, Tuple, List
from componentize_py_types import Result, Err
from componentize_py_async_support.streams import StreamReader
from componentize_py_async_support.futures import FutureReader
from spin_sdk import http, key_value
from spin_sdk.http import Request, Response
from spin_sdk.key_value import Store
Expand All @@ -9,7 +13,7 @@ async def handle_request(self, request: Request) -> Response:
print(await get_keys(a))
print(await a.exists("test"))
print(await a.get("test"))
print(await a.delete("test"))
await a.delete("test")
print(await get_keys(a))

return Response(
Expand All @@ -18,14 +22,10 @@ async def handle_request(self, request: Request) -> Response:
bytes("Hello from Python!", "utf-8")
)

async def get_keys(Store) -> list[str]:
stream, future = await Store.get_keys()
keys = []

while True:
batch = await stream.read(max_count=100)
if not batch:
break
keys.extend(batch)

return keys
async def get_keys(store: Store) -> list[str]:
stream, future = await store.get_keys()
with stream, future:
keys = []
while not stream.writer_dropped:
keys += await stream.read(max_count=100)
return keys
5 changes: 3 additions & 2 deletions examples/spin-postgres/app.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from spin_sdk import http, postgres
from spin_sdk.http import Request, Response
from spin_sdk.postgres import RowSet, DbValue


def format_value(db_value) -> str:
def format_value(db_value: DbValue) -> str:
if hasattr(db_value, "value"):
return str(db_value.value)
return "NULL"


def format_rowset(rowset) -> str:
def format_rowset(rowset: RowSet) -> str:
lines = []
col_names = [col.name for col in rowset.columns]
lines.append(" | ".join(col_names))
Expand Down
24 changes: 23 additions & 1 deletion run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,43 @@

source venv/bin/activate

# First, install any example-specific dependencies (common dependencies such as
# `componentize-py`, `spin-sdk`, and `mypy` are assumed to have been installed
# in the virtual environment).

if [ ! -d examples/matrix-math/numpy ]
then
(cd examples/matrix-math \
&& curl -OL https://github.com/dicej/wasi-wheels/releases/download/v0.0.2/numpy-wasi.tar.gz \
&& tar xf numpy-wasi.tar.gz)
fi

# Next, run MyPy on all the examples

for example in examples/*
do
echo "linting $example"
if [ $example = "examples/matrix-math" ]
then
# NumPy fails linting as of this writing, so we skip it
extra_option="--follow-imports silent"
else
unset extra_option
fi
export MYPYPATH=$(pwd)/src
(cd $example && mypy --strict $extra_option -m app) || exit 1
done

# Next, build all the examples

for example in examples/*
do
echo "building $example"
(cd $example && spin build) || exit 1
done

# Finally, run some of the examples and test that they behave as expected

# run trivial examples
for example in examples/hello examples/external-lib-example examples/spin-kv examples/spin-variables
do
pushd $example
Expand Down
10 changes: 5 additions & 5 deletions src/spin_sdk/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ async def handle(self, request: WasiRequest) -> WasiResponse:
simple_response.headers['content-length'] = str(content_length)

tx, rx = wit.byte_stream()
componentize_py_async_support.spawn(copy(simple_response.body, tx))
componentize_py_async_support.spawn(_copy(simple_response.body, tx))
response = WasiResponse.new(Fields.from_list(list(map(
lambda pair: (pair[0], bytes(pair[1], "utf-8")),
simple_response.headers.items()
Expand Down Expand Up @@ -159,7 +159,7 @@ async def send(request: Request) -> Response:
content_length = len(request.body) if request.body is not None else 0
# Make a copy rather than mutate in place, since the caller might not
# expect us to mutate it:
headers_dict = headers_dict.copy()
headers_dict = dict(headers_dict)
headers_dict['content-length'] = str(content_length)

headers = list(map(
Expand All @@ -168,12 +168,12 @@ async def send(request: Request) -> Response:
))

tx, rx = wit.byte_stream()
componentize_py_async_support.spawn(copy(request.body, tx))
componentize_py_async_support.spawn(_copy(request.body, tx))
outgoing_request = WasiRequest.new(Fields.from_list(headers), rx, _trailers_future(), None)[0]
outgoing_request.set_method(method)
outgoing_request.set_scheme(scheme)
if url_parsed.netloc == '':
if scheme == "http":
if isinstance(scheme, Scheme_Http):
authority = ":80"
else:
authority = ":443"
Expand Down Expand Up @@ -228,7 +228,7 @@ def strip_forbidden_headers(headers:MutableMapping[str, str]) -> MutableMapping[
pass
return headers

async def copy(bytes:bytes, tx:ByteStreamWriter):
async def _copy(bytes: bytes | None, tx: ByteStreamWriter) -> None:
with tx:
if bytes is not None:
await tx.write_all(bytes)
Expand Down
4 changes: 3 additions & 1 deletion src/spin_sdk/key_value.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Module for accessing Spin key-value stores"""

from spin_sdk.wit.imports.spin_key_value_key_value_3_0_0 import Store
from spin_sdk.wit.imports import spin_key_value_key_value_3_0_0 as kv

Store = kv.Store

async def open(name: str) -> Store:
"""
Expand Down
20 changes: 14 additions & 6 deletions src/spin_sdk/llm.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Module for working with the Spin large language model API"""

from dataclasses import dataclass
from typing import Optional, Sequence
from typing import Optional, List
from spin_sdk.wit.imports import fermyon_spin_llm_2_0_0 as spin_llm


@dataclass
class InferencingParams:
max_tokens: int = 100
Expand All @@ -14,7 +15,7 @@ class InferencingParams:
top_p: float = 0.9


def generate_embeddings(model: str, text: Sequence[str]) -> spin_llm.EmbeddingsResult:
def generate_embeddings(model: str, text: List[str]) -> spin_llm.EmbeddingsResult:
"""
A `componentize_py_types.Err(spin_sdk.wit.imports.fermyon_spin_llm_2_0_0.Error_ModelNotSupported)` will be raised if the component does not have access to the specified model.

Expand All @@ -32,8 +33,16 @@ def infer_with_options(model: str, prompt: str, options: Optional[InferencingPar

A `componentize_py_types.Err(spin_sdk.wit.imports.fermyon_spin_llm_2_0_0.Error_InvalidInput(str))` will be raised if an invalid input is provided.
"""
options = options or InferencingParams
return spin_llm.infer(model, prompt, options)
some_options = options or InferencingParams()
my_options = spin_llm.InferencingParams(
some_options.max_tokens,
some_options.repeat_penalty,
some_options.repeat_penalty_last_n_token_count,
some_options.temperature,
some_options.top_k,
some_options.top_p,
)
return spin_llm.infer(model, prompt, my_options)

def infer(model: str, prompt: str) -> spin_llm.InferencingResult:
"""
Expand All @@ -43,6 +52,5 @@ def infer(model: str, prompt: str) -> spin_llm.InferencingResult:

A `componentize_py_types.Err(spin_sdk.wit.imports.fermyon_spin_llm_2_0_0.Error_InvalidInput(str))` will be raised if an invalid input is provided.
"""
options = InferencingParams
return spin_llm.infer(model, prompt, options)
return infer_with_options(model, prompt, None)

6 changes: 5 additions & 1 deletion src/spin_sdk/postgres.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"""Module for interacting with a Postgres database"""

from spin_sdk.wit.imports.spin_postgres_postgres_4_2_0 import Connection
from spin_sdk.wit.imports import spin_postgres_postgres_4_2_0 as pg

Connection = pg.Connection
RowSet = pg.RowSet
DbValue = pg.DbValue

async def open(connection_string: str) -> Connection:
"""
Expand Down
10 changes: 7 additions & 3 deletions src/spin_sdk/sqlite.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"""Module for interacting with an SQLite database"""

from typing import List
from spin_sdk.wit.imports.spin_sqlite_sqlite_3_1_0 import (
Connection, Value_Integer, Value_Real, Value_Text, Value_Blob
)
from spin_sdk.wit.imports import spin_sqlite_sqlite_3_1_0 as sqlite

Connection = sqlite.Connection
Value_Integer = sqlite.Value_Integer
Value_Real = sqlite.Value_Real
Value_Text = sqlite.Value_Text
Value_Blob = sqlite.Value_Blob

async def open(name: str) -> Connection:
"""Open a connection to a named database instance.
Expand Down
2 changes: 1 addition & 1 deletion src/spin_sdk/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from spin_sdk.wit.imports import spin_variables_variables_3_0_0 as variables

async def get(key: str):
async def get(key: str) -> str:
"""
Gets the value of the given key
"""
Expand Down
Loading