diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst index efb1fa3f..c7caa47b 100644 --- a/docs/source/tutorial.rst +++ b/docs/source/tutorial.rst @@ -201,26 +201,16 @@ We can throw exceptions in C++ that will then be dealt with in Python. Two patte Python Extensions ================= -In order to create and use a Python Extension we must do four basic things: +In order to create and use Python Extensions we must do two things: -First, we use :cpp:func:`py::autofunction` to create an array of `PyMethoddef `_. +First, we use the ``LIBPY_AUTOMODULE`` macro to create and initialize the module: .. literalinclude:: tutorial/libpy_tutorial/scalar_functions.cc - :lines: 47-53 + :lines: 45-53 -Second, we create a `PyModuleDef `_ module. - -.. literalinclude:: tutorial/libpy_tutorial/scalar_functions.cc - :lines: 55-65 - -Then we intialize the module (`see also `_): - -.. literalinclude:: tutorial/libpy_tutorial/scalar_functions.cc - :lines: 67-74 - -.. note:: The initialization function must be named ``PyInit_name()``, where name is the name of the module. - -Finally, we must tell ``setup.py`` to build our module using the ``LibpyExtension`` helper: +Next, we must tell ``setup.py`` to build our module using the ``LibpyExtension`` helper: .. literalinclude:: tutorial/setup.py :lines: 18-28,37,50-54,71-72 + +Finally, we must ensure that we ``import libpy`` in Python before importing the extension module. diff --git a/docs/source/tutorial/libpy_tutorial/arrays.cc b/docs/source/tutorial/libpy_tutorial/arrays.cc index 98ffd2df..a69ea1bb 100644 --- a/docs/source/tutorial/libpy_tutorial/arrays.cc +++ b/docs/source/tutorial/libpy_tutorial/arrays.cc @@ -1,8 +1,8 @@ #include #include -#include #include +#include #include #include @@ -42,32 +42,13 @@ py::owned_ref<> is_prime(py::array_view values) { return py::move_to_numpy_array(std::move(out)); } -namespace { -PyMethodDef methods[] = { - py::autofunction("simple_sum"), - py::autofunction("simple_sum_iterator"), - py::autofunction("is_prime"), - py::end_method_list, -}; - -PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "libpy_tutorial.arrays", - nullptr, - -1, - methods, - nullptr, - nullptr, - nullptr, - nullptr, -}; - -PyMODINIT_FUNC PyInit_arrays() { - if (py::abi::ensure_compatible_libpy_abi()) { - return nullptr; - } - import_array(); - return PyModule_Create(&module); +LIBPY_AUTOMODULE(libpy_tutorial, + arrays, + ({py::autofunction("simple_sum"), + py::autofunction("simple_sum_iterator"), + py::autofunction("is_prime")})) +(py::borrowed_ref<>) { + return false; } -} // namespace + } // namespace libpy_tutorial diff --git a/docs/source/tutorial/libpy_tutorial/classes.cc b/docs/source/tutorial/libpy_tutorial/classes.cc index 644d2648..66bbeb0e 100644 --- a/docs/source/tutorial/libpy_tutorial/classes.cc +++ b/docs/source/tutorial/libpy_tutorial/classes.cc @@ -2,8 +2,8 @@ #include #include -#include #include +#include #include namespace libpy_tutorial { @@ -67,52 +67,23 @@ struct LIBPY_NO_EXPORT to_object } // namespace py::dispatch namespace libpy_tutorial { -namespace { -PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "libpy_tutorial.classes", - nullptr, - -1, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, -}; - -PyMODINIT_FUNC PyInit_classes() { - if (py::abi::ensure_compatible_libpy_abi()) { - return nullptr; - } - import_array(); - auto m = py::owned_ref(PyModule_Create(&module)); - if (!m) { - return nullptr; - } - try { - auto type = - py::autoclass("Vec3d") - .doc("An efficient 3-vector.") // add a class docstring - .new_() //__new__ takes parameters - // bind the named methods to Python - .def<&vec3d::x>("x") - .def<&vec3d::y>("y") - .def<&vec3d::z>("z") - .def<&vec3d::magnitude>("magnitude") - .str() // set `operator<<(std::ostream&, vec3d) to `str(x)` in Python - .repr() // set `repr` to be the result of `repr(x)` in Python - .arithmetic() // bind the arithmetic operators to their Python - // equivalents - .type(); - if (PyObject_SetAttrString(m.get(), "Vec3d", static_cast(type))) { - return nullptr; - } - } - catch (const std::exception& e) { - return py::raise_from_cxx_exception(e); - } - return std::move(m).escape(); +LIBPY_AUTOMODULE(libpy_tutorial, classes, ({})) +(py::borrowed_ref<> m) { + py::owned_ref t = + py::autoclass(PyModule_GetName(m) + ".Vec3d") + .doc("An efficient 3-vector.") // add a class docstring + .new_() //__new__ takes parameters + // bind the named methods to Python + .def<&vec3d::x>("x") + .def<&vec3d::y>("y") + .def<&vec3d::z>("z") + .def<&vec3d::magnitude>("magnitude") + .str() // set `operator<<(std::ostream&, vec3d) to `str(x)` in Python + .repr() // set `repr` to be the result of `repr(x)` in Python + .arithmetic() // bind the arithmetic operators to their Python + // equivalents + .type(); + return PyObject_SetAttrString(m.get(), "Vec3d", static_cast(t)); } -} // namespace } // namespace libpy_tutorial diff --git a/docs/source/tutorial/libpy_tutorial/exceptions.cc b/docs/source/tutorial/libpy_tutorial/exceptions.cc index 1f987695..74482d43 100644 --- a/docs/source/tutorial/libpy_tutorial/exceptions.cc +++ b/docs/source/tutorial/libpy_tutorial/exceptions.cc @@ -2,8 +2,8 @@ #include #include -#include #include +#include #include namespace libpy_tutorial { @@ -16,31 +16,12 @@ void raise_from_cxx() { throw std::invalid_argument("Supposedly a bad argument was used"); } -namespace { -PyMethodDef methods[] = { - py::autofunction("throw_value_error"), - py::autofunction("raise_from_cxx"), - py::end_method_list, -}; - -PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "libpy_tutorial.exceptions", - nullptr, - -1, - methods, - nullptr, - nullptr, - nullptr, - nullptr, -}; - -PyMODINIT_FUNC PyInit_exceptions() { - if (py::abi::ensure_compatible_libpy_abi()) { - return nullptr; - } - import_array(); - return PyModule_Create(&module); +LIBPY_AUTOMODULE(libpy_tutorial, + exceptions, + ({py::autofunction("throw_value_error"), + py::autofunction("raise_from_cxx")})) +(py::borrowed_ref<>) { + return false; } -} // namespace + } // namespace libpy_tutorial diff --git a/docs/source/tutorial/libpy_tutorial/ndarrays.cc b/docs/source/tutorial/libpy_tutorial/ndarrays.cc index 556630f9..35caa004 100644 --- a/docs/source/tutorial/libpy_tutorial/ndarrays.cc +++ b/docs/source/tutorial/libpy_tutorial/ndarrays.cc @@ -1,7 +1,7 @@ #include -#include #include +#include #include #include @@ -58,30 +58,10 @@ py::owned_ref<> apply_kernel(py::ndarray_view pixels, pixels.strides()); } -namespace { -PyMethodDef methods[] = { - py::autofunction("apply_kernel"), - py::end_method_list, -}; - -PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "libpy_tutorial.ndarrays", - nullptr, - -1, - methods, - nullptr, - nullptr, - nullptr, - nullptr, -}; - -PyMODINIT_FUNC PyInit_ndarrays() { - if (py::abi::ensure_compatible_libpy_abi()) { - return nullptr; - } - import_array(); - return PyModule_Create(&module); +LIBPY_AUTOMODULE(libpy_tutorial, + ndarrays, + ({py::autofunction("apply_kernel")})) +(py::borrowed_ref<>) { + return false; } -} // namespace } // namespace libpy_tutorial diff --git a/docs/source/tutorial/libpy_tutorial/scalar_functions.cc b/docs/source/tutorial/libpy_tutorial/scalar_functions.cc index c78f109c..57644d33 100644 --- a/docs/source/tutorial/libpy_tutorial/scalar_functions.cc +++ b/docs/source/tutorial/libpy_tutorial/scalar_functions.cc @@ -1,8 +1,8 @@ #include #include -#include #include +#include #include #include @@ -35,41 +35,21 @@ std::string optional_arg(py::arg::optional opt_arg) { return opt_arg.get().value_or("default value"); } -py::owned_ref<> keyword_args( - py::arg::kwd kw_arg_kwd, - py::arg::opt_kwd - opt_kw_arg_kwd) { +py::owned_ref<> +keyword_args(py::arg::kwd kw_arg_kwd, + py::arg::opt_kwd opt_kw_arg_kwd) { return py::build_tuple(kw_arg_kwd.get(), opt_kw_arg_kwd.get()); } -namespace { -PyMethodDef methods[] = { - py::autofunction("bool_scalar"), - py::autofunction("monte_carlo_pi"), - py::autofunction("optional_arg"), - py::autofunction("keyword_args"), - py::end_method_list, -}; - -PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "libpy_tutorial.scalar_functions", - nullptr, - -1, - methods, - nullptr, - nullptr, - nullptr, - nullptr, -}; - -PyMODINIT_FUNC PyInit_scalar_functions() { - if (py::abi::ensure_compatible_libpy_abi()) { - return nullptr; - } - import_array(); - return PyModule_Create(&module); +LIBPY_AUTOMODULE(libpy_tutorial, + scalar_functions, + ({py::autofunction("bool_scalar"), + py::autofunction("monte_carlo_pi"), + py::autofunction("optional_arg"), + py::autofunction("keyword_args")})) +(py::borrowed_ref<>) { + return false; } -} // namespace + } // namespace libpy_tutorial diff --git a/docs/source/tutorial/setup.py b/docs/source/tutorial/setup.py index de57e004..29fc7e02 100644 --- a/docs/source/tutorial/setup.py +++ b/docs/source/tutorial/setup.py @@ -27,6 +27,7 @@ def extension(*args, **kwargs): **kwargs ) + install_requires = [ 'setuptools', 'libpy', @@ -44,6 +45,7 @@ def extension(*args, **kwargs): package_data={ "": ["*.png"], }, + include_package_data=True, install_requires=install_requires, license="Apache 2.0", url="https://github.com/quantopian/libpy",