diff --git a/README.md b/README.md index 96e1fe9..601876b 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ impl FileOrFileLike { } // is a file-like - match PyFileLikeObject::with_requirements(path_or_file_like, true, false, true) { + match PyFileLikeObject::with_requirements(path_or_file_like, true, false, true, false) { Ok(f) => Ok(FileOrFileLike::FileLike(f)), Err(e) => Err(e) } diff --git a/examples/path_or_file_like/src/lib.rs b/examples/path_or_file_like/src/lib.rs index 9d916a6..7af220a 100644 --- a/examples/path_or_file_like/src/lib.rs +++ b/examples/path_or_file_like/src/lib.rs @@ -24,7 +24,7 @@ impl FileOrFileLike { } // is a file-like - match PyFileLikeObject::with_requirements(path_or_file_like, true, false, true) { + match PyFileLikeObject::with_requirements(path_or_file_like, true, false, true, false) { Ok(f) => Ok(FileOrFileLike::FileLike(f)), Err(e) => Err(e), } @@ -61,7 +61,7 @@ fn accepts_path_or_file_like_read(path_or_file_like: PyObject) -> PyResult PyResult<()> { // is a file-like - match PyFileLikeObject::with_requirements(file_like, false, true, false) { + match PyFileLikeObject::with_requirements(file_like, false, true, false, false) { Ok(mut f) => { println!("Its a file-like object"); f.write_all(b"Hello, world!")?; diff --git a/src/lib.rs b/src/lib.rs index d1c1501..ccd47d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use pyo3::types::{PyBytes, PyString, PyType}; use std::io; use std::io::{Read, Seek, SeekFrom, Write}; +use std::os::fd::{AsRawFd, RawFd}; #[derive(Debug)] pub struct PyFileLikeObject { @@ -33,12 +34,13 @@ impl PyFileLikeObject { /// Same as `PyFileLikeObject::new`, but validates that the underlying /// python object has a `read`, `write`, and `seek` methods in respect to parameters. - /// Will return a `TypeError` if object does not have `read`, `seek`, and `write` methods. + /// Will return a `TypeError` if object does not have `read`, `seek`, `write` and `fileno` methods. pub fn with_requirements( object: PyObject, read: bool, write: bool, seek: bool, + fileno: bool, ) -> PyResult { Python::with_gil(|py| { if read && object.getattr(py, "read").is_err() { @@ -59,6 +61,12 @@ impl PyFileLikeObject { )); } + if fileno && object.getattr(py, "fileno").is_err() { + return Err(PyErr::new::( + "Object does not have a .fileno() method.", + )); + } + PyFileLikeObject::new(object) }) } @@ -179,3 +187,20 @@ impl Seek for PyFileLikeObject { }) } } + +impl AsRawFd for PyFileLikeObject { + fn as_raw_fd(&self) -> RawFd { + Python::with_gil(|py| { + let fileno = self + .inner + .getattr(py, "fileno") + .expect("Object does not have a fileno() method."); + + let fd = fileno + .call(py, (), None) + .expect("fileno() method did not return a file descriptor."); + + fd.extract(py).expect("File descriptor is not an integer.") + }) + } +}