diff --git a/CHANGELOG.md b/CHANGELOG.md index 4660cfbe..aaefbf0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Bump `pyO3` and `rust-numpy` to 0.26.0: introduce Python build 3.14/3.14t support https://github.com/light-curve/light-curve-python/pull/553 -- **Breaking** macOS x86\_64 binary wheel now requires macOS 15 instead of 13 https://github.com/light-curve/light-curve-python/issues/587 +- Bump `pyO3` and `rust-numpy` from 0.25.0 to 0.27.0: introduce Python build 3.14/3.14t + support https://github.com/light-curve/light-curve-python/pull/553 https://github.com/light-curve/light-curve-python/pull/590 +- **Breaking** macOS x86\_64 binary wheel now requires macOS 15 instead of + 13 https://github.com/light-curve/light-curve-python/issues/587 ### Deprecated diff --git a/light-curve/Cargo.lock b/light-curve/Cargo.lock index 06080ff0..e276cc9e 100644 --- a/light-curve/Cargo.lock +++ b/light-curve/Cargo.lock @@ -1411,9 +1411,9 @@ dependencies = [ [[package]] name = "numpy" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2dba356160b54f5371b550575b78130a54718b4c6e46b3f33a6da74a27e78b" +checksum = "0fa24ffc88cf9d43f7269d6b6a0d0a00010924a8cc90604a21ef9c433b66998d" dependencies = [ "libc", "ndarray 0.16.1", @@ -1601,9 +1601,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383" +checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf" dependencies = [ "indoc", "inventory", @@ -1619,18 +1619,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f" +checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb" dependencies = [ "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105" +checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be" dependencies = [ "libc", "pyo3-build-config", @@ -1638,9 +1638,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded" +checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -1650,9 +1650,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.26.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf" +checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b" dependencies = [ "heck", "proc-macro2", diff --git a/light-curve/Cargo.toml b/light-curve/Cargo.toml index 47294308..dda03523 100644 --- a/light-curve/Cargo.toml +++ b/light-curve/Cargo.toml @@ -47,11 +47,11 @@ mimalloc = { version = "0.1.48", features = [ "local_dynamic_tls", ], optional = true } ndarray = { version = "0.16.1", features = ["rayon"] } -numpy = "0.26.0" +numpy = "0.27.0" num_cpus = "1.17.0" num-traits = "0.2" once_cell = "1" -pyo3 = { version = "0.26.0", features = [ +pyo3 = { version = "0.27.1", features = [ "extension-module", "multiple-pymethods", ] } diff --git a/light-curve/src/dmdt.rs b/light-curve/src/dmdt.rs index bd7bf726..42d13c72 100644 --- a/light-curve/src/dmdt.rs +++ b/light-curve/src/dmdt.rs @@ -112,7 +112,7 @@ where let wrapped_t_ = t_ .into_iter() .enumerate() - .map(|(i, t)| match t.downcast::>() { + .map(|(i, t)| match t.cast::>() { Ok(a) => Ok(a.readonly()), Err(_) => Err(Exception::TypeError(format!( "t_[{}] has mismatched dtype with the t_[0] which is {}", @@ -189,8 +189,8 @@ where .into_iter() .enumerate() .map(|(i, (t, m))| { - let t = t.downcast::>().map(|a| a.readonly()); - let m = m.downcast::>().map(|a| a.readonly()); + let t = t.cast::>().map(|a| a.readonly()); + let m = m.cast::>().map(|a| a.readonly()); match (t, m) { (Ok(t), Ok(m)) => Ok((t, m)), _ => Err(Exception::TypeError(format!( @@ -256,8 +256,8 @@ where .into_iter() .enumerate() .map(|(i, (t, m))| { - let t = t.downcast::>().map(|a| a.readonly()); - let m = m.downcast::>().map(|a| a.readonly()); + let t = t.cast::>().map(|a| a.readonly()); + let m = m.cast::>().map(|a| a.readonly()); match (t, m) { (Ok(t), Ok(m)) => { let t: ContArray<_> = t.as_array().into(); @@ -332,9 +332,9 @@ where .into_iter() .enumerate() .map(|(i, (t, m, sigma))| { - let t = t.downcast::>().map(|a| a.readonly()); - let m = m.downcast::>().map(|a| a.readonly()); - let sigma = sigma.downcast::>().map(|a| a.readonly()); + let t = t.cast::>().map(|a| a.readonly()); + let m = m.cast::>().map(|a| a.readonly()); + let sigma = sigma.cast::>().map(|a| a.readonly()); match (t, m, sigma) { (Ok(t), Ok(m), Ok(sigma)) => Ok((t, m, Self::sigma_to_err2(sigma))), @@ -406,9 +406,9 @@ where .into_iter() .enumerate() .map(|(i, (t, m, sigma))| { - let t = t.downcast::>().map(|a| a.readonly()); - let m = m.downcast::>().map(|a| a.readonly()); - let sigma = sigma.downcast::>().map(|a| a.readonly()); + let t = t.cast::>().map(|a| a.readonly()); + let m = m.cast::>().map(|a| a.readonly()); + let sigma = sigma.cast::>().map(|a| a.readonly()); match (t, m, sigma) { (Ok(t), Ok(m), Ok(sigma)) => { diff --git a/light-curve/src/features.rs b/light-curve/src/features.rs index 9709a75c..dc1632d4 100644 --- a/light-curve/src/features.rs +++ b/light-curve/src/features.rs @@ -339,10 +339,10 @@ impl PyFeatureEvaluator { .into_iter() .enumerate() .map(|(i, (t, m, sigma))| { - let t = t.downcast::>().map(|a| a.readonly()); - let m = m.downcast::>().map(|a| a.readonly()); + let t = t.cast::>().map(|a| a.readonly()); + let m = m.cast::>().map(|a| a.readonly()); let sigma = match &sigma { - Some(sigma) => sigma.downcast::>().map(|a| Some(a.readonly())), + Some(sigma) => sigma.cast::>().map(|a| Some(a.readonly())), None => Ok(None), }; @@ -1014,7 +1014,7 @@ macro_rules! fit_evaluator { let make_transformation = match transform { None => false, - Some(py_transform) => match py_transform.downcast::() { + Some(py_transform) => match py_transform.cast::() { Ok(py_bool) => py_bool.is_true(), Err(_) => return Err(PyValueError::new_err( "transform must be a bool or None, other types are not implemented yet", @@ -1262,7 +1262,7 @@ impl Bins { let mut eval_f32 = lcf::Bins::default(); let mut eval_f64 = lcf::Bins::default(); for x in features.try_iter()? { - let py_feature = x?.downcast::()?.borrow(); + let py_feature = x?.cast::()?.borrow(); eval_f32.add_feature(py_feature.feature_evaluator_f32.clone()); eval_f64.add_feature(py_feature.feature_evaluator_f64.clone()); } @@ -1684,7 +1684,7 @@ impl Periodogram { const STEP_SIZE_TOLLERANCE: f64 = 10.0 * f32::EPSILON as f64; // It is more likely for users to give f64 array - let freqs_f64 = PyArrayLike1::::extract_bound(&freqs)?; + let freqs_f64 = PyArrayLike1::::extract(freqs.as_borrowed())?; let freqs_f64 = freqs_f64.readonly(); let freqs_f64 = freqs_f64.as_array(); let size = freqs_f64.len(); @@ -1726,7 +1726,8 @@ impl Periodogram { let freq_grid_f32 = match &freq_grid_f64 { FreqGrid::Arbitrary(_) => { - let freqs_f32 = PyArrayLike1::::extract_bound(&freqs)?; + let freqs_f32 = + PyArrayLike1::::extract(freqs.as_borrowed())?; let freqs_f32 = freqs_f32.readonly(); let freqs_f32 = freqs_f32.as_array(); FreqGrid::from_array(freqs_f32) @@ -1748,7 +1749,7 @@ impl Periodogram { if let Some(features) = features { for x in features.try_iter()? { - let py_feature = x?.downcast::()?.borrow(); + let py_feature = x?.cast::()?.borrow(); eval_f32.add_feature(py_feature.feature_evaluator_f32.clone()); eval_f64.add_feature(py_feature.feature_evaluator_f64.clone()); } diff --git a/light-curve/src/np_array.rs b/light-curve/src/np_array.rs index f1d98e5a..48f9ab3a 100644 --- a/light-curve/src/np_array.rs +++ b/light-curve/src/np_array.rs @@ -27,7 +27,7 @@ impl DType for f64 { } pub(crate) fn unknown_type_exception(name: &str, obj: &Bound) -> Exception { - let message = if let Ok(arr) = obj.downcast::() { + let message = if let Ok(arr) = obj.cast::() { let ndim = arr.ndim(); if ndim != 1 { format!("'{name}' is a {ndim}-d array, only 1-d arrays are supported.") @@ -59,13 +59,13 @@ fn cast_fail_reason( let first_name = names.first().expect("Empty names slice"); let fist_obj = objects.first().expect("Empty objects slice"); - // If the very first argument downcast + // If the very first argument cast if idx == 0 { return unknown_type_exception(first_name, fist_obj); } - let maybe_first_f32_array = try_downcast_to_f32_array(objects[0]); - let maybe_first_f64_array = try_downcast_to_f64_array(objects[0], cast); + let maybe_first_f32_array = try_cast_to_f32_array(objects[0]); + let maybe_first_f64_array = try_cast_to_f64_array(objects[0], cast); let (first_arr, first_dtype_name) = if let Some(f32_array) = maybe_first_f32_array.as_ref() { (f32_array.as_untyped(), f32::dtype_name()) } else if let Some(f64_array) = maybe_first_f64_array.as_ref() { @@ -79,7 +79,7 @@ fn cast_fail_reason( .get(idx) .expect("idx is out of bounds of objects slice"); - let error_message = if let Ok(fail_arr) = fail_obj.downcast::() { + let error_message = if let Ok(fail_arr) = fail_obj.cast::() { if fail_arr.ndim() != 1 { format!( "'{}' is a {}-d array, only 1-d arrays are supported.", @@ -125,12 +125,12 @@ impl GenericPyReadonlyArrays<'_, N> { } } -fn try_downcast_objects_to_f32_arrays<'py, const N: usize>( +fn try_cast_objects_to_f32_arrays<'py, const N: usize>( objects: &[&Bound<'py, PyAny>; N], ) -> [Option>; N] { let mut arrays = [const { None }; N]; for (&obj, arr) in objects.iter().zip(arrays.iter_mut()) { - *arr = try_downcast_to_f32_array(obj); + *arr = try_cast_to_f32_array(obj); // If we cannot cast an array, we stop trying for future arguments if arr.is_none() { break; @@ -139,18 +139,18 @@ fn try_downcast_objects_to_f32_arrays<'py, const N: usize>( arrays } -fn try_downcast_to_f32_array<'py>(obj: &Bound<'py, PyAny>) -> Option> { - let py_array = obj.downcast::>().ok()?; +fn try_cast_to_f32_array<'py>(obj: &Bound<'py, PyAny>) -> Option> { + let py_array = obj.cast::>().ok()?; Some(py_array.readonly()) } -fn try_downcast_to_f64_array<'py>( +fn try_cast_to_f64_array<'py>( obj: &Bound<'py, PyAny>, cast: bool, ) -> Option> { - match (obj.downcast::>(), cast) { + match (obj.cast::>(), cast) { (Ok(py_array), _) => Some(py_array.readonly()), - (Err(_), true) => match PyArrayLike1::::extract_bound(obj) { + (Err(_), true) => match PyArrayLike1::::extract(obj.as_borrowed()) { Ok(py_array) => Some(py_array.readonly()), Err(_) => None, }, @@ -168,11 +168,11 @@ const fn index() -> [usize; N] { arr } -fn downcast_objects_cast<'py, const N: usize>( +fn cast_objects_with_dtype_change<'py, const N: usize>( names: &'static [&'static str; N], objects: &[&Bound<'py, PyAny>; N], ) -> Res> { - let f32_arrays = try_downcast_objects_to_f32_arrays(objects); + let f32_arrays = try_cast_objects_to_f32_arrays(objects); if f32_arrays.iter().all(|arr| arr.is_some()) { Ok(GenericPyReadonlyArrays::F32( @@ -183,7 +183,7 @@ fn downcast_objects_cast<'py, const N: usize>( let f64_arr = if let Some(f32_arr) = &f32_arrays[i] { f32_arr.cast_array::(false)?.readonly() } else { - try_downcast_to_f64_array(objects[i], true) + try_cast_to_f64_array(objects[i], true) .ok_or_else(|| cast_fail_reason(i, names, objects, true))? }; Ok(f64_arr) @@ -193,11 +193,11 @@ fn downcast_objects_cast<'py, const N: usize>( } } -fn downcast_objects_no_cast<'py, const N: usize>( +fn cast_objects_no_dtype_change<'py, const N: usize>( names: &'static [&'static str; N], objects: &[&Bound<'py, PyAny>; N], ) -> Res> { - let f32_arrays = try_downcast_objects_to_f32_arrays(objects); + let f32_arrays = try_cast_objects_to_f32_arrays(objects); if f32_arrays.iter().all(|arr| arr.is_some()) { Ok(GenericPyReadonlyArrays::F32( @@ -208,7 +208,7 @@ fn downcast_objects_no_cast<'py, const N: usize>( let f64_arrays = objects .map_option(|obj| { valid_f64_count += 1; - try_downcast_to_f64_array(obj, false) + try_cast_to_f64_array(obj, false) }) .ok_or_else(|| { let valid_f32_count = f32_arrays.iter().filter(|arr| arr.is_some()).count(); @@ -224,7 +224,7 @@ fn downcast_objects_no_cast<'py, const N: usize>( } } -pub(crate) fn downcast_and_validate<'py, const N: usize>( +pub(crate) fn cast_and_validate<'py, const N: usize>( names: &'static [&'static str; N], objects: &[&Bound<'py, PyAny>; N], check_size: &[bool; N], @@ -233,9 +233,9 @@ pub(crate) fn downcast_and_validate<'py, const N: usize>( assert_eq!(names.len(), objects.len()); let arrays = if cast { - downcast_objects_cast(names, objects)? + cast_objects_with_dtype_change(names, objects)? } else { - downcast_objects_no_cast(names, objects)? + cast_objects_no_dtype_change(names, objects)? }; let mut first_array_len = None; // We checked that 1) names size matches objects size, 2) objects is not empty @@ -299,7 +299,7 @@ macro_rules! dtype_dispatch { let objects = &[&$first_arg, $(&$arg, )*]; let check_size = &[ false, $(_distinguish_eq_symbol!($eq), )* ]; - let generic_arrays = crate::np_array::downcast_and_validate(names, objects, check_size, $cast)?; + let generic_arrays = crate::np_array::cast_and_validate(names, objects, check_size, $cast)?; match generic_arrays { crate::np_array::GenericPyReadonlyArrays::F32(arrays) => { let func = $f32; diff --git a/light-curve/src/transform.rs b/light-curve/src/transform.rs index 55c4c5ec..99d9b43b 100644 --- a/light-curve/src/transform.rs +++ b/light-curve/src/transform.rs @@ -110,13 +110,13 @@ pub(crate) fn parse_transform( match option { None => Ok(None), Some(py_any) => { - if let Ok(py_bool) = py_any.downcast::() { + if let Ok(py_bool) = py_any.cast::() { if py_bool.is_true() { Ok(Some(default)) } else { Ok(None) } - } else if let Ok(py_str) = py_any.downcast::() { + } else if let Ok(py_str) = py_any.cast::() { // py_str.to_str() is Python 3.10+ only let cow_string = py_str.to_cow()?; let s = cow_string.as_ref();