-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pydantic support #137
Comments
the code with the error is in this PR |
Hi @henderiw. Thanks for reporting this. I just tried making a simple app that uses Pydantic, and it seems to work. Here's what I did:
Note that BTW, @benbrandt is working on improving the WASI wheel situation. The goal is to create an "official" package index to which you'll be able to point Hope that helps! |
I can now build indeed the component. but when I run it I get this error (.venv) (base) wasm/component-reconciler - (result) > just run-guest-python this is the code I used import reconciler
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel
class Reconciler(reconciler.Reconciler):
def reconcile(self, object: str) -> reconciler.ReconcileResult:
# Example values for the result
requeue = False # Whether to requeue
requeue_after = 30 # Requeue after 30 seconds
#response_object = f"Processed: {object}" # Return a string with processed information
class User(BaseModel):
id: int
name: str = 'John Doe'
signup_ts: Optional[datetime] = None
friends: List[int] = []
external_data = {'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']}
user = User(**external_data)
print(user)
# Return the result with appropriate values
return reconciler.ReconcileResult(
requeue=requeue,
requeue_after=requeue_after,
object=f"Processed: {object}"
) without the pydantic code it runs fine import reconciler
class Reconciler(reconciler.Reconciler):
def reconcile(self, object: str) -> reconciler.ReconcileResult:
# Example values for the result
requeue = False # Whether to requeue
requeue_after = 30 # Requeue after 30 seconds
# Return the result with appropriate values
return reconciler.ReconcileResult(
requeue=requeue,
requeue_after=requeue_after,
object=f"Processed: {object}"
) (.venv) (base) wasm/component-reconciler - (result) > just run-guest-python |
I can also confirm your example works for me. but in my runtime it doesn't. this is my current runtime for reference use std::path::PathBuf;
use anyhow::{Context, Result};
use wasmtime::component::{bindgen, Component, Linker};
use wasmtime::{Engine, Store};
use wasmtime_wasi::{ResourceTable, WasiCtx, WasiView};
use std::time::Instant;
bindgen!({path: "../../../wit", world: "reconciler", async: false});
/// This state is used by the Runtime host,
/// we use it to store the WASI context (implementations of WASI)
/// and resource tables that components will use when executing
///
/// see:
/// - https://docs.rs/wasmtime-wasi/latest/wasmtime_wasi/trait.WasiView.html
/// - https://docs.rs/wasmtime-wasi/latest/wasmtime_wasi/fn.add_to_linker_sync.html
struct HostState {
ctx: WasiCtx,
table: ResourceTable,
}
impl HostState {
pub fn new() -> Self {
let ctx = WasiCtx::builder().inherit_stdio().build();
Self {
ctx,
table: ResourceTable::default(),
}
}
}
impl ReconcilerImports for HostState {
fn get(&mut self, name: String) -> String {
println!("Host received name: {}", name);
format!("Hello, {}!", name)
}
}
impl WasiView for HostState {
fn ctx(&mut self) -> &mut WasiCtx {
&mut self.ctx
}
fn table(&mut self) -> &mut ResourceTable {
&mut self.table
}
}
/// load the WASM component and return the instance
fn load_reconciler_instance(
path: PathBuf,
) -> Result<(Store<HostState>, Reconciler)> {
// Initialize the Wasmtime engine
let engine = Engine::default();
// Load the WASM component
let component = Component::from_file(&engine, &path).context("Component file not found")?;
// Create the store to manage the state of the component
let states: HostState = HostState::new();
let mut store = Store::<HostState>::new(&engine, states);
// Set up the linker for linking interfaces
let mut linker = Linker::new(&engine);
// Add WASI implementations to the linker for components to use
wasmtime_wasi::add_to_linker_sync(&mut linker)?;
// Add the `Reconciler` interface to the linker
Reconciler::add_to_linker(&mut linker, |state| state)?;
// Instantiate the component
let instance = Reconciler::instantiate(&mut store, &component, &linker)
.context("Failed to instantiate the reconciler world")?;
Ok((store, instance))
}
// call the reconcile function
fn call_reconcile(
store: &mut Store<HostState>,
instance: &Reconciler,
input_json: String,
) -> std::result::Result<ReconcileResult, ReconcileError> {
// Call the reconcile function
let result = instance
.call_reconcile(store, &input_json)
.map_err(|e| ReconcileError {
code: 500,
message: format!("Failed to call reconcile: {}", e),
})??;
Ok(result)
}
fn main() -> Result<()> {
let wasm_path = PathBuf::from(
std::env::var_os("GUEST_WASM_PATH")
.context("missing/invalid path to WebAssembly module (env: GUEST_WASM_PATH)")?,
);
// Input JSON
let input_json = r#"{"apiVersion":"topo.kubenet.dev/v1alpha1","kind":"Topology","metadata":{"name":"kubenet","namespace":"default"},"spec":{"defaults":{"type":"7220ixr-d3l","provider":"srlinux.nokia.com","version":"24.7.2"},"nodes":[{"name":"node1"},{"name":"node2"}],"links":[{"endpoints":[{"node":"node1","port":1,"endpoint":1},{"node":"node2","port":1,"endpoint":1}]}]}}"#.to_string();
//load the instance
let (mut store, instance) = load_reconciler_instance(wasm_path)
.map_err(|e| anyhow::anyhow!("Error loading reconciler instance: {}", e))?;
// Measure time taken to run the instance 10 times
let start = Instant::now();
for i in 0..10 {
println!("Running iteration: {}", i + 1);
// Measure iteration time
let iteration_start = Instant::now();
match call_reconcile(&mut store, &instance, input_json.clone()) {
Ok(result) => {
let iteration_duration = iteration_start.elapsed();
println!("Reconcile Iteration {} succeeded with output: {:#?}", i, result);
println!("Reconcile Iteration {} elaspetime {:?}", i, iteration_duration);
}
Err(e) => {
let iteration_duration = iteration_start.elapsed();
eprintln!("Reconcile Iteration {} failed: {}", i, e);
println!("Reconcile Iteration {} elaspetime {:?}", i, iteration_duration);
}
}
}
let duration = start.elapsed();
println!("Time taken for 10 iterations: {:?}", duration);
Ok(())
} |
I suspect this is related to the issue described here and here. I would recommend moving the |
confirmed. this works import reconciler
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = 'John Doe'
signup_ts: Optional[datetime] = None
friends: List[int] = []
class Reconciler(reconciler.Reconciler):
def reconcile(self, object: str) -> reconciler.ReconcileResult:
# Example values for the result
requeue = False # Whether to requeue
requeue_after = 30 # Requeue after 30 seconds
external_data = {'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']}
user = User(**external_data)
print(user)
# Return the result with appropriate values
return reconciler.ReconcileResult(
requeue=requeue,
requeue_after=requeue_after,
object=f"Processed: {object}"
) Running iteration: 1 |
did anyone try pydantic with componentize-py?
I ran into this issue and was told to raise an issue here.
I am not able to compile the code to a wasm binary
error:
I installed the modules in my venv
(.venv) (base) wasm/component-reconciler - (result) > uv pip show typing-extensions
Name: typing-extensions
Version: 4.12.2
Location: /Users/henderiw/code/wasm/component-reconciler/.venv/lib/python3.11/site-packages
Requires:
Required-by: pydantic, pydantic-core
(.venv) (base) wasm/component-reconciler - (result) >
(.venv) (base) wasm/component-reconciler - (result) > uv pip show pydantic_core
Name: pydantic-core
Version: 2.27.2
Location: /Users/henderiw/code/wasm/component-reconciler/.venv/lib/python3.11/site-packages
Requires: typing-extensions
Required-by: pydantic
Not sure what is going on? (edited)
The text was updated successfully, but these errors were encountered: