-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nicer API to pass py::capsule destructor #752
Conversation
I'm already using it in a module deployed to pypi.. any chance you can add a macro to detect the API change? :( |
If it becomes part of 2.1 or 2.2, you can of course #ifdef based on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, this definitely also removes the ambiguity of whether to borrow or steal that PyObject*
.
include/pybind11/pytypes.h
Outdated
pybind11_fail("Could not allocate capsule object!"); | ||
} | ||
|
||
explicit capsule(const void *value, void (*destructor)(void *)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
explicit
isn't needed here.
@@ -1004,10 +1004,27 @@ class capsule : public object { | |||
PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) | |||
PYBIND11_DEPRECATED("Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()") | |||
capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed) : object(ptr, stolen)) { } | |||
explicit capsule(const void *value, void (*destruct)(PyObject *) = nullptr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just deprecate this constructor for backward compatibility? (Just without the = nullptr
default and explicit
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea!
include/pybind11/pytypes.h
Outdated
pybind11_fail("Could not allocate capsule object!"); | ||
} | ||
|
||
explicit capsule(const void *value, void (*destructor)(void *)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking it would be nice to make this take a function with a (deduced) T *
argument, with a reinterpret cast of the capsule pointer to the deduced type when invoking the destructor. Unfortunately I think that would require some special handling to accept a lambda, so might not be worthwhile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I had implemented at first (with an extra closure object stored in the capsule context), but it struck me as a bit overkill.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(In any case, that sort of thing can still be added later on if there a good case for this functionality can be made. This PR is about preventing fallout from a problematic API that is about to be documented.)
Thanks @dean0x7d, I added a deprecated constructor now. I'll merge this into 2.1 unless there are objections. |
No objections. |
I'm not sure how common the use case of #733 is -- would it warrant adding a dedicated constructor? E.g. |
I think it would be nice to have. I don't understand why Python imposes |
Well, the only reason why #733 uses a capsule is because module destructors aren't exposed. If they were, then it would just be added to wherever the module docs are and wouldn't need to worry about capsules. Of course, only Python 3 supports module destructors IIRC, so you'd need this hack anyways -- but maybe it could be done internally? |
Module destructors, using this as a workaround for Python 2, seems like a useful addition, but can be added later (i.e. for 2.2). |
This is the last 2.1 PR; I think it's good as is, but the dummy-pointer version might also be useful. (Though I think it can wait as well, if you prefer to merge without it). |
I had the same thought and just added it. |
c053462
to
15c8e40
Compare
Added docs & the destructor-only capsules. |
That's a pretty weird PyPy failure -- it looks like the pytest capture object is not working. |
Rebase against current master: I just pushed a change to use pypy 5.7 instead of the 5.8 nightly in the travis-ci test, which fixes the PyPy build. |
bbe8715
to
601f4aa
Compare
thanks -- done. |
I just turned on this cool new travis-ci setting for pybind11 PR builds: https://blog.travis-ci.com/2017-03-22-introducing-auto-cancellation |
Cool -- that's a useful feature indeed! |
Hmm, that didn't fix the PyPy test failure. I wonder if you could work around it by not using a capture, perhaps by setting/checking a static variable? |
Doesn't PyPy need a couple of GC calls after a |
that's right -- I forgot about that. |
tests/test_python_types.py
Outdated
a = m.return_capsule_with_destructor_2() | ||
del a | ||
pytest.gc_collect() | ||
print(capture) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover from debugging.
that cancel feature is already starting to pay off :) |
Ok, that did it! |
Use `PyCapsule_Destructor` (part of the stable Python ABI) instead of spelling out the C `typedef`. The deprecation message is misleading. Replace with a message pointing to another existing ctor. Background: According to @wjacob the original motivation for deprecating the ctor (in PR pybind#752) was to hide Python C API details, but PR pybind#902 brought those back with a new ctor, it cannot be avoided. Having a `PyCapsule_Destructor` or a `void (*destructor)(void *)` are two separate and valid use cases.
Use `PyCapsule_Destructor` (part of the stable Python ABI) instead of spelling out the C `typedef`. The deprecation message is misleading. Replace with a message pointing to another existing ctor. Background: According to @wjakob the original motivation for deprecating the ctor (in PR pybind#752) was to hide Python C API details, but PR pybind#902 brought those back with a new ctor, it cannot be avoided. Having a `PyCapsule_Destructor` or a `void (*destructor)(void *)` are two separate and valid use cases.
Use `PyCapsule_Destructor` (part of the stable Python ABI) instead of spelling out the C `typedef`. The deprecation message is misleading. Replace with a message pointing to another existing ctor. Background: According to @wjakob the original motivation for deprecating the ctor (in PR #752) was to hide Python C API details, but PR #902 brought those back with a new ctor, it cannot be avoided. Having a `PyCapsule_Destructor` or a `void (*destructor)(void *)` are two separate and valid use cases.
The current way of specifying a destructor for
py::capsule
instances strikes me as quite inelegant (the Python C API leaks through, requiring the user to deal withPyCapsule_GetPointer
). This PR changes the convention.