-
Notifications
You must be signed in to change notification settings - Fork 26
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
bind_extension_point
prevents object garbage collection
#97
Comments
Related: #79 |
Great, thanks. Should this be closed as duplicate of the other issue? |
I don't think it's quite a duplicate; it seems reasonable to me to leave both issues open. (But also reasonable to create a PR that solves both issues simultaneously.) |
So if I understand correctly, this is a bug, in the sense that it's in clear opposition to the design intent:
(from envisage/envisage/extension_point_binding.py Lines 19 to 21 in 38c1ffc
That is, the If so, I'm actually quite happy about this, since Rather than fixing the weak-ref mechanics, I'd be much happier to have an extension unbinding operation available. |
Yes indeed. In the current code (w/o this PR), the Even with adding an |
Right, but I think there's a case for "fixing" it by simply replacing the |
Yes, and that would be perfectly fine since it would match the current behavior as well. I just thought not having to do any changes in exiting projects would be good, and would also behave much like existing As of now, the need for this has been worked around. I'll get to adding |
Yes, there is that. But on the flip side, I'm a bit worried about breaking existing code that was inadvertently relying on the non-collection of the bindings. Maybe that's not a serious possibility.
Agreed that it would be good to have that consistency. |
This has just bitten me yet again. Let's see if we can fix for the upcoming Envisage release. |
Some thoughts about possible steps towards a fix:
An org-wide code search turned up no direct uses of But: there's an |
There are some horrible things going on here. At first sight, it looks as though the reference to I believe (and sincerely hope) that we have no client code that's making that injection, in which case the three-argument form of |
A code search turned up no evidence that |
This PR cleans up some odd use of global state (an extension registry that lived on the `ExtensionPoint` trait type class) that's never used in practice. In detail: - `ExtensionPointBinding` no longer uses `ExtensionPoint.extension_registry` as the default extension registry. (Note that `ExtensionPoint.extension_registry` doesn't exist unless it's explicitly injected from some external source.) - The tests for `bind_extension_point` no longer _inject_ a registry onto the `ExtensionPoint` trait type class, and have been updated to use an explicit registry everywhere - The `extension_registry` argument to `bind_extension_point` is now required rather than optional - The `bind` static method on the `ExtensionPoint` trait type, which doesn't support specifying an extension registry, has been removed. If any users of this exist, they should use `bind_extension_point` instead. My original plan was to deprecate calls to `bind_extension_point` that didn't specify a registry. That changed when I discovered that those calls only work after a deliberate injection of a registry onto the `ExtensionPoint` trait type class. To the best of my knowledge, no code is doing that (outside of `test_extension_point_binding` in this package), and all uses of `bind_extension_point` that I found in the wild are already supplying a registry explicitly. I also found no uses of the `ExtensionPoint.bind` static method. So I think in this case deprecation is unnecessary and we can simply remove the functionality. xref: #97
This PR adds an `unbind_extension_point` function that reverses the effects of `bind_extension_point`. In particular, `unbind_extension_point` removes references to the target `HasTraits` object from global state, allowing that object to be garbage collected in the usual way. (Previously, those references would live until the end of the process.) ## Detailed changes - New `unbind_extension_point` function (exported via `envisage.api`), with parameters exactly matching those of `bind_extension_point`. This undoes listener changes, and removes the binding from the global `ExtensionPointBinding._bindings` dictionary. - New private `ExtensionPointBinding._unbind` method that undoes listener changes. The `_initialize` method has been renamed to `_bind` to match. - Creation of an `ExtensionPointBinding` object no longer modifies the global `ExtensionPointBinding._bindings` dictionary; instead, that mutation of global state is done in `bind_extension_point`. (At some point in the future, we may want to move this global state somewhere else - perhaps onto the extension registry.) - `ExtensionPointBinding._bindings` is now a regular Python `dict` instead of a `WeakKeyDictionary`: the weak reference functionality never worked in the first place because our dictionary values had a strong reference to the corresponding keys, so there's no need for the additional complication introduced by the use of a `WeakKeyDictionary`. Fixes #97
bind_extension_point
stores a reference to the binding and prevents collection of the object, and it does not offer any way tounbind
either.ExtensionPointBinding
objects are stored in aWeakKeyDictionary
mappingobject
weakref to theExtensionPointBinding
instance, but the binding itself stores a strong reference to theobject
and hence prevents its garbage collection.The text was updated successfully, but these errors were encountered: