diff --git a/conda.recipe/bld.bat b/conda.recipe/bld.bat deleted file mode 100644 index b9cd616ce..000000000 --- a/conda.recipe/bld.bat +++ /dev/null @@ -1,2 +0,0 @@ -"%PYTHON%" setup.py install --single-version-externally-managed --record=record.txt -if errorlevel 1 exit 1 diff --git a/conda.recipe/build.sh b/conda.recipe/build.sh deleted file mode 100644 index 175d6f16e..000000000 --- a/conda.recipe/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -${PYTHON} setup.py install --single-version-externally-managed --record=record.txt; - diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml deleted file mode 100644 index fbbb830b7..000000000 --- a/conda.recipe/meta.yaml +++ /dev/null @@ -1,26 +0,0 @@ -package: - name: pybind11 - version: {{ environ.get('GIT_DESCRIBE_TAG', '').replace('v', '') }} - -build: - number: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} - {% if environ.get('GIT_DESCRIBE_NUMBER', '0') == '0' %}string: py{{ environ.get('PY_VER').replace('.', '') }}_0 - {% else %}string: py{{ environ.get('PY_VER').replace('.', '') }}_{{ environ.get('GIT_BUILD_STR', 'GIT_STUB') }}{% endif %} - -source: - git_url: ../ - -requirements: - build: - - python - - run: - - python - -test: - imports: - - pybind11 - -about: - home: https://github.com/pybind/pybind11/ - summary: Seamless operability between C++11 and Python diff --git a/docs/release.rst b/docs/release.rst index e0f8a8638..4c3ff72f3 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -2,20 +2,18 @@ To release a new version of pybind11: - Update the version number and push to pypi - Update ``pybind11/_version.py`` (set release version, remove 'dev') + - Tag release date in ``doc/changelog.rst``. - ``git add`` and ``git commit``. + - ``git tag -a vX.Y -m 'vX.Y release'``. + - ``git push`` + - ``git push --tags``. - ``python setup.py sdist upload``. - ``python setup.py bdist_wheel upload``. - - Tag release date in ``doc/changelog.rst``. -- Tag the commit and push to anaconda.org - - ``git tag -a vX.Y -m 'vX.Y release'``. - - ``conda-build conda.recipe`` - This should ouput the path of the generated tar.bz2 for the package - - ``conda-convert --platform all [path/to/tar.bz2] -o .`` - - ``for i in *-32/* *-64/*; do anaconda upload -u pybind $i; done`` +- Update conda-forge + - change version number in ``meta.yml`` + - update checksum to match the one computed by pypi - Get back to work - Update ``_version.py`` (add 'dev' and increment minor). - Update version macros in ``include/pybind11/common.h`` - - ``git add`` and ``git commit``. ``git push``. ``git push --tags``. - -The remote for the last ``git push --tags`` should be the main repository for -pybind11. + - ``git add`` and ``git commit``. + ``git push`` diff --git a/example/example11.cpp b/example/example11.cpp index 1a472c9e8..5a91ee298 100644 --- a/example/example11.cpp +++ b/example/example11.cpp @@ -19,6 +19,13 @@ void kw_func4(const std::vector &entries) { std::cout << endl; } +void call_kw_func(py::function f) { + py::tuple args = py::make_tuple(1234); + py::dict kwargs; + kwargs["y"] = py::cast(5678); + f(*args, **kwargs); +} + void init_ex11(py::module &m) { m.def("kw_func", &kw_func, py::arg("x"), py::arg("y")); m.def("kw_func2", &kw_func, py::arg("x") = 100, py::arg("y") = 200); @@ -30,4 +37,5 @@ void init_ex11(py::module &m) { list.push_back(17); m.def("kw_func4", &kw_func4, py::arg("myList") = list); + m.def("call_kw_func", &call_kw_func); } diff --git a/example/example11.py b/example/example11.py index 04baa7bc9..948b0fd7c 100755 --- a/example/example11.py +++ b/example/example11.py @@ -5,7 +5,7 @@ import pydoc sys.path.append('.') -from example import kw_func, kw_func2, kw_func3, kw_func4 +from example import kw_func, kw_func2, kw_func3, kw_func4, call_kw_func print(pydoc.render_doc(kw_func, "Help on %s")) print(pydoc.render_doc(kw_func2, "Help on %s")) @@ -33,3 +33,5 @@ except Exception as e: kw_func4() kw_func4(myList = [1, 2, 3]) + +call_kw_func(kw_func2) diff --git a/example/example11.ref b/example/example11.ref index 54e4fef31..0ce066b9d 100644 --- a/example/example11.ref +++ b/example/example11.ref @@ -32,3 +32,4 @@ Caught expected exception: Incompatible function arguments. The following argume kw_func4: 13 17 kw_func4: 1 2 3 +kw_func(x=1234, y=5678) diff --git a/example/example5.cpp b/example/example5.cpp index 4ba6a34f4..11d37d0ef 100644 --- a/example/example5.cpp +++ b/example/example5.cpp @@ -43,12 +43,12 @@ void dog_bark(const Dog &dog) { } bool test_callback1(py::object func) { - func.call(); + func(); return false; } int test_callback2(py::object func) { - py::object result = func.call("Hello", 'x', true, 5); + py::object result = func("Hello", 'x', true, 5); return result.cast(); } diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 5beb21ace..4ee79d204 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -796,7 +796,7 @@ template object handle::call(Args&&... args) const { +template object handle::operator()(Args&&... args) const { tuple args_tuple = pybind11::make_tuple(std::forward(args)...); object result(PyObject_CallObject(m_ptr, args_tuple.ptr()), false); if (!result) @@ -804,6 +804,24 @@ template object handle::call(Args&&... args) const { return result; } +template object handle::call(Args &&... args) const { + return operator()(std::forward(args)...); +} + +inline object handle::operator()(detail::args args) const { + object result(PyObject_CallObject(m_ptr, args.ptr()), false); + if (!result) + throw error_already_set(); + return result; +} + +inline object handle::operator()(detail::args args, detail::kwargs kwargs) const { + object result(PyObject_Call(m_ptr, args.ptr(), kwargs.ptr()), false); + if (!result) + throw error_already_set(); + return result; +} + #define PYBIND11_MAKE_OPAQUE(Type) \ namespace pybind11 { namespace detail { \ template<> class type_caster : public type_caster_base { }; \ diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 2750d4994..727031f33 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -201,6 +201,7 @@ struct buffer_info { std::vector shape; // Shape of the tensor (1 entry per dimension) std::vector strides; // Number of entries between adjacent entries (for each per dimension) + buffer_info() : ptr(nullptr), view(nullptr) {} buffer_info(void *ptr, size_t itemsize, const std::string &format, int ndim, const std::vector &shape, const std::vector &strides) : ptr(ptr), itemsize(itemsize), size(1), format(format), diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index f2f098592..fa61a1188 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -145,7 +145,7 @@ struct type_caster::value>:: if (obj.get_type() != matrix_type.ptr()) { try { - obj = matrix_type.call(obj); + obj = matrix_type(obj); } catch (const error_already_set &) { PyErr_Clear(); return false; @@ -233,7 +233,7 @@ struct type_caster::value>:: { sizeof(StorageIndex) } )); - return matrix_type.call( + return matrix_type( std::make_tuple(data, innerIndices, outerIndices), std::make_pair(src.rows(), src.cols()) ).release(); diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h index ae3e8b38a..f74a9bdf9 100644 --- a/include/pybind11/functional.h +++ b/include/pybind11/functional.h @@ -26,7 +26,7 @@ public: object src(src_, true); value = [src](Args... args) -> Return { gil_scoped_acquire acq; - object retval(src.call(std::move(args)...)); + object retval(src(std::move(args)...)); /* Visual studio 2015 parser issue: need parentheses around this expression */ return (retval.template cast()); }; diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index b35790bf1..0b0e0eef6 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -128,6 +128,7 @@ template class array_t : public array { public: PYBIND11_OBJECT_CVT(array_t, array, is_non_null, m_ptr = ensure(m_ptr)); array_t() : array() { } + array_t(const buffer_info& info) : array(info) {} static bool is_non_null(PyObject *ptr) { return ptr != nullptr; } static PyObject *ensure(PyObject *ptr) { if (ptr == nullptr) @@ -147,7 +148,7 @@ NAMESPACE_BEGIN(detail) template struct npy_format_descriptor::value>::type> { private: - constexpr static const int values[] = { + constexpr static const int values[8] = { array::API::NPY_BYTE_, array::API::NPY_UBYTE_, array::API::NPY_SHORT_, array::API::NPY_USHORT_, array::API::NPY_INT_, array::API::NPY_UINT_, array::API::NPY_LONGLONG_, array::API::NPY_ULONGLONG_ }; public: diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 7af9b7537..11777f5ec 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -176,7 +176,7 @@ protected: if (a.descr) a.descr = strdup(a.descr); else if (a.value) - a.descr = strdup(((std::string) ((object) handle(a.value).attr("__repr__")).call().str()).c_str()); + a.descr = strdup(((std::string) ((object) handle(a.value).attr("__repr__"))().str()).c_str()); } auto const ®istered_types = detail::get_internals().registered_types_cpp; @@ -1203,7 +1203,7 @@ inline function get_overload(const void *this_ptr, const char *name) { pybind11::gil_scoped_acquire gil; \ pybind11::function overload = pybind11::get_overload(this, #name); \ if (overload) \ - return overload.call(__VA_ARGS__).template cast(); } + return overload(__VA_ARGS__).template cast(); } #define PYBIND11_OVERLOAD(ret_type, class_name, name, ...) \ PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \ diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 82725ce47..99fb5034e 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -21,7 +21,7 @@ class str; class object; class dict; class iterator; -namespace detail { class accessor; } +namespace detail { class accessor; class args; class kwargs; } /// Holds a reference to a Python object (no reference counting) class handle { @@ -43,11 +43,17 @@ public: inline detail::accessor attr(const char *key) const; inline pybind11::str str() const; template T cast() const; - template object call(Args&&... args_) const; + template + [[deprecated("call(...) was deprecated in favor of operator()(...)")]] + object call(Args&&... args) const; + template object operator()(Args&&... args) const; + inline object operator()(detail::args args) const; + inline object operator()(detail::args args, detail::kwargs kwargs) const; operator bool() const { return m_ptr != nullptr; } bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } bool check() const { return m_ptr != nullptr; } + inline detail::args operator*() const; protected: PyObject *m_ptr; }; @@ -212,6 +218,17 @@ private: ssize_t pos = 0; }; +class kwargs : public handle { +public: + kwargs(handle h) : handle(h) { } +}; + +class args : public handle { +public: + args(handle h) : handle(h) { } + kwargs operator*() const { return kwargs(*this); } +}; + inline bool PyIterable_Check(PyObject *obj) { PyObject *iter = PyObject_GetIter(obj); if (iter) { @@ -315,6 +332,7 @@ inline detail::accessor handle::attr(handle key) const { return detail::accessor inline detail::accessor handle::attr(const char *key) const { return detail::accessor(ptr(), key, true); } inline iterator handle::begin() const { return iterator(PyObject_GetIter(ptr()), false); } inline iterator handle::end() const { return iterator(nullptr, false); } +inline detail::args handle::operator*() const { return detail::args(*this); } class str : public object { public: