Converting Python dictionary into an internal data structure #3457
-
I'm new both Rust and PyO3 and maybe this is somewhat obvious, but could not figure this out yet. I'm trying to create a Python extension around a Rust library that accepts its own context object that I have to construct from a dictionary that I pass from Python. Here's an example code: fn evaluate(&mut self) -> PyResult<bool> {
let context = Context::default();
let value = self.program.execute(&context).unwrap();
match value {
Value::Bool(v) => Ok(v),
_ => Ok(false),
}
} Now I'm trying to change that so that it accepts a Python dictionary and I need to convert values from the dictionary to the correct type. Something like this: fn evaluate(&mut self, py: Python, ctx: HashMap<String, &PyObject>) -> PyResult<bool> {
let context = Context::default();
for (key, value) in ctx {
let type_of_value = // how would I get the type of `value` here?
match type_of_value {
bool => context.add_variable(key, Value::Bool(value)),
String => context.add_variable(key, Value::String(value)),
}
}
let value = self.program.execute(&context).unwrap();
match value {
Value::Bool(v) => Ok(v),
_ => Ok(false),
}
} For the Python side this would look like this: program.evaluate({
"string1": "value1",
"bool1": True,
}) The Now that I think of it I feel like creating an internal enum that would be used from Python side as a value could be a better option instead of being able to accept any Python object 🤔 I would appreciate any pointers into the right direction. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
You have multiple options: You could derive #[derive(FromPyObject)]
enum Value {
String(String),
Bool(bool),
}
#[pyfunction]
fn evaluate(&mut self, py: Python, ctx: HashMap<String, Value>) -> PyResult<bool> {
let context = Context::default();
for (key, value) in ctx {
context.add_variable(key, value);
}
let value = self.program.execute(&ctx).unwrap();
match value {
Value::Bool(v) => Ok(v),
_ => Ok(false),
}
} But you could also try to #[pyfunction]
fn evaluate(&mut self, py: Python, ctx: HashMap<String, PyObject>) -> PyResult<bool> {
let context = Context::default();
for (key, value) in ctx {
if let Ok(value) = value.extract::<bool>() {
context.add_variable(key, Value::Bool(value));
} else if let Ok(value) = value.extract::<String>() {
context.add_variable(key, Value::String(value))
} else {
// Handle case of unsupported type, e.g. return an error.
}
}
let value = self.program.execute(&context).unwrap();
match value {
Value::Bool(v) => Ok(v),
_ => Ok(false),
}
} |
Beta Was this translation helpful? Give feedback.
-
Alright, thank you. I think I have some ideas to try out:
|
Beta Was this translation helpful? Give feedback.
You have multiple options: You could derive
FromPyObject
for your enum and consume it directly, e.g.But you could also try to
extract
the types required, i.e. use theFromPyObject
trait manually, e.g.