Skip to content

tidy up some remaining PyO3 GIL Refs #1225

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

Merged
merged 1 commit into from
Mar 13, 2024
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
68 changes: 34 additions & 34 deletions benches/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use pyo3::types::{PyDict, PyString};

use _pydantic_core::{validate_core_schema, SchemaValidator};

fn build_schema_validator_with_globals(py: Python, code: &str, globals: Option<&PyDict>) -> SchemaValidator {
let mut schema = py.eval(code, globals, None).unwrap().extract().unwrap();
fn build_schema_validator_with_globals(py: Python, code: &str, globals: Option<&Bound<'_, PyDict>>) -> SchemaValidator {
let mut schema = py.eval_bound(code, globals, None).unwrap().extract().unwrap();
schema = validate_core_schema(&schema, None).unwrap().extract().unwrap();
SchemaValidator::py_new(py, &schema, None).unwrap()
}
Expand Down Expand Up @@ -71,7 +71,7 @@ fn list_int_input(py: Python<'_>) -> (SchemaValidator, PyObject) {
(0..100).map(|x| x.to_string()).collect::<Vec<String>>().join(",")
);

let input = py.eval(&code, None, None).unwrap();
let input = py.eval_bound(&code, None, None).unwrap();
(validator, input.to_object(py))
}

Expand Down Expand Up @@ -117,7 +117,7 @@ fn list_error_json(bench: &mut Bencher) {
match validator.validate_json(py, &json(py, &code), None, None, None) {
Ok(_) => panic!("unexpectedly valid"),
Err(e) => {
let v = e.value(py);
let v = e.value_bound(py);
// println!("error: {}", v.to_string());
assert_eq!(v.getattr("title").unwrap().to_string(), "list[int]");
let error_count: i64 = v.call_method0("error_count").unwrap().extract().unwrap();
Expand All @@ -144,12 +144,12 @@ fn list_error_python_input(py: Python<'_>) -> (SchemaValidator, PyObject) {
.join(", ")
);

let input = py.eval(&code, None, None).unwrap().extract().unwrap();
let input = py.eval_bound(&code, None, None).unwrap().extract().unwrap();

match validator.validate_python(py, &input, None, None, None, None) {
Ok(_) => panic!("unexpectedly valid"),
Err(e) => {
let v = e.value(py);
let v = e.value_bound(py);
// println!("error: {}", v.to_string());
assert_eq!(v.getattr("title").unwrap().to_string(), "list[int]");
let error_count: i64 = v.call_method0("error_count").unwrap().extract().unwrap();
Expand Down Expand Up @@ -211,7 +211,7 @@ fn list_any_python(bench: &mut Bencher) {
"[{}]",
(0..100).map(|x| x.to_string()).collect::<Vec<String>>().join(",")
);
let input = py.eval(&code, None, None).unwrap().to_object(py);
let input = py.eval_bound(&code, None, None).unwrap().to_object(py);
let input = black_box(input.bind(py));
bench.iter(|| {
let v = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand Down Expand Up @@ -263,7 +263,7 @@ fn dict_python(bench: &mut Bencher) {
.collect::<Vec<String>>()
.join(", ")
);
let input = py.eval(&code, None, None).unwrap().to_object(py);
let input = py.eval_bound(&code, None, None).unwrap().to_object(py);
let input = black_box(input.bind(py));
bench.iter(|| {
let v = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand Down Expand Up @@ -292,12 +292,12 @@ fn dict_value_error(bench: &mut Bencher) {
.join(", ")
);

let input = py.eval(&code, None, None).unwrap().to_object(py).into_bound(py);
let input = py.eval_bound(&code, None, None).unwrap().to_object(py).into_bound(py);

match validator.validate_python(py, &input, None, None, None, None) {
Ok(_) => panic!("unexpectedly valid"),
Err(e) => {
let v = e.value(py);
let v = e.value_bound(py);
// println!("error: {}", v.to_string());
assert_eq!(v.getattr("title").unwrap().to_string(), "dict[str,constrained-int]");
let error_count: i64 = v.call_method0("error_count").unwrap().extract().unwrap();
Expand Down Expand Up @@ -370,7 +370,7 @@ fn typed_dict_python(bench: &mut Bencher) {
);

let code = r#"{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7, "h": 8, "i": 9, "j": 0}"#.to_string();
let input = py.eval(&code, None, None).unwrap().to_object(py);
let input = py.eval_bound(&code, None, None).unwrap().to_object(py);
let input = black_box(input.bind(py));
bench.iter(|| {
let v = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand Down Expand Up @@ -410,13 +410,13 @@ fn typed_dict_deep_error(bench: &mut Bencher) {

let code = "{'field_a': '1', 'field_b': {'field_c': '2', 'field_d': {'field_e': '4', 'field_f': 'xx'}}}";

let input = py.eval(code, None, None).unwrap().to_object(py);
let input = py.eval_bound(code, None, None).unwrap().to_object(py);
let input = black_box(input.bind(py));

match validator.validate_python(py, &input, None, None, None, None) {
Ok(_) => panic!("unexpectedly valid"),
Err(e) => {
let v = e.value(py);
let v = e.value_bound(py);
// println!("error: {}", v.to_string());
assert_eq!(v.getattr("title").unwrap().to_string(), "typed-dict");
let error_count: i64 = v.call_method0("error_count").unwrap().extract().unwrap();
Expand All @@ -438,7 +438,7 @@ fn typed_dict_deep_error(bench: &mut Bencher) {
#[bench]
fn complete_model(bench: &mut Bencher) {
Python::with_gil(|py| {
let sys_path = py.import("sys").unwrap().getattr("path").unwrap();
let sys_path = py.import_bound("sys").unwrap().getattr("path").unwrap();
sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap();

let complete_schema = py.import_bound("complete_schema").unwrap();
Expand All @@ -458,7 +458,7 @@ fn complete_model(bench: &mut Bencher) {
#[bench]
fn nested_model_using_definitions(bench: &mut Bencher) {
Python::with_gil(|py| {
let sys_path = py.import("sys").unwrap().getattr("path").unwrap();
let sys_path = py.import_bound("sys").unwrap().getattr("path").unwrap();
sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap();

let complete_schema = py.import_bound("nested_schema").unwrap();
Expand All @@ -480,7 +480,7 @@ fn nested_model_using_definitions(bench: &mut Bencher) {
#[bench]
fn nested_model_inlined(bench: &mut Bencher) {
Python::with_gil(|py| {
let sys_path = py.import("sys").unwrap().getattr("path").unwrap();
let sys_path = py.import_bound("sys").unwrap().getattr("path").unwrap();
sys_path.call_method1("append", ("./tests/benchmarks/",)).unwrap();

let complete_schema = py.import_bound("nested_schema").unwrap();
Expand Down Expand Up @@ -520,7 +520,7 @@ fn literal_strings_few_small_python(bench: &mut Bencher) {
Python::with_gil(|py| {
let validator = build_schema_validator(py, "{'type': 'literal', 'expected': [f'{idx}' for idx in range(5)]}");

let input = py.eval("'4'", None, None).unwrap();
let input = py.eval_bound("'4'", None, None).unwrap();
let input = input.to_object(py).into_bound(py);
let input_str: String = input.extract().unwrap();
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand All @@ -540,7 +540,7 @@ fn literal_strings_few_large_python(bench: &mut Bencher) {
"{'type': 'literal', 'expected': ['a' * 25 + f'{idx}' for idx in range(5)]}",
);

let input = py.eval("'a' * 25 + '4'", None, None).unwrap();
let input = py.eval_bound("'a' * 25 + '4'", None, None).unwrap();
let input = input.to_object(py).into_bound(py);
let input_str: String = input.extract().unwrap();
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand All @@ -556,7 +556,7 @@ fn literal_strings_few_large_python(bench: &mut Bencher) {
fn literal_enums_few_python(bench: &mut Bencher) {
Python::with_gil(|py| {
let globals = PyDict::new_bound(py);
py.run(
py.run_bound(
r#"
from enum import Enum

Expand All @@ -566,18 +566,18 @@ class Foo(Enum):
v3 = object()
v4 = object()
"#,
Some(globals.as_gil_ref()),
Some(&globals),
None,
)
.unwrap();

let validator = build_schema_validator_with_globals(
py,
"{'type': 'literal', 'expected': [Foo.v1, Foo.v2, Foo.v3, Foo.v4]}",
Some(globals.as_gil_ref()),
Some(&globals),
);

let input = py.eval("Foo.v4", Some(globals.as_gil_ref()), None).unwrap();
let input = py.eval_bound("Foo.v4", Some(&globals), None).unwrap();
let input = input.to_object(py).into_bound(py);
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
assert!(input.eq(result).unwrap());
Expand Down Expand Up @@ -607,7 +607,7 @@ fn literal_strings_many_small_python(bench: &mut Bencher) {
Python::with_gil(|py| {
let validator = build_schema_validator(py, "{'type': 'literal', 'expected': [f'{idx}' for idx in range(100)]}");

let input = py.eval("'99'", None, None).unwrap();
let input = py.eval_bound("'99'", None, None).unwrap();
let input = input.to_object(py).into_bound(py);
let input_str: String = input.extract().unwrap();
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand All @@ -627,7 +627,7 @@ fn literal_strings_many_large_python(bench: &mut Bencher) {
"{'type': 'literal', 'expected': ['a' * 25 + f'{idx}' for idx in range(100)]}",
);

let input = py.eval("'a' * 25 + '99'", None, None).unwrap();
let input = py.eval_bound("'a' * 25 + '99'", None, None).unwrap();
let input = input.to_object(py).into_bound(py);
let input_str: String = input.extract().unwrap();
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand All @@ -644,7 +644,7 @@ fn literal_ints_many_json(bench: &mut Bencher) {
Python::with_gil(|py| {
let validator = build_schema_validator(py, "{'type': 'literal', 'expected': list(range(100))}");

let input_json = py.eval("'99'", None, None).unwrap();
let input_json = py.eval_bound("'99'", None, None).unwrap();
let input_json = input_json.to_object(py).into_bound(py);
let result = validator.validate_json(py, &input_json, None, None, None).unwrap();
let result_int: i64 = result.extract(py).unwrap();
Expand All @@ -663,9 +663,9 @@ fn literal_strings_many_large_json(bench: &mut Bencher) {
"{'type': 'literal', 'expected': ['a' * 25 + f'{idx}' for idx in range(100)]}",
);

let input = py.eval("'a' * 25 + '99'", None, None).unwrap();
let input = py.eval_bound("'a' * 25 + '99'", None, None).unwrap();
let input = input.to_object(py).into_bound(py);
let input_json = py.eval("'\"' + 'a' * 25 + '99' + '\"'", None, None).unwrap();
let input_json = py.eval_bound("'\"' + 'a' * 25 + '99' + '\"'", None, None).unwrap();
let input_json = input_json.to_object(py).into_bound(py);
let input_str: String = input.extract().unwrap();
let result = validator.validate_json(py, &input_json, None, None, None).unwrap();
Expand All @@ -681,7 +681,7 @@ fn literal_strings_many_large_json(bench: &mut Bencher) {
fn literal_mixed_few_python(bench: &mut Bencher) {
Python::with_gil(|py| {
let globals = PyDict::new_bound(py);
py.run(
py.run_bound(
r#"
from enum import Enum

Expand All @@ -691,19 +691,19 @@ class Foo(Enum):
v3 = object()
v4 = object()
"#,
Some(globals.as_gil_ref()),
Some(&globals),
None,
)
.unwrap();
let validator = build_schema_validator_with_globals(
py,
"{'type': 'literal', 'expected': [None, 'null', -1, Foo.v4]}",
Some(globals.as_gil_ref()),
Some(&globals),
);

// String
{
let input = py.eval("'null'", None, None).unwrap();
let input = py.eval_bound("'null'", None, None).unwrap();
let input = input.to_object(py).into_bound(py);
let input_str: String = input.extract().unwrap();
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand All @@ -716,7 +716,7 @@ class Foo(Enum):

// Int
{
let input = py.eval("-1", None, None).unwrap();
let input = py.eval_bound("-1", None, None).unwrap();
let input = input.to_object(py).into_bound(py);
let input_int: i64 = input.extract().unwrap();
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
Expand All @@ -729,7 +729,7 @@ class Foo(Enum):

// None
{
let input = py.eval("None", None, None).unwrap();
let input = py.eval_bound("None", None, None).unwrap();
let input = input.to_object(py).into_bound(py);
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
assert!(input.eq(result).unwrap());
Expand All @@ -740,7 +740,7 @@ class Foo(Enum):

// Enum
{
let input = py.eval("Foo.v4", Some(globals.as_gil_ref()), None).unwrap();
let input = py.eval_bound("Foo.v4", Some(&globals), None).unwrap();
let input = input.to_object(py).into_bound(py);
let result = validator.validate_python(py, &input, None, None, None, None).unwrap();
assert!(input.eq(result).unwrap());
Expand Down
6 changes: 3 additions & 3 deletions src/argument_markers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ impl ArgsKwargs {
#[pymethods]
impl ArgsKwargs {
#[new]
fn py_new(py: Python, args: &PyTuple, kwargs: Option<&PyDict>) -> Self {
fn py_new(py: Python, args: &PyTuple, kwargs: Option<&Bound<'_, PyDict>>) -> Self {
Self {
args: args.into_py(py),
kwargs: match kwargs {
Some(d) if !d.is_empty() => Some(d.into_py(py)),
Some(d) if !d.is_empty() => Some(d.to_owned().unbind()),
_ => None,
},
}
Expand Down Expand Up @@ -94,7 +94,7 @@ impl PydanticUndefinedType {
}

#[pyo3(signature = (_memo, /))]
fn __deepcopy__(&self, py: Python, _memo: &PyAny) -> Py<Self> {
fn __deepcopy__(&self, py: Python, _memo: &Bound<'_, PyAny>) -> Py<Self> {
self.__copy__(py)
}

Expand Down
10 changes: 5 additions & 5 deletions src/errors/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub fn list_all_errors(py: Python) -> PyResult<Bound<'_, PyList>> {
}

fn field_from_context<'py, T: FromPyObject<'py>>(
context: Option<&'py PyDict>,
context: Option<&Bound<'py, PyDict>>,
field_name: &str,
enum_name: &str,
type_name_fn: fn() -> &'static str,
Expand All @@ -57,7 +57,7 @@ fn field_from_context<'py, T: FromPyObject<'py>>(
}

fn cow_field_from_context<'py, T: FromPyObject<'py>, B: ?Sized + 'static>(
context: Option<&'py PyDict>,
context: Option<&Bound<'py, PyDict>>,
field_name: &str,
enum_name: &str,
_type_name_fn: fn() -> &'static str,
Expand Down Expand Up @@ -101,7 +101,7 @@ macro_rules! error_types {
),+,
}
impl ErrorType {
pub fn new(py: Python, value: &str, context: Option<&PyDict>) -> PyResult<Self> {
pub fn new(py: Python, value: &str, context: Option<Bound<'_, PyDict>>) -> PyResult<Self> {
let lookup = ERROR_TYPE_LOOKUP.get_or_init(py, Self::build_lookup);
let error_type = match lookup.get(value) {
Some(error_type) => error_type.clone(),
Expand All @@ -111,10 +111,10 @@ macro_rules! error_types {
$(
Self::$item { .. } => {
Ok(Self::$item {
context: context.map(|c| c.into_py(py)),
$(
$key: $ctx_fn(context, stringify!($key), stringify!($item), || stringify!($ctx_type))?,
$key: $ctx_fn(context.as_ref(), stringify!($key), stringify!($item), || stringify!($ctx_type))?,
)*
context: context.map(|c| c.unbind()),
})
},
)+
Expand Down
2 changes: 1 addition & 1 deletion src/errors/validation_exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ impl TryFrom<&Bound<'_, PyAny>> for PyLineError {
.ok_or_else(|| PyKeyError::new_err("type"))?;

let error_type = if let Ok(type_str) = type_raw.downcast::<PyString>() {
let context: Option<&PyDict> = dict.get_as(intern!(py, "ctx"))?;
let context: Option<Bound<'_, PyDict>> = dict.get_as(intern!(py, "ctx"))?;
ErrorType::new(py, type_str.to_str()?, context)?
} else if let Ok(custom_error) = type_raw.extract::<PydanticCustomError>() {
ErrorType::new_custom_error(py, custom_error)
Expand Down
6 changes: 3 additions & 3 deletions src/errors/value_exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ pub struct PydanticCustomError {
#[pymethods]
impl PydanticCustomError {
#[new]
pub fn py_new(py: Python, error_type: String, message_template: String, context: Option<&PyDict>) -> Self {
pub fn py_new(error_type: String, message_template: String, context: Option<Bound<'_, PyDict>>) -> Self {
Self {
error_type,
message_template,
context: context.map(|c| c.into_py(py)),
context: context.map(Bound::unbind),
}
}

Expand Down Expand Up @@ -143,7 +143,7 @@ pub struct PydanticKnownError {
#[pymethods]
impl PydanticKnownError {
#[new]
pub fn py_new(py: Python, error_type: &str, context: Option<&PyDict>) -> PyResult<Self> {
pub fn py_new(py: Python, error_type: &str, context: Option<Bound<'_, PyDict>>) -> PyResult<Self> {
let error_type = ErrorType::new(py, error_type, context)?;
Ok(Self { error_type })
}
Expand Down
6 changes: 3 additions & 3 deletions src/input/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,11 +562,11 @@ impl TzInfo {
hasher.finish()
}

fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyResult<Py<PyAny>> {
fn __richcmp__(&self, other: &Bound<'_, PyAny>, op: CompareOp) -> PyResult<Py<PyAny>> {
let py = other.py();
if other.is_instance_of::<PyTzInfo>() {
let offset_delta = other.call_method1(intern!(py, "utcoffset"), (py.None(),))?;
if offset_delta.is_none() {
if PyAnyMethods::is_none(&offset_delta) {
return Ok(py.NotImplemented());
}
let offset_seconds: f64 = offset_delta.call_method0(intern!(py, "total_seconds"))?.extract()?;
Expand All @@ -577,7 +577,7 @@ impl TzInfo {
}
}

fn __deepcopy__(&self, py: Python, _memo: &PyDict) -> PyResult<Py<Self>> {
fn __deepcopy__(&self, py: Python, _memo: &Bound<'_, PyDict>) -> PyResult<Py<Self>> {
Py::new(py, self.clone())
}

Expand Down
Loading