in python/src/PythonInputStream.h [74:154]
long long read(char *buffer, long long bytesToRead) {
py::gil_scoped_acquire acquire;
if (buffer == nullptr) {
throw py::buffer_error(
"C++ code attempted to read from a Python file-like object into a "
"null destination buffer.");
}
if (bytesToRead < 0) {
throw py::buffer_error("C++ code attempted to read a negative number "
"of bytes from a Python file-like object.");
}
long long bytesRead = 0;
if (peekValue.size()) {
long long bytesToCopy =
std::min(bytesToRead, (long long)peekValue.size());
std::memcpy(buffer, peekValue.data(), bytesToCopy);
for (int i = 0; i < bytesToCopy; i++)
peekValue.erase(peekValue.begin());
bytesRead += bytesToCopy;
buffer += bytesToCopy;
}
while (bytesRead < bytesToRead) {
auto readResult = fileLike.attr("read")(
std::min(MAX_BUFFER_SIZE, bytesToRead - bytesRead));
if (!py::isinstance<py::bytes>(readResult)) {
std::string message = "Python file-like object was expected to return "
"bytes from its read(...) method, but "
"returned " +
py::str(readResult.get_type().attr("__name__"))
.cast<std::string>() +
".";
if (py::hasattr(fileLike, "mode") &&
py::str(fileLike.attr("mode")).cast<std::string>() == "r") {
message += " (Try opening the stream in \"rb\" mode instead of "
"\"r\" mode if possible.)";
}
throw py::type_error(message);
return 0;
}
py::bytes bytesObject = readResult.cast<py::bytes>();
char *pythonBuffer = nullptr;
py::ssize_t pythonLength = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(bytesObject.ptr(), &pythonBuffer,
&pythonLength)) {
throw py::buffer_error(
"Internal error: failed to read bytes from bytes object!");
}
if (!buffer && pythonLength > 0) {
throw py::buffer_error("Internal error: bytes pointer is null, but a "
"non-zero number of bytes were returned!");
}
if (bytesRead + pythonLength > bytesToRead) {
throw py::buffer_error(
"Python returned " + std::to_string(pythonLength) +
" bytes, but only " + std::to_string(bytesToRead - bytesRead) +
" bytes were requested.");
}
if (buffer && pythonLength > 0) {
std::memcpy(buffer, pythonBuffer, pythonLength);
bytesRead += pythonLength;
buffer += pythonLength;
} else {
break;
}
}
lastReadWasSmallerThanExpected = bytesToRead > bytesRead;
return bytesRead;
}