From cc7e785cba0b02e2512802bd57d3d29e2d7931d1 Mon Sep 17 00:00:00 2001 From: Caleb Hattingh Date: Tue, 7 May 2024 16:36:46 +0200 Subject: [PATCH] deps: upgrade PyO3 to 0.21 (#275) --- .github/workflows/ci.yml | 5 +++ Cargo.lock | 32 ++++++++++------- Cargo.toml | 6 ++-- src/document.rs | 77 ++++++++++++++++++++++++---------------- src/facet.rs | 10 +++--- src/index.rs | 2 +- src/lib.rs | 6 ++-- src/query.rs | 16 ++++----- src/schema.rs | 10 +++--- 9 files changed, 96 insertions(+), 68 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fdae028..af283bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,15 +42,20 @@ jobs: run: cargo fmt --check Test: + continue-on-error: ${{ matrix.python-version == '3.13' }} + env: + UNSAFE_PYO3_SKIP_VERSION_CHECK: ${{ matrix.unsafe-pyo3-skip-version-check }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.12"] allow-prereleases: [false] + unsafe-pyo3-skip-version-check: [0] include: - os: ubuntu-latest python-version: "3.13" allow-prereleases: true + unsafe-pyo3-skip-version-check: 1 - os: ubuntu-latest python-version: "3.11" allow-prereleases: false diff --git a/Cargo.lock b/Cargo.lock index 7eb097b..3747ad3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -722,6 +722,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "powerfmt" version = "0.2.0" @@ -745,9 +751,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.20.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8453b658fe480c3e70c8ed4e3d3ec33eb74988bd186561b0cc66b85c3bc4b" +checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" dependencies = [ "cfg-if", "chrono", @@ -755,6 +761,7 @@ dependencies = [ "libc", "memoffset", "parking_lot", + "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", @@ -763,9 +770,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.20.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5" +checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" dependencies = [ "once_cell", "target-lexicon", @@ -773,9 +780,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.20.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214929900fd25e6604661ed9cf349727c8920d47deff196c4e28165a6ef2a96b" +checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" dependencies = [ "libc", "pyo3-build-config", @@ -783,9 +790,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.20.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac53072f717aa1bfa4db832b39de8c875b7c7af4f4a6fe93cdbf9264cf8383b" +checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -795,21 +802,22 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.20.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774b5a8282bd4f25f803b1f0d945120be959a36c72e08e7cd031c792fdfd424" +checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" dependencies = [ "heck", "proc-macro2", + "pyo3-build-config", "quote", "syn", ] [[package]] name = "pythonize" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffd1c3ef39c725d63db5f9bc455461bafd80540cb7824c61afb823501921a850" +checksum = "9d0664248812c38cc55a4ed07f88e4df516ce82604b93b1ffdc041aa77a6cb3c" dependencies = [ "pyo3", "serde", diff --git a/Cargo.toml b/Cargo.toml index fd38541..00e2b47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ name = "tantivy" crate-type = ["cdylib"] [build-dependencies] -pyo3-build-config = "0.20.0" +pyo3-build-config = "0.21.0" [dependencies] base64 = "0.22" @@ -19,10 +19,10 @@ chrono = "0.4.38" tantivy = "0.22.0" itertools = "0.12.1" futures = "0.3.30" -pythonize = "0.20.0" +pythonize = "0.21.0" serde = "1.0" serde_json = "1.0.116" [dependencies.pyo3] -version = "0.20.0" +version = "0.21.0" features = ["chrono", "extension-module"] diff --git a/src/document.rs b/src/document.rs index db0ab0c..ac391ab 100644 --- a/src/document.rs +++ b/src/document.rs @@ -27,7 +27,7 @@ use std::{ str::FromStr, }; -pub(crate) fn extract_value(any: &PyAny) -> PyResult { +pub(crate) fn extract_value(any: &Bound) -> PyResult { if let Ok(s) = any.extract::() { return Ok(Value::Str(s)); } @@ -42,7 +42,7 @@ pub(crate) fn extract_value(any: &PyAny) -> PyResult { } if let Ok(datetime) = any.extract::() { return Ok(Value::Date(tv::DateTime::from_timestamp_secs( - datetime.timestamp(), + datetime.and_utc().timestamp(), ))); } if let Ok(facet) = any.extract::() { @@ -52,7 +52,8 @@ pub(crate) fn extract_value(any: &PyAny) -> PyResult { return Ok(Value::Bytes(b)); } if let Ok(dict) = any.downcast::() { - if let Ok(json) = pythonize::depythonize(dict) { + if let Ok(json) = pythonize::depythonize_bound(dict.clone().into_any()) + { return Ok(Value::Object(json)); } } @@ -60,7 +61,7 @@ pub(crate) fn extract_value(any: &PyAny) -> PyResult { } pub(crate) fn extract_value_for_type( - any: &PyAny, + any: &Bound, tv_type: tv::schema::Type, field_name: &str, ) -> PyResult { @@ -68,7 +69,7 @@ pub(crate) fn extract_value_for_type( fn to_pyerr_for_type<'a, E: std::error::Error>( type_name: &'a str, field_name: &'a str, - any: &'a PyAny, + any: &'a Bound, ) -> impl Fn(E) -> PyErr + 'a { move |_| { to_pyerr(format!( @@ -104,7 +105,9 @@ pub(crate) fn extract_value_for_type( .extract::() .map_err(to_pyerr_for_type("DateTime", field_name, any))?; - Value::Date(tv::DateTime::from_timestamp_secs(datetime.timestamp())) + Value::Date(tv::DateTime::from_timestamp_secs( + datetime.and_utc().timestamp(), + )) } tv::schema::Type::Facet => Value::Facet( any.extract::() @@ -124,9 +127,11 @@ pub(crate) fn extract_value_for_type( Value::Object( any.downcast::() - .map(|dict| pythonize::depythonize(dict)) - .map_err(to_pyerr_for_type("Json", field_name, any))? - .map_err(to_pyerr_for_type("Json", field_name, any))?, + .map_err(to_pyerr_for_type("Json", field_name, any)) + .and_then(|dict| { + pythonize::depythonize_bound(dict.clone().into_any()) + .map_err(to_pyerr_for_type("Json", field_name, any)) + })?, ) } tv::schema::Type::IpAddr => { @@ -147,16 +152,16 @@ pub(crate) fn extract_value_for_type( Ok(value) } -fn extract_value_single_or_list(any: &PyAny) -> PyResult> { +fn extract_value_single_or_list(any: &Bound) -> PyResult> { if let Ok(values) = any.downcast::() { - values.iter().map(extract_value).collect() + values.iter().map(|v| extract_value(&v)).collect() } else { Ok(vec![extract_value(any)?]) } } fn extract_value_single_or_list_for_type( - any: &PyAny, + any: &Bound, field_type: &tv::schema::FieldType, field_name: &str, ) -> PyResult> { @@ -179,7 +184,11 @@ fn extract_value_single_or_list_for_type( values .iter() .map(|any| { - extract_value_for_type(any, field_type.value_type(), field_name) + extract_value_for_type( + &any, + field_type.value_type(), + field_name, + ) }) .collect() } else { @@ -195,7 +204,7 @@ fn object_to_py( py: Python, obj: &BTreeMap, ) -> PyResult { - let dict = PyDict::new(py); + let dict = PyDict::new_bound(py); for (k, v) in obj.iter() { dict.set_item(k, value_to_py(py, v)?)?; } @@ -216,7 +225,7 @@ fn value_to_py(py: Python, value: &Value) -> PyResult { } Value::Date(d) => { let utc = d.into_utc(); - PyDateTime::new( + PyDateTime::new_bound( py, utc.year(), utc.month() as u8, @@ -538,7 +547,7 @@ impl Document { /// [`extend()`], or `add_()` functions. #[new] #[pyo3(signature = (**kwargs))] - fn new(kwargs: Option<&PyDict>) -> PyResult { + fn new(kwargs: Option<&Bound>) -> PyResult { let mut document = Document::default(); if let Some(field_dict) = kwargs { document.extend(field_dict, None)?; @@ -548,7 +557,7 @@ impl Document { fn extend( &mut self, - py_dict: &PyDict, + py_dict: &Bound, schema: Option<&Schema>, ) -> PyResult<()> { Document::extract_py_values_from_dict( @@ -560,7 +569,7 @@ impl Document { #[staticmethod] fn from_dict( - py_dict: &PyDict, + py_dict: &Bound, schema: Option<&Schema>, ) -> PyResult { let mut field_values: BTreeMap> = BTreeMap::new(); @@ -581,7 +590,7 @@ impl Document { /// For this reason, the dictionary, will associate /// a list of value for every field. fn to_dict(&self, py: Python) -> PyResult { - let dict = PyDict::new(py); + let dict = PyDict::new_bound(py); for (key, values) in &self.field_values { let values_py: Vec = values .iter() @@ -642,7 +651,7 @@ impl Document { /// Args: /// field_name (str): The field name for which we are adding the date. /// value (datetime): The date that will be added to the document. - fn add_date(&mut self, field_name: String, value: &PyDateTime) { + fn add_date(&mut self, field_name: String, value: &Bound) { let datetime = Utc .with_ymd_and_hms( value.get_year(), @@ -685,7 +694,11 @@ impl Document { /// to the document. /// /// Raises a ValueError if the JSON is invalid. - fn add_json(&mut self, field_name: String, value: &PyAny) -> PyResult<()> { + fn add_json( + &mut self, + field_name: String, + value: &Bound, + ) -> PyResult<()> { type JsonMap = serde_json::Map; if let Ok(json_str) = value.extract::<&str>() { @@ -693,7 +706,9 @@ impl Document { serde_json::from_str(json_str).map_err(to_pyerr)?; self.add_value(field_name, json_map); Ok(()) - } else if let Ok(json_map) = pythonize::depythonize::(value) { + } else if let Ok(json_map) = + pythonize::depythonize_bound::(value.clone()) + { self.add_value(field_name, json_map); Ok(()) } else { @@ -760,7 +775,7 @@ impl Document { self.clone() } - fn __deepcopy__(&self, _memo: &PyDict) -> Self { + fn __deepcopy__(&self, _memo: &Bound) -> Self { self.clone() } @@ -778,21 +793,21 @@ impl Document { } #[staticmethod] - fn _internal_from_pythonized(serialized: &PyAny) -> PyResult { - pythonize::depythonize(serialized).map_err(to_pyerr) + fn _internal_from_pythonized(serialized: &Bound) -> PyResult { + pythonize::depythonize_bound(serialized.clone()).map_err(to_pyerr) } fn __reduce__<'a>( slf: PyRef<'a, Self>, py: Python<'a>, - ) -> PyResult<&'a PyTuple> { + ) -> PyResult> { let serialized = pythonize::pythonize(py, &*slf).map_err(to_pyerr)?; - Ok(PyTuple::new( + Ok(PyTuple::new_bound( py, [ slf.into_py(py).getattr(py, "_internal_from_pythonized")?, - PyTuple::new(py, [serialized]).to_object(py), + PyTuple::new_bound(py, [serialized]).to_object(py), ], )) } @@ -810,7 +825,7 @@ impl Document { } fn extract_py_values_from_dict( - py_dict: &PyDict, + py_dict: &Bound, schema: Option<&Schema>, out_field_values: &mut BTreeMap>, ) -> PyResult<()> { @@ -847,12 +862,12 @@ impl Document { let value_list = if let Some(field_type) = field_type { extract_value_single_or_list_for_type( - key_value.get_item(1)?, + &key_value.get_item(1)?, field_type, key.as_str(), )? } else { - extract_value_single_or_list(key_value.get_item(1)?)? + extract_value_single_or_list(&key_value.get_item(1)?)? }; out_field_values.insert(key, value_list); diff --git a/src/facet.rs b/src/facet.rs index 74fb598..b1a52b6 100644 --- a/src/facet.rs +++ b/src/facet.rs @@ -34,7 +34,7 @@ impl Facet { /// Create a new instance of the "root facet" Equivalent to /. #[classmethod] - fn root(_cls: &PyType) -> Facet { + fn root(_cls: &Bound) -> Facet { Facet { inner: schema::Facet::root(), } @@ -60,7 +60,7 @@ impl Facet { /// /// Returns the created Facet. #[classmethod] - fn from_string(_cls: &PyType, facet_string: &str) -> Facet { + fn from_string(_cls: &Bound, facet_string: &str) -> Facet { Facet { inner: schema::Facet::from(facet_string), } @@ -98,13 +98,13 @@ impl Facet { fn __reduce__<'a>( slf: PyRef<'a, Self>, py: Python<'a>, - ) -> PyResult<&'a PyTuple> { + ) -> PyResult> { let encoded_bytes = slf.inner.encoded_str().as_bytes().to_vec(); - Ok(PyTuple::new( + Ok(PyTuple::new_bound( py, [ slf.into_py(py).getattr(py, "from_encoded")?, - PyTuple::new(py, [encoded_bytes]).to_object(py), + PyTuple::new_bound(py, [encoded_bytes]).to_object(py), ], )) } diff --git a/src/index.rs b/src/index.rs index 5669ba2..316bca9 100644 --- a/src/index.rs +++ b/src/index.rs @@ -154,7 +154,7 @@ impl IndexWriter { fn delete_documents( &mut self, field_name: &str, - field_value: &PyAny, + field_value: &Bound, ) -> PyResult { let field = get_field(&self.schema, field_name)?; let value = extract_value(field_value)?; diff --git a/src/lib.rs b/src/lib.rs index af72865..dd1a5af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,7 +74,7 @@ use crate::document::extract_value; /// >>> assert len(result) == 1 /// #[pymodule] -fn tantivy(_py: Python, m: &PyModule) -> PyResult<()> { +fn tantivy(_py: Python, m: &Bound) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -119,7 +119,7 @@ fn tantivy(_py: Python, m: &PyModule) -> PyResult<()> { /// >>> assert isinstance(errors[0], query_parser_error.FieldDoesNotExistError) /// >>> assert isinstance(errors[1], query_parser_error.ExpectedIntError) #[pymodule] -fn query_parser_error(_py: Python, m: &PyModule) -> PyResult<()> { +fn query_parser_error(_py: Python, m: &Bound) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -161,7 +161,7 @@ pub(crate) fn get_field( pub(crate) fn make_term( schema: &tv::schema::Schema, field_name: &str, - field_value: &PyAny, + field_value: &Bound, ) -> PyResult { let field = get_field(schema, field_name)?; let value = extract_value(field_value)?; diff --git a/src/query.rs b/src/query.rs index a963211..d38a747 100644 --- a/src/query.rs +++ b/src/query.rs @@ -71,7 +71,7 @@ impl Query { pub(crate) fn term_query( schema: &Schema, field_name: &str, - field_value: &PyAny, + field_value: &Bound, index_option: &str, ) -> PyResult { let term = make_term(&schema.inner, field_name, field_value)?; @@ -95,12 +95,12 @@ impl Query { pub(crate) fn term_set_query( schema: &Schema, field_name: &str, - field_values: Vec<&PyAny>, + field_values: Vec>, ) -> PyResult { let terms = field_values .into_iter() .map(|field_value| { - make_term(&schema.inner, field_name, field_value) + make_term(&schema.inner, field_name, &field_value) }) .collect::, _>>()?; let inner = tv::query::TermSetQuery::new(terms); @@ -133,7 +133,7 @@ impl Query { pub(crate) fn fuzzy_term_query( schema: &Schema, field_name: &str, - text: &PyString, + text: &Bound, distance: u8, transposition_cost_one: bool, prefix: bool, @@ -170,18 +170,18 @@ impl Query { pub(crate) fn phrase_query( schema: &Schema, field_name: &str, - words: Vec<&PyAny>, + words: Vec>, slop: u32, ) -> PyResult { let mut terms_with_offset = Vec::with_capacity(words.len()); for (idx, word) in words.into_iter().enumerate() { if let Ok((offset, value)) = word.extract() { // Custom offset is provided. - let term = make_term(&schema.inner, field_name, value)?; + let term = make_term(&schema.inner, field_name, &value)?; terms_with_offset.push((offset, term)); } else { // Custom offset is not provided. Use the list index as the offset. - let term = make_term(&schema.inner, field_name, word)?; + let term = make_term(&schema.inner, field_name, &word)?; terms_with_offset.push((idx, term)); }; } @@ -221,7 +221,7 @@ impl Query { #[staticmethod] pub(crate) fn disjunction_max_query( subqueries: Vec, - tie_breaker: Option<&PyFloat>, + tie_breaker: Option>, ) -> PyResult { let inner_queries: Vec> = subqueries .iter() diff --git a/src/schema.rs b/src/schema.rs index 122a971..d1b5549 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -29,21 +29,21 @@ impl Schema { } #[staticmethod] - fn _internal_from_pythonized(serialized: &PyAny) -> PyResult { - pythonize::depythonize(serialized).map_err(to_pyerr) + fn _internal_from_pythonized(serialized: &Bound) -> PyResult { + pythonize::depythonize_bound(serialized.clone()).map_err(to_pyerr) } fn __reduce__<'a>( slf: PyRef<'a, Self>, py: Python<'a>, - ) -> PyResult<&'a PyTuple> { + ) -> PyResult> { let serialized = pythonize::pythonize(py, &*slf).map_err(to_pyerr)?; - Ok(PyTuple::new( + Ok(PyTuple::new_bound( py, [ slf.into_py(py).getattr(py, "_internal_from_pythonized")?, - PyTuple::new(py, [serialized]).to_object(py), + PyTuple::new_bound(py, [serialized]).to_object(py), ], )) }