diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp
index c9e5a99c..ba45f713 100644
--- a/src/py/libcamera/py_camera_manager.cpp
+++ b/src/py/libcamera/py_camera_manager.cpp
@@ -5,6 +5,7 @@
 
 #include "py_camera_manager.h"
 
+#include <poll.h>
 #include <sys/eventfd.h>
 #include <unistd.h>
 
@@ -55,9 +56,10 @@ py::list PyCameraManager::getCameras()
 	return l;
 }
 
-std::vector<py::object> PyCameraManager::getReadyRequests()
+std::vector<py::object> PyCameraManager::getReadyRequests(bool nonBlocking)
 {
-	readFd();
+	if (!nonBlocking || hasEvents())
+		readFd();
 
 	std::vector<Request *> v;
 	getRequests(v);
@@ -113,3 +115,18 @@ void PyCameraManager::getRequests(std::vector<Request *> &v)
 	std::lock_guard guard(reqlist_mutex_);
 	swap(v, reqList_);
 }
+
+bool PyCameraManager::hasEvents()
+{
+	struct pollfd pfd = {
+		.fd = eventFd_,
+		.events = POLLIN,
+		.revents = 0,
+	};
+
+	int ret = poll(&pfd, 1, 0);
+	if (ret == -1)
+		throw std::system_error(errno, std::generic_category());
+
+	return pfd.revents & POLLIN;
+}
diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h
index b0b971ad..2396d236 100644
--- a/src/py/libcamera/py_camera_manager.h
+++ b/src/py/libcamera/py_camera_manager.h
@@ -23,7 +23,7 @@ public:
 
 	int eventFd() const { return eventFd_; }
 
-	std::vector<pybind11::object> getReadyRequests();
+	std::vector<pybind11::object> getReadyRequests(bool nonBlocking = false);
 
 	void handleRequestCompleted(Request *req);
 
@@ -36,4 +36,6 @@ private:
 	void readFd();
 	void pushRequest(Request *req);
 	void getRequests(std::vector<Request *> &v);
+
+	bool hasEvents();
 };
diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp
index 23018288..ee4ecb9b 100644
--- a/src/py/libcamera/py_main.cpp
+++ b/src/py/libcamera/py_main.cpp
@@ -103,7 +103,8 @@ PYBIND11_MODULE(_libcamera, m)
 		.def_property_readonly("cameras", &PyCameraManager::getCameras)
 
 		.def_property_readonly("event_fd", &PyCameraManager::eventFd)
-		.def("get_ready_requests", &PyCameraManager::getReadyRequests);
+		.def("get_ready_requests", &PyCameraManager::getReadyRequests,
+		     py::arg("nonblocking") = false);
 
 	pyCamera
 		.def_property_readonly("id", &Camera::id)
