| 1 |
From 2ad8113511381ae502a000809700cb672c073f92 Mon Sep 17 00:00:00 2001
|
| 2 |
From: Brian Harring <ferringb@gmail.com>
|
| 3 |
Date: Fri, 11 Nov 2011 02:04:43 -0800
|
| 4 |
Subject: [PATCH] WeakRefFinalizer: use atexit to cleanup any strongly
|
| 5 |
referenced instances at sys.exit
|
| 6 |
|
| 7 |
---
|
| 8 |
NEWS | 4 ++++
|
| 9 |
snakeoil/weakrefs.py | 23 ++++++++++++++++++++---
|
| 10 |
2 files changed, 24 insertions(+), 3 deletions(-)
|
| 11 |
|
| 12 |
diff --git a/NEWS b/NEWS
|
| 13 |
index 04015ee..4fbfb0e 100644
|
| 14 |
--- a/NEWS
|
| 15 |
+++ b/NEWS
|
| 16 |
@@ -2,6 +2,10 @@ Snakeoil Release Notes
|
| 17 |
======================
|
| 18 |
|
| 19 |
|
| 20 |
+* Fix WeakRefFinalizer so that instances that are still strongly referenced
|
| 21 |
+ at the time of sys.exit have their finalizers ran via atexit.
|
| 22 |
+
|
| 23 |
+
|
| 24 |
snakeoil 0.4.4: Oct 26th, 2011
|
| 25 |
|
| 26 |
* use sane permissions for directories created for tests.
|
| 27 |
diff --git a/snakeoil/weakrefs.py b/snakeoil/weakrefs.py
|
| 28 |
index 1a25a9c..272b4d3 100644
|
| 29 |
--- a/snakeoil/weakrefs.py
|
| 30 |
+++ b/snakeoil/weakrefs.py
|
| 31 |
@@ -10,13 +10,15 @@ __all__ = ("WeakValCache", "WeakRefFinalizer")
|
| 32 |
# Unused import
|
| 33 |
# pylint: disable-msg=W0611
|
| 34 |
|
| 35 |
+import atexit
|
| 36 |
+
|
| 37 |
try:
|
| 38 |
# No name in module
|
| 39 |
# pylint: disable-msg=E0611
|
| 40 |
from snakeoil._caching import WeakValCache
|
| 41 |
- from weakref import ref
|
| 42 |
+ from weakref import ref, WeakKeyDictionary
|
| 43 |
except ImportError:
|
| 44 |
- from weakref import WeakValueDictionary as WeakValCache, ref
|
| 45 |
+ from weakref import WeakValueDictionary as WeakValCache, ref, WeakKeyDictionary
|
| 46 |
|
| 47 |
from snakeoil.obj import make_kls, BaseDelayedObject
|
| 48 |
from snakeoil.currying import partial
|
| 49 |
@@ -38,7 +40,6 @@ class WeakRefProxy(BaseDelayedObject):
|
| 50 |
obj.__enable_finalization__(weakref)
|
| 51 |
return obj
|
| 52 |
|
| 53 |
-
|
| 54 |
def __enable_finalization__(self, weakref):
|
| 55 |
# note we directly access the class, to ensure the instance hasn't overshadowed.
|
| 56 |
self.__class__.__finalizer_weakrefs__[id(self)] = weakref
|
| 57 |
@@ -116,6 +117,9 @@ class WeakRefFinalizer(type):
|
| 58 |
>>> del obj
|
| 59 |
finalization invoked: bar
|
| 60 |
"""
|
| 61 |
+
|
| 62 |
+ __known_classes__ = WeakKeyDictionary()
|
| 63 |
+
|
| 64 |
def __new__(cls, name, bases, d):
|
| 65 |
if '__del__' in d:
|
| 66 |
d['__finalizer__'] = d.pop("__del__")
|
| 67 |
@@ -137,6 +141,7 @@ class WeakRefFinalizer(type):
|
| 68 |
new_cls = super(WeakRefFinalizer, cls).__new__(cls, name, bases, d)
|
| 69 |
new_cls.__proxy_class__ = partial(make_kls(new_cls, WeakRefProxy), cls, lambda x:x)
|
| 70 |
new_cls.__proxy_class__.__name__ = name
|
| 71 |
+ cls.__known_classes__[new_cls] = True
|
| 72 |
return new_cls
|
| 73 |
|
| 74 |
def __call__(cls, *a, **kw):
|
| 75 |
@@ -146,3 +151,15 @@ class WeakRefFinalizer(type):
|
| 76 |
# weakref registration
|
| 77 |
getattr(proxy, '__finalizer__')
|
| 78 |
return proxy
|
| 79 |
+
|
| 80 |
+ @classmethod
|
| 81 |
+ def _atexit_cleanup(cls):
|
| 82 |
+ # cleanup any instances strongly referenced at the time of sys.exit
|
| 83 |
+ target_classes = cls.__known_classes__.keys()
|
| 84 |
+ for target_cls in target_classes:
|
| 85 |
+ for target_ref in target_cls.__finalizer_weakrefs__.values():
|
| 86 |
+ obj = target_ref()
|
| 87 |
+ if obj is not None:
|
| 88 |
+ obj.__finalizer__()
|
| 89 |
+
|
| 90 |
+atexit.register(WeakRefFinalizer._atexit_cleanup)
|
| 91 |
--
|
| 92 |
1.7.8.rc1
|
| 93 |
|