diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 4fba11e2172..24e8a76401f 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -1080,7 +1080,8 @@ impl BuildFlags { script.push_str("config = sysconfig.get_config_vars()\n"); for k in &BuildFlags::ALL { - script.push_str(&format!("print(config.get('{}', '0'))\n", k)); + use std::fmt::Write; + writeln!(&mut script, "print(config.get('{}', '0'))", k).unwrap(); } let stdout = run_python_script(interpreter.as_ref(), &script)?; @@ -1229,7 +1230,8 @@ fn find_sysconfigdata(cross: &CrossCompileConfig) -> Result> { sysconfigdata files found:", ); for path in sysconfig_paths { - error_msg += &format!("\n\t{}", path.display()); + use std::fmt::Write; + write!(&mut error_msg, "\n\t{}", path.display()).unwrap(); } bail!("{}\n", error_msg); } diff --git a/src/conversion.rs b/src/conversion.rs index 04ad9c688ef..29119928660 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -598,6 +598,23 @@ where } } +/// ```rust,compile_fail +/// use pyo3::prelude::*; +/// +/// #[pyclass] +/// struct TestClass { +/// num: u32, +/// } +/// +/// let t = TestClass { num: 10 }; +/// +/// Python::with_gil(|py| { +/// let pyvalue = Py::new(py, t).unwrap().to_object(py); +/// let t: TestClass = pyvalue.extract(py).unwrap(); +/// }) +/// ``` +mod test_no_clone {} + #[cfg(test)] mod tests { use crate::types::{IntoPyDict, PyAny, PyDict, PyList}; diff --git a/src/impl_/frompyobject.rs b/src/impl_/frompyobject.rs index 824842a60a1..a0c7b13df7c 100644 --- a/src/impl_/frompyobject.rs +++ b/src/impl_/frompyobject.rs @@ -15,23 +15,26 @@ pub fn failed_to_extract_enum( error_names.join(" | ") ); for ((variant_name, error_name), error) in variant_names.iter().zip(error_names).zip(errors) { - err_msg.push('\n'); - err_msg.push_str(&format!( - "- variant {variant_name} ({error_name}): {error_msg}", + use std::fmt::Write; + write!( + &mut err_msg, + "\n- variant {variant_name} ({error_name}): {error_msg}", variant_name = variant_name, error_name = error_name, error_msg = extract_traceback(py, error.clone_ref(py)), - )); + ) + .unwrap(); } PyTypeError::new_err(err_msg) } /// Flattens a chain of errors into a single string. fn extract_traceback(py: Python<'_>, mut error: PyErr) -> String { + use std::fmt::Write; + let mut error_msg = error.to_string(); while let Some(cause) = error.cause(py) { - error_msg.push_str(", caused by "); - error_msg.push_str(&cause.to_string()); + write!(&mut error_msg, ", caused by {}", cause).unwrap(); error = cause } error_msg diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index 349cc20e6e0..6e34e1847ff 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -51,6 +51,7 @@ fn _test_compile_errors() { tests_rust_1_57(&t); tests_rust_1_58(&t); tests_rust_1_60(&t); + tests_rust_1_62(&t); #[rustversion::since(1.49)] fn tests_rust_1_49(t: &trybuild::TestCases) { @@ -62,7 +63,7 @@ fn _test_compile_errors() { #[rustversion::since(1.56)] fn tests_rust_1_56(t: &trybuild::TestCases) { t.compile_fail("tests/ui/invalid_closure.rs"); - t.compile_fail("tests/ui/invalid_result_conversion.rs"); + t.compile_fail("tests/ui/pyclass_send.rs"); } @@ -84,7 +85,6 @@ fn _test_compile_errors() { fn tests_rust_1_58(t: &trybuild::TestCases) { t.compile_fail("tests/ui/invalid_pyfunctions.rs"); t.compile_fail("tests/ui/invalid_pymethods.rs"); - t.compile_fail("tests/ui/missing_clone.rs"); t.compile_fail("tests/ui/not_send.rs"); t.compile_fail("tests/ui/not_send2.rs"); t.compile_fail("tests/ui/not_send3.rs"); @@ -99,12 +99,20 @@ fn _test_compile_errors() { fn tests_rust_1_60(t: &trybuild::TestCases) { t.compile_fail("tests/ui/invalid_intern_arg.rs"); t.compile_fail("tests/ui/invalid_frozen_pyclass_borrow.rs"); - t.compile_fail("tests/ui/invalid_pymethod_receiver.rs"); - t.compile_fail("tests/ui/missing_intopy.rs"); } #[rustversion::before(1.60)] fn tests_rust_1_60(_t: &trybuild::TestCases) {} + + #[rustversion::since(1.62)] + fn tests_rust_1_62(t: &trybuild::TestCases) { + t.compile_fail("tests/ui/invalid_pymethod_receiver.rs"); + t.compile_fail("tests/ui/invalid_result_conversion.rs"); + t.compile_fail("tests/ui/missing_intopy.rs"); + } + + #[rustversion::before(1.62)] + fn tests_rust_1_62(_t: &trybuild::TestCases) {} } #[cfg(feature = "nightly")] diff --git a/tests/ui/abi3_nativetype_inheritance.stderr b/tests/ui/abi3_nativetype_inheritance.stderr index 25084a3c969..2ac0dce88a6 100644 --- a/tests/ui/abi3_nativetype_inheritance.stderr +++ b/tests/ui/abi3_nativetype_inheritance.stderr @@ -4,6 +4,7 @@ error[E0277]: the trait bound `PyDict: PyClass` is not satisfied 5 | #[pyclass(extends=PyDict)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict` | + = help: the trait `PyClass` is implemented for `TestClass` = note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict` = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -13,6 +14,7 @@ error[E0277]: the trait bound `PyDict: PyClass` is not satisfied 5 | #[pyclass(extends=PyDict)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict` | + = help: the trait `PyClass` is implemented for `TestClass` = note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict` note: required by a bound in `PyRefMut` --> src/pycell.rs @@ -27,6 +29,7 @@ error[E0277]: the trait bound `PyDict: PyClass` is not satisfied 5 | #[pyclass(extends=PyDict)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict` | + = help: the trait `PyClass` is implemented for `TestClass` = note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict` note: required by a bound in `ThreadCheckerInherited` --> src/impl_/pyclass.rs diff --git a/tests/ui/invalid_pymethod_receiver.stderr b/tests/ui/invalid_pymethod_receiver.stderr index 9584b37af67..04d2a032b3d 100644 --- a/tests/ui/invalid_pymethod_receiver.stderr +++ b/tests/ui/invalid_pymethod_receiver.stderr @@ -4,11 +4,15 @@ error[E0277]: the trait bound `i32: From<&PyCell>` is not satisfied 8 | fn method_with_invalid_self_type(slf: i32, py: Python<'_>, index: u32) {} | ^^^ the trait `From<&PyCell>` is not implemented for `i32` | - = help: the following implementations were found: - > - > - > - > - and 71 others + = help: the following other types implement trait `From`: + > + > + > + > + > + > + > + > + and 67 others = note: required because of the requirements on the impl of `Into` for `&PyCell` = note: required because of the requirements on the impl of `TryFrom<&PyCell>` for `i32` diff --git a/tests/ui/invalid_result_conversion.stderr b/tests/ui/invalid_result_conversion.stderr index f2ca0f5cc03..d1905eef83a 100644 --- a/tests/ui/invalid_result_conversion.stderr +++ b/tests/ui/invalid_result_conversion.stderr @@ -12,8 +12,7 @@ error[E0277]: the trait bound `Result<(), MyError>: IntoPyCallbackOutput<_>` is 21 | #[pyfunction] | ^^^^^^^^^^^^^ the trait `IntoPyCallbackOutput<_>` is not implemented for `Result<(), MyError>` | - = help: the following implementations were found: - as IntoPyCallbackOutput> + = help: the trait `IntoPyCallbackOutput` is implemented for `Result` note: required by a bound in `pyo3::callback::convert` --> src/callback.rs | diff --git a/tests/ui/missing_clone.rs b/tests/ui/missing_clone.rs deleted file mode 100644 index d577bdfcdf9..00000000000 --- a/tests/ui/missing_clone.rs +++ /dev/null @@ -1,16 +0,0 @@ -use pyo3::prelude::*; - -#[pyclass] -struct TestClass { - num: u32, -} - -fn main() { - let t = TestClass { num: 10 }; - - let gil = Python::acquire_gil(); - let py = gil.python(); - - let pyvalue = Py::new(py, t).unwrap().to_object(py); - let t: TestClass = pyvalue.extract(py).unwrap(); -} diff --git a/tests/ui/missing_clone.stderr b/tests/ui/missing_clone.stderr deleted file mode 100644 index 59c1f324ff2..00000000000 --- a/tests/ui/missing_clone.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0277]: the trait bound `TestClass: Clone` is not satisfied - --> tests/ui/missing_clone.rs:15:32 - | -15 | let t: TestClass = pyvalue.extract(py).unwrap(); - | ^^^^^^^ the trait `Clone` is not implemented for `TestClass` - | - = note: required because of the requirements on the impl of `pyo3::FromPyObject<'_>` for `TestClass` -note: required by a bound in `pyo3::Py::::extract` - --> src/instance.rs - | - | D: FromPyObject<'p>, - | ^^^^^^^^^^^^^^^^ required by this bound in `pyo3::Py::::extract` diff --git a/tests/ui/missing_intopy.stderr b/tests/ui/missing_intopy.stderr index b714d798dd2..2419ef60138 100644 --- a/tests/ui/missing_intopy.stderr +++ b/tests/ui/missing_intopy.stderr @@ -30,6 +30,16 @@ error[E0277]: the trait bound `Blah: IntoPyCallbackOutput<_>` is not satisfied 3 | #[pyo3::pyfunction] | ^^^^^^^^^^^^^^^^^^^ the trait `IntoPyCallbackOutput<_>` is not implemented for `Blah` | + = help: the following other types implement trait `IntoPyCallbackOutput`: + <() as IntoPyCallbackOutput<()>> + <() as IntoPyCallbackOutput> + <*mut PyObject as IntoPyCallbackOutput<*mut PyObject>> + > + , Py> as IntoPyCallbackOutput<*mut PyObject>> + as IntoPyCallbackOutput, Py>>> + , Py> as IntoPyCallbackOutput<*mut PyObject>> + as IntoPyCallbackOutput, Py>>> + and 7 others note: required by a bound in `pyo3::callback::convert` --> src/callback.rs |