Switch to nanobind (#839)
* mostly builds * most tests pass * fix circle build * add back buffer protocol * includes * fix for py38 * limit to cpu device * include * fix stubs * move signatures for docs * stubgen + docs fix * doc for compiled function, comments
This commit is contained in:
+82
-9
@@ -1,25 +1,54 @@
|
||||
// Copyright © 2023 Apple Inc.
|
||||
// Copyright © 2023-2024 Apple Inc.
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <nanobind/nanobind.h>
|
||||
#include <nanobind/stl/optional.h>
|
||||
#include <nanobind/stl/variant.h>
|
||||
|
||||
#include "mlx/stream.h"
|
||||
#include "mlx/utils.h"
|
||||
|
||||
namespace py = pybind11;
|
||||
using namespace py::literals;
|
||||
namespace nb = nanobind;
|
||||
using namespace nb::literals;
|
||||
using namespace mlx::core;
|
||||
|
||||
void init_stream(py::module_& m) {
|
||||
py::class_<Stream>(
|
||||
// Create the StreamContext on enter and delete on exit.
|
||||
class PyStreamContext {
|
||||
public:
|
||||
PyStreamContext(StreamOrDevice s) : _inner(nullptr) {
|
||||
if (std::holds_alternative<std::monostate>(s)) {
|
||||
throw std::runtime_error(
|
||||
"[StreamContext] Invalid argument, please specify a stream or device.");
|
||||
}
|
||||
_s = s;
|
||||
}
|
||||
|
||||
void enter() {
|
||||
_inner = new StreamContext(_s);
|
||||
}
|
||||
|
||||
void exit() {
|
||||
if (_inner != nullptr) {
|
||||
delete _inner;
|
||||
_inner = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
StreamOrDevice _s;
|
||||
StreamContext* _inner;
|
||||
};
|
||||
|
||||
void init_stream(nb::module_& m) {
|
||||
nb::class_<Stream>(
|
||||
m,
|
||||
"Stream",
|
||||
R"pbdoc(
|
||||
A stream for running operations on a given device.
|
||||
)pbdoc")
|
||||
.def(py::init<int, Device>(), "index"_a, "device"_a)
|
||||
.def_readonly("device", &Stream::device)
|
||||
.def(nb::init<int, Device>(), "index"_a, "device"_a)
|
||||
.def_ro("device", &Stream::device)
|
||||
.def(
|
||||
"__repr__",
|
||||
[](const Stream& s) {
|
||||
@@ -31,7 +60,7 @@ void init_stream(py::module_& m) {
|
||||
return s1 == s2;
|
||||
});
|
||||
|
||||
py::implicitly_convertible<Device::DeviceType, Device>();
|
||||
nb::implicitly_convertible<Device::DeviceType, Device>();
|
||||
|
||||
m.def(
|
||||
"default_stream",
|
||||
@@ -56,4 +85,48 @@ void init_stream(py::module_& m) {
|
||||
&new_stream,
|
||||
"device"_a,
|
||||
R"pbdoc(Make a new stream on the given device.)pbdoc");
|
||||
|
||||
nb::class_<PyStreamContext>(m, "StreamContext", R"pbdoc(
|
||||
A context manager for setting the current device and stream.
|
||||
|
||||
See :func:`stream` for usage.
|
||||
|
||||
Args:
|
||||
s: The stream or device to set as the default.
|
||||
)pbdoc")
|
||||
.def(nb::init<StreamOrDevice>(), "s"_a)
|
||||
.def("__enter__", [](PyStreamContext& scm) { scm.enter(); })
|
||||
.def(
|
||||
"__exit__",
|
||||
[](PyStreamContext& scm,
|
||||
const std::optional<nb::type_object>& exc_type,
|
||||
const std::optional<nb::object>& exc_value,
|
||||
const std::optional<nb::object>& traceback) { scm.exit(); },
|
||||
"exc_type"_a = nb::none(),
|
||||
"exc_value"_a = nb::none(),
|
||||
"traceback"_a = nb::none());
|
||||
m.def(
|
||||
"stream",
|
||||
[](StreamOrDevice s) { return PyStreamContext(s); },
|
||||
"s"_a,
|
||||
R"pbdoc(
|
||||
Create a context manager to set the default device and stream.
|
||||
|
||||
Args:
|
||||
s: The :obj:`Stream` or :obj:`Device` to set as the default.
|
||||
|
||||
Returns:
|
||||
A context manager that sets the default device and stream.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block::python
|
||||
|
||||
import mlx.core as mx
|
||||
|
||||
# Create a context manager for the default device and stream.
|
||||
with mx.stream(mx.cpu):
|
||||
# Operations here will use mx.cpu by default.
|
||||
pass
|
||||
)pbdoc");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user