Merge pull request #3374 from Tpt/pathlike

Makes PathBuf FromPyObject implementation work on all os.PathLike
This commit is contained in:
Adam Reichold 2023-08-09 14:50:28 +00:00 committed by GitHub
commit 1df7270e15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 17 deletions

View File

@ -37,6 +37,7 @@ The table below contains the Python type and the corresponding function argument
| `decimal.Decimal` | `rust_decimal::Decimal`[^5] | - |
| `ipaddress.IPv4Address` | `std::net::IpAddr`, `std::net::IpV4Addr` | - |
| `ipaddress.IPv6Address` | `std::net::IpAddr`, `std::net::IpV6Addr` | - |
| `os.PathLike ` | `PathBuf`, `Path` | `&PyString`, `&PyUnicode` |
| `pathlib.Path` | `PathBuf`, `Path` | `&PyString`, `&PyUnicode` |
| `typing.Optional[T]` | `Option<T>` | - |
| `typing.Sequence[T]` | `Vec<T>` | `&PySequence` |

View File

@ -0,0 +1 @@
`PathBuf` `FromPyObject` implementation now works on all `os.PathLike` values.

View File

@ -0,0 +1 @@
Linking of `PyOS_FSPath` on PyPy.

View File

@ -1,5 +1,6 @@
use crate::object::PyObject;
extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyOS_FSPath")]
pub fn PyOS_FSPath(path: *mut PyObject) -> *mut PyObject;
}

View File

@ -1,5 +1,7 @@
import pathlib
import pytest
import pyo3_pytests.path as rpath
@ -16,3 +18,25 @@ def test_take_pathbuf():
def test_take_pathlib():
p = pathlib.Path("/root")
assert rpath.take_pathbuf(p) == str(p)
def test_take_pathlike():
assert rpath.take_pathbuf(PathLike("/root")) == "/root"
def test_take_invalid_pathlike():
with pytest.raises(TypeError):
assert rpath.take_pathbuf(PathLike(1))
def test_take_invalid():
with pytest.raises(TypeError):
assert rpath.take_pathbuf(3)
class PathLike:
def __init__(self, path):
self._path = path
def __fspath__(self):
return self._path

View File

@ -1,5 +1,7 @@
use crate::intern;
use crate::{FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject};
use crate::{
ffi, AsPyPointer, FromPyObject, FromPyPointer, IntoPy, PyAny, PyObject, PyResult, Python,
ToPyObject,
};
use std::borrow::Cow;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
@ -14,21 +16,9 @@ impl ToPyObject for Path {
impl FromPyObject<'_> for PathBuf {
fn extract(ob: &PyAny) -> PyResult<Self> {
let os_str = match OsString::extract(ob) {
Ok(s) => s,
Err(err) => {
let py = ob.py();
let pathlib = py.import(intern!(py, "pathlib"))?;
let pathlib_path = pathlib.getattr(intern!(py, "Path"))?;
if ob.is_instance(pathlib_path)? {
let path_str = ob.call_method0(intern!(py, "__str__"))?;
OsString::extract(path_str)?
} else {
return Err(err);
}
}
};
Ok(PathBuf::from(os_str))
// We use os.fspath to get the underlying path as bytes or str
let path = unsafe { PyAny::from_owned_ptr_or_err(ob.py(), ffi::PyOS_FSPath(ob.as_ptr())) }?;
Ok(OsString::extract(path)?.into())
}
}