Skip to content

Commit e0fe042

Browse files
authored
Add PyString::from_bytes (#5437)
* Add PyString::from_bytes * add newsfragment * gate the test behind not(any(Py_LIMITED_API, PyPy, GraalPy)) * Update the docstring * Fix PyMemoryError not in scope * style
1 parent 6f02125 commit e0fe042

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

newsfragments/5437.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add PyString::from_bytes. This saves a redundant UTF-8 validation check because Python internally validates the bytes again.

src/types/string.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,20 @@ impl PyString {
168168
}
169169
}
170170

171+
/// Creates a new Python string object from bytes.
172+
///
173+
/// Returns PyMemoryError if out of memory.
174+
/// Returns [PyUnicodeDecodeError] if the slice is not a valid UTF-8 string.
175+
pub fn from_bytes<'py>(py: Python<'py>, s: &[u8]) -> PyResult<Bound<'py, PyString>> {
176+
let ptr = s.as_ptr().cast();
177+
let len = s.len() as ffi::Py_ssize_t;
178+
unsafe {
179+
ffi::PyUnicode_FromStringAndSize(ptr, len)
180+
.assume_owned_or_err(py)
181+
.cast_into_unchecked()
182+
}
183+
}
184+
171185
/// Intern the given string
172186
///
173187
/// This will return a reference to the same Python string object if called repeatedly with the same string.
@@ -828,6 +842,20 @@ mod tests {
828842
});
829843
}
830844

845+
#[test]
846+
#[cfg(not(any(Py_LIMITED_API, PyPy, GraalPy)))]
847+
fn test_pystring_from_bytes() {
848+
Python::attach(|py| {
849+
let result = PyString::from_bytes(py, "\u{2122}".as_bytes());
850+
assert!(result.is_ok());
851+
let result = PyString::from_bytes(py, b"\x80");
852+
assert!(result
853+
.unwrap_err()
854+
.get_type(py)
855+
.is(py.get_type::<PyUnicodeDecodeError>()));
856+
});
857+
}
858+
831859
#[test]
832860
fn test_intern_string() {
833861
Python::attach(|py| {

0 commit comments

Comments
 (0)