Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into feature/py_move_s…
Browse files Browse the repository at this point in the history
…hared
  • Loading branch information
EricCousineau-TRI committed Dec 18, 2017
2 parents 112a846 + a303c6f commit a1e9679
Show file tree
Hide file tree
Showing 23 changed files with 168 additions and 31 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,10 @@ install:
${PYPY:+--extra-index-url https://imaginary.ca/trusty-pypi}
echo "done."
wget -q -O eigen.tar.gz https://bitbucket.org/eigen/eigen/get/3.3.3.tar.gz
tar xzf eigen.tar.gz
export CMAKE_INCLUDE_PATH="${CMAKE_INCLUDE_PATH:+$CMAKE_INCLUDE_PATH:}$PWD/eigen-eigen-67e894c6cd8f"
mkdir eigen
curl -fsSL https://bitbucket.org/eigen/eigen/get/3.3.4.tar.bz2 | \
tar --extract -j --directory=eigen --strip-components=1
export CMAKE_INCLUDE_PATH="${CMAKE_INCLUDE_PATH:+$CMAKE_INCLUDE_PATH:}$PWD/eigen"
fi
set +e
script:
Expand Down
12 changes: 11 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,18 @@ adhere to the following rules to make the process as smooth as possible:
* This project has a strong focus on providing general solutions using a
minimal amount of code, thus small pull requests are greatly preferred.

### License
### Licensing of contributions

pybind11 is provided under a BSD-style license that can be found in the
``LICENSE`` file. By using, distributing, or contributing to this project, you
agree to the terms and conditions of this license.

You are under no obligation whatsoever to provide any bug fixes, patches, or
upgrades to the features, functionality or performance of the source code
("Enhancements") to anyone; however, if you choose to make your Enhancements
available either publicly, or directly to the author of this software, without
imposing a separate written license agreement for such Enhancements, then you
hereby grant the following license: a non-exclusive, royalty-free perpetual
license to install, use, modify, prepare derivative works, incorporate into
other computer software, distribute, and sublicense such enhancements or
derivative works thereof, in binary and source code form.
11 changes: 2 additions & 9 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,5 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

You are under no obligation whatsoever to provide any bug fixes, patches, or
upgrades to the features, functionality or performance of the source code
("Enhancements") to anyone; however, if you choose to make your Enhancements
available either publicly, or directly to the author of this software, without
imposing a separate written license agreement for such Enhancements, then you
hereby grant the following license: a non-exclusive, royalty-free perpetual
license to install, use, modify, prepare derivative works, incorporate into
other computer software, distribute, and sublicense such enhancements or
derivative works thereof, in binary and source code form.
Please also refer to the file CONTRIBUTING.md, which clarifies licensing of
external contributions to this project including patches, pull requests, etc.
15 changes: 15 additions & 0 deletions docs/advanced/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,21 @@ avoids this issue involves weak reference with a cleanup callback:
// Create a weak reference with a cleanup callback and initially leak it
(void) py::weakref(m.attr("BaseClass"), cleanup_callback).release();
.. note::

PyPy (at least version 5.9) does not garbage collect objects when the
interpreter exits. An alternative approach (which also works on CPython) is to use
the :py:mod:`atexit` module [#f7]_, for example:

.. code-block:: cpp
auto atexit = py::module::import("atexit");
atexit.attr("register")(py::cpp_function([]() {
// perform cleanup here -- this function is called with the GIL held
}));
.. [#f7] https://docs.python.org/3/library/atexit.html
Generating documentation using Sphinx
=====================================
Expand Down
3 changes: 3 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ v2.3.0 (Not yet released)
* Added support for write only properties.
`#1144 <https://github.com/pybind/pybind11/pull/1144>`_.

* The ``value()`` method of ``py::enum_`` now accepts an optional docstring
that will be shown in the documentation of the associated enumeration.

v2.2.1 (September 14, 2017)
-----------------------------------------------------

Expand Down
16 changes: 16 additions & 0 deletions docs/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,19 @@ Common gotchas to watch out for involve not ``free()``-ing memory region
that that were ``malloc()``-ed in another shared library, using data
structures with incompatible ABIs, and so on. pybind11 is very careful not
to make these types of mistakes.

How to cite this project?
=========================

We suggest the following BibTeX template to cite pybind11 in scientific
discourse:

.. code-block:: bash
@misc{pybind11,
author = {Wenzel Jakob and Jason Rhinelander and Dean Moldovan},
year = {2017},
note = {https://github.com/pybind/pybind11},
title = {pybind11 -- Seamless operability between C++11 and Python}
}
9 changes: 5 additions & 4 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1097,11 +1097,12 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
static handle cast(T src, return_value_policy /* policy */, handle /* parent */) {
if (std::is_floating_point<T>::value) {
return PyFloat_FromDouble((double) src);
} else if (sizeof(T) <= sizeof(long)) {
} else if (sizeof(T) <= sizeof(ssize_t)) {
// This returns a long automatically if needed
if (std::is_signed<T>::value)
return PyLong_FromLong((long) src);
return PYBIND11_LONG_FROM_SIGNED(src);
else
return PyLong_FromUnsignedLong((unsigned long) src);
return PYBIND11_LONG_FROM_UNSIGNED(src);
} else {
if (std::is_signed<T>::value)
return PyLong_FromLongLong((long long) src);
Expand Down Expand Up @@ -1864,7 +1865,7 @@ template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_ca
throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)");
#else
throw cast_error("Unable to cast Python instance of type " +
(std::string) str(handle.get_type()) + " to C++ type '" + type_id<T>() + "''");
(std::string) str(handle.get_type()) + " to C++ type '" + type_id<T>() + "'");
#endif
}
return conv;
Expand Down
4 changes: 4 additions & 0 deletions include/pybind11/complex.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ template <typename T> struct format_descriptor<std::complex<T>, detail::enable_i
static std::string format() { return std::string(value); }
};

#ifndef PYBIND11_CPP17

template <typename T> constexpr const char format_descriptor<
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];

#endif

NAMESPACE_BEGIN(detail)

template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
Expand Down
8 changes: 8 additions & 0 deletions include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@
#define PYBIND11_BYTES_SIZE PyBytes_Size
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) o)
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) o)
#define PYBIND11_BYTES_NAME "bytes"
#define PYBIND11_STRING_NAME "str"
#define PYBIND11_SLICE_OBJECT PyObject
Expand All @@ -180,6 +182,8 @@
#define PYBIND11_BYTES_SIZE PyString_Size
#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
#define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed.
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed.
#define PYBIND11_BYTES_NAME "str"
#define PYBIND11_STRING_NAME "unicode"
#define PYBIND11_SLICE_OBJECT PySliceObject
Expand Down Expand Up @@ -803,9 +807,13 @@ template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_ar
static std::string format() { return std::string(1, c); }
};

#if !defined(PYBIND11_CPP17)

template <typename T> constexpr const char format_descriptor<
T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2];

#endif

/// RAII wrapper that temporarily clears any Python error state
struct error_scope {
PyObject *type, *value, *trace;
Expand Down
5 changes: 5 additions & 0 deletions include/pybind11/eigen.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# ifdef __clang__
// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated
// under Clang, so disable that warning here:
# pragma GCC diagnostic ignored "-Wdeprecated"
# endif
# if __GNUC__ >= 7
# pragma GCC diagnostic ignored "-Wint-in-bool-context"
# endif
Expand Down
27 changes: 21 additions & 6 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -1708,15 +1708,30 @@ template <typename Type> class enum_ : public class_<Type> {
auto m_entries_ptr = m_entries.inc_ref().ptr();
def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str {
for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
if (pybind11::cast<Type>(kv.second) == value)
if (pybind11::cast<Type>(kv.second[int_(0)]) == value)
return pybind11::str("{}.{}").format(name, kv.first);
}
return pybind11::str("{}.???").format(name);
});
def_property_readonly_static("__members__", [m_entries_ptr](object /* self */) {
def_property_readonly_static("__doc__", [m_entries_ptr](handle self) {
std::string docstring;
const char *tp_doc = ((PyTypeObject *) self.ptr())->tp_doc;
if (tp_doc)
docstring += std::string(tp_doc) + "\n\n";
docstring += "Members:";
for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
auto key = std::string(pybind11::str(kv.first));
auto comment = kv.second[int_(1)];
docstring += "\n\n " + key;
if (!comment.is_none())
docstring += " : " + (std::string) pybind11::str(comment);
}
return docstring;
});
def_property_readonly_static("__members__", [m_entries_ptr](handle /* self */) {
dict m;
for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr))
m[kv.first] = kv.second;
m[kv.first] = kv.second[int_(0)];
return m;
}, return_value_policy::copy);
def(init([](Scalar i) { return static_cast<Type>(i); }));
Expand Down Expand Up @@ -1764,15 +1779,15 @@ template <typename Type> class enum_ : public class_<Type> {
/// Export enumeration entries into the parent scope
enum_& export_values() {
for (const auto &kv : m_entries)
m_parent.attr(kv.first) = kv.second;
m_parent.attr(kv.first) = kv.second[int_(0)];
return *this;
}

/// Add an enumeration entry
enum_& value(char const* name, Type value) {
enum_& value(char const* name, Type value, const char *doc = nullptr) {
auto v = pybind11::cast(value, return_value_policy::copy);
this->attr(name) = v;
m_entries[pybind11::str(name)] = v;
m_entries[pybind11::str(name)] = std::make_pair(v, doc);
return *this;
}

Expand Down
3 changes: 3 additions & 0 deletions include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ class error_already_set : public std::runtime_error {
PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr());
}

error_already_set(const error_already_set &) = default;
error_already_set(error_already_set &&) = default;

inline ~error_already_set();

/// Give the currently-held error back to Python, if any. If there is currently a Python error
Expand Down
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function(pybind11_enable_warnings target_name)
if(MSVC)
target_compile_options(${target_name} PRIVATE /W4)
else()
target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual)
target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated)
endif()

if(PYBIND11_WERROR)
Expand Down
5 changes: 5 additions & 0 deletions tests/test_builtin_casters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,9 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_complex
m.def("complex_cast", [](float x) { return "{}"_s.format(x); });
m.def("complex_cast", [](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });

// test int vs. long (Python 2)
m.def("int_cast", []() {return (int) 42;});
m.def("long_cast", []() {return (long) 42;});
m.def("longlong_cast", []() {return ULLONG_MAX;});
}
13 changes: 13 additions & 0 deletions tests/test_builtin_casters.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,16 @@ def test_numpy_bool():
assert convert(np.bool_(False)) is False
assert noconvert(np.bool_(True)) is True
assert noconvert(np.bool_(False)) is False


def test_int_long():
"""In Python 2, a C++ int should return a Python int rather than long
if possible: longs are not always accepted where ints are used (such
as the argument to sys.exit()). A C++ long long is always a Python
long."""

import sys
must_be_long = type(getattr(sys, 'maxint', 1) + 1)
assert isinstance(m.int_cast(), int)
assert isinstance(m.long_cast(), int)
assert isinstance(m.longlong_cast(), must_be_long)
2 changes: 2 additions & 0 deletions tests/test_call_policies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ TEST_SUBMODULE(call_policies, m) {
class Child {
public:
Child() { py::print("Allocating child."); }
Child(const Child &) = default;
Child(Child &&) = default;
~Child() { py::print("Releasing child."); }
};
py::class_<Child>(m, "Child")
Expand Down
10 changes: 9 additions & 1 deletion tests/test_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
TEST_SUBMODULE(class_, m) {
// test_instance
struct NoConstructor {
NoConstructor() = default;
NoConstructor(const NoConstructor &) = default;
NoConstructor(NoConstructor &&) = default;
static NoConstructor *new_instance() {
auto *ptr = new NoConstructor();
print_created(ptr, "via new_instance");
Expand Down Expand Up @@ -82,7 +85,12 @@ TEST_SUBMODULE(class_, m) {
m.def("dog_bark", [](const Dog &dog) { return dog.bark(); });

// test_automatic_upcasting
struct BaseClass { virtual ~BaseClass() {} };
struct BaseClass {
BaseClass() = default;
BaseClass(const BaseClass &) = default;
BaseClass(BaseClass &&) = default;
virtual ~BaseClass() {}
};
struct DerivedClass1 : BaseClass { };
struct DerivedClass2 : BaseClass { };

Expand Down
14 changes: 14 additions & 0 deletions tests/test_constants_and_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,30 @@ namespace test_exc_sp {
int f1(int x) noexcept { return x+1; }
int f2(int x) noexcept(true) { return x+2; }
int f3(int x) noexcept(false) { return x+3; }
#if defined(__GNUG__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated"
#endif
int f4(int x) throw() { return x+4; } // Deprecated equivalent to noexcept(true)
#if defined(__GNUG__)
# pragma GCC diagnostic pop
#endif
struct C {
int m1(int x) noexcept { return x-1; }
int m2(int x) const noexcept { return x-2; }
int m3(int x) noexcept(true) { return x-3; }
int m4(int x) const noexcept(true) { return x-4; }
int m5(int x) noexcept(false) { return x-5; }
int m6(int x) const noexcept(false) { return x-6; }
#if defined(__GNUG__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated"
#endif
int m7(int x) throw() { return x-7; }
int m8(int x) const throw() { return x-8; }
#if defined(__GNUG__)
# pragma GCC diagnostic pop
#endif
};
}

Expand Down
6 changes: 3 additions & 3 deletions tests/test_enum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ TEST_SUBMODULE(enums, m) {
EOne = 1,
ETwo
};
py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic())
.value("EOne", EOne)
.value("ETwo", ETwo)
py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration")
.value("EOne", EOne, "Docstring for EOne")
.value("ETwo", ETwo, "Docstring for ETwo")
.export_values();

// test_scoped_enum
Expand Down
16 changes: 16 additions & 0 deletions tests/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ def test_unscoped_enum():
assert m.UnscopedEnum.__members__ == \
{"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo}

assert m.UnscopedEnum.__doc__ == \
'''An unscoped enumeration
Members:
EOne : Docstring for EOne
ETwo : Docstring for ETwo''' or m.UnscopedEnum.__doc__ == \
'''An unscoped enumeration
Members:
ETwo : Docstring for ETwo
EOne : Docstring for EOne'''

# no TypeError exception for unscoped enum ==/!= int comparisons
y = m.UnscopedEnum.ETwo
assert y == 2
Expand Down
1 change: 1 addition & 0 deletions tests/test_factory_constructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ TEST_SUBMODULE(factory_constructors, m) {
// test_reallocations
// Class that has verbose operator_new/operator_delete calls
struct NoisyAlloc {
NoisyAlloc(const NoisyAlloc &) = default;
NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); }
NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); }
~NoisyAlloc() { py::print("~NoisyAlloc()"); }
Expand Down
Loading

0 comments on commit a1e9679

Please sign in to comment.