Skip to content

Commit ec502ec

Browse files
committed
replace PyString::from_object with PyString::from_encoded_object
1 parent 1b00b0d commit ec502ec

File tree

3 files changed

+45
-12
lines changed

3 files changed

+45
-12
lines changed

newsfragments/5017.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `PyString::from_encoded_object`.

newsfragments/5017.changed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Deprecate `PyString::from_object` in favour of `PyString::from_encoded_object`.

src/types/string.rs

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::types::PyBytes;
1010
use crate::IntoPy;
1111
use crate::{ffi, Bound, Py, PyAny, PyResult, Python};
1212
use std::borrow::Cow;
13-
use std::ffi::CString;
13+
use std::ffi::{CStr, CString};
1414
use std::str;
1515

1616
/// Deprecated alias for [`PyString`].
@@ -212,32 +212,48 @@ impl PyString {
212212
/// Attempts to create a Python string from a Python [bytes-like object].
213213
///
214214
/// [bytes-like object]: (https://docs.python.org/3/glossary.html#term-bytes-like-object).
215+
pub fn from_encoded_object<'py>(
216+
src: &Bound<'py, PyAny>,
217+
encoding: &CStr,
218+
errors: &CStr,
219+
) -> PyResult<Bound<'py, PyString>> {
220+
unsafe {
221+
ffi::PyUnicode_FromEncodedObject(src.as_ptr(), encoding.as_ptr(), errors.as_ptr())
222+
.assume_owned_or_err(src.py())
223+
.downcast_into_unchecked()
224+
}
225+
}
226+
227+
/// Deprecated form of `PyString::from_encoded_object`.
228+
///
229+
/// This version took `&str` arguments for `encoding` and `errors`, which required a runtime
230+
/// conversion to `CString` internally.
231+
#[deprecated(
232+
since = "0.24.1",
233+
note = "replaced with to `PyString::from_encoded_object`"
234+
)]
215235
pub fn from_object<'py>(
216236
src: &Bound<'py, PyAny>,
217237
encoding: &str,
218238
errors: &str,
219239
) -> PyResult<Bound<'py, PyString>> {
220240
let encoding = CString::new(encoding)?;
221241
let errors = CString::new(errors)?;
222-
unsafe {
223-
ffi::PyUnicode_FromEncodedObject(
224-
src.as_ptr(),
225-
encoding.as_ptr().cast(),
226-
errors.as_ptr().cast(),
227-
)
228-
.assume_owned_or_err(src.py())
229-
.downcast_into_unchecked()
230-
}
242+
PyString::from_encoded_object(src, &encoding, &errors)
231243
}
232244

233245
/// Deprecated name for [`PyString::from_object`].
234-
#[deprecated(since = "0.23.0", note = "renamed to `PyString::from_object`")]
246+
#[deprecated(
247+
since = "0.23.0",
248+
note = "replcaed with `PyString::from_encoded_object`"
249+
)]
235250
#[inline]
236251
pub fn from_object_bound<'py>(
237252
src: &Bound<'py, PyAny>,
238253
encoding: &str,
239254
errors: &str,
240255
) -> PyResult<Bound<'py, PyString>> {
256+
#[allow(deprecated)]
241257
Self::from_object(src, encoding, errors)
242258
}
243259
}
@@ -586,6 +602,8 @@ impl PartialEq<Borrowed<'_, '_, PyString>> for &'_ str {
586602

587603
#[cfg(test)]
588604
mod tests {
605+
use pyo3_ffi::c_str;
606+
589607
use super::*;
590608
use crate::{IntoPyObject, PyObject};
591609

@@ -678,6 +696,14 @@ mod tests {
678696
Python::with_gil(|py| {
679697
let py_bytes = PyBytes::new(py, b"ab\xFFcd");
680698

699+
let py_string =
700+
PyString::from_encoded_object(&py_bytes, c_str!("utf-8"), c_str!("ignore"))
701+
.unwrap();
702+
703+
let result = py_string.to_cow().unwrap();
704+
assert_eq!(result, "abcd");
705+
706+
#[allow(deprecated)]
681707
let py_string = PyString::from_object(&py_bytes, "utf-8", "ignore").unwrap();
682708

683709
let result = py_string.to_cow().unwrap();
@@ -686,13 +712,18 @@ mod tests {
686712
}
687713

688714
#[test]
689-
fn test_string_from_obect_with_invalid_encoding_errors() {
715+
fn test_string_from_object_with_invalid_encoding_errors() {
690716
Python::with_gil(|py| {
691717
let py_bytes = PyBytes::new(py, b"abcd");
692718

719+
let result = PyString::from_encoded_object(&py_bytes, c_str!("wat"), c_str!("ignore"));
720+
assert!(result.is_err());
721+
722+
#[allow(deprecated)]
693723
let result = PyString::from_object(&py_bytes, "utf\0-8", "ignore");
694724
assert!(result.is_err());
695725

726+
#[allow(deprecated)]
696727
let result = PyString::from_object(&py_bytes, "utf-8", "ign\0ore");
697728
assert!(result.is_err());
698729
});

0 commit comments

Comments
 (0)