do not timebomb other tests with orphaned finalize calls

This commit is contained in:
Nils Nemitz 2021-06-13 20:12:01 +09:00
parent 1c49aef4ae
commit 0e066308fa
2 changed files with 29 additions and 33 deletions

View File

@ -5,6 +5,7 @@ import weakref
import itertools import itertools
import collections import collections
import warnings import warnings
import time
__all__ = ['StyleRegistry'] __all__ = ['StyleRegistry']
@ -89,9 +90,8 @@ class StyleRegistry(QtCore.QObject):
self.color_dic.update( DEFAULT_COLORS) self.color_dic.update( DEFAULT_COLORS)
# set of objects that are registered for update on palette change: # set of objects that are registered for update on palette change:
self.registered_objects = {} # stores registration: (weakref(object), descriptor), deletion handled by weakref.finalize self.registered_objects = {} # stores registration: (weakref(object), descriptor), deletion handled by weakref.finalize
# DEBUG ---------------------------- # DEBUG
self.unregistered_objects = {} # set of registrations that have already been deleted. # self.registered_history = {} # stores all previous registrations for debugging
# ----------------------------------
self.color_cache = weakref.WeakValueDictionary() # keeps a cache of QColor objects, key: (name, alpha) self.color_cache = weakref.WeakValueDictionary() # keeps a cache of QColor objects, key: (name, alpha)
self.pen_cache = weakref.WeakValueDictionary() # keeps a cache of QPen objects, key: (name, width, alpha) self.pen_cache = weakref.WeakValueDictionary() # keeps a cache of QPen objects, key: (name, width, alpha)
self.brush_cache = weakref.WeakValueDictionary() # keeps a cache of QBrush objects, key: (name, alpha) self.brush_cache = weakref.WeakValueDictionary() # keeps a cache of QBrush objects, key: (name, alpha)
@ -302,40 +302,35 @@ class StyleRegistry(QtCore.QObject):
""" """
if hasattr(obj,'colorRegistration'): if hasattr(obj,'colorRegistration'):
registration = obj.registration registration = obj.registration
if registration in self.registered_objects:
# if this object is already registered, we should not try to add another finalize call.
return
else: else:
registration = next(StyleRegistry._registrationGenerator) registration = next(StyleRegistry._registrationGenerator)
obj.registration = registration # patch in attribute obj.registration = registration # patch in attribute
if registration in self.registered_objects:
print('re-registering',registration,' objects is:', obj, 'was:', self.registered_objects[registration] )
raise RuntimeError('re-registering object')
quit()
# if registration > 0:
# if (registration-1) not in self.registered_objects:
# print('previous registration',registration-1,'is not in list of registered objects!')
# raise RuntimeError('re-registering object')
# quit()
self.registered_objects[registration] = (weakref.ref(obj), desc) self.registered_objects[registration] = (weakref.ref(obj), desc)
fin = weakref.finalize(obj, self.unregister, registration) # DEBUG:
# self.registered_history[registration] = (weakref.ref(obj), desc)
fin = weakref.finalize(obj, self.unregister, registration )
fin.atexit = False # no need to clean up registry on program exit fin.atexit = False # no need to clean up registry on program exit
print('registering', registration, '(',str(obj),'):',str(desc)) # DEBUG:
# print('registering', registration, '(',str(obj),'):',str(desc))
def unregister(self, registration): def unregister(self, registration):
""" """
Removes obj (QColor, QPen or QBrush) from the registry, usually called by finalize on deletion Removes obj (QColor, QPen or QBrush) from the registry, usually called by finalize on deletion
""" """
if registration in self.unregistered_objects: obj, desc = self.registered_objects.pop(registration, (False, False))
print('unregistering',registration,', which was previous unregistered!') if obj is False:
raise RuntimeError('double un-registering object') # DEBUG:
quit() # obj_hist, desc_hist = self.registered_history.get(registration, (False, False))
# if obj_hist is not False:
obj, desc = self.registered_objects[registration] # raise RuntimeError(f'Unregistered object {registration} already unregistered, previously registered as {obj_hist} ({desc_hist}).')
print('unregistering', registration, '(',str(obj),'):',str(desc)) raise RuntimeError(f'Unregistered object {registration} unlisted.')
# DEBUG:
# print('unregistering', registration, '(',str(obj),'):',str(desc))
del obj, desc del obj, desc
self.unregistered_objects[registration] = True
#
# if registration in self.registered_objects:
del self.registered_objects[registration]
def colors(self): def colors(self):
""" return current list of colors """ """ return current list of colors """
@ -357,7 +352,7 @@ class StyleRegistry(QtCore.QObject):
self.color_dic.clear() self.color_dic.clear()
self.color_dic.update(colors) self.color_dic.update(colors)
# notifies registerd color objects of new assignments: # notifies registered color objects of new assignments:
for ref, desc in self.registered_objects.values(): for ref, desc in self.registered_objects.values():
# ref, desc = self.registered_objects[key] # ref, desc = self.registered_objects[key]
obj = ref() obj = ref()

View File

@ -17,9 +17,10 @@ def test_registration():
def test_specification_formats(): def test_specification_formats():
next_reg = None next_reg = None
reg = pg.functions.styleRegistry() reg = pg.functions.styleRegistry()
reg.registered_objects = {} # force-clear registry initial_length = len(reg.registered_objects)
# reg.registered_objects = {} # force-clear registry
obj_list = [] # start building a list of test objects obj_list = [] # start building a list of test objects
assert len(reg.registered_objects) == len(obj_list) # registry should be empty assert len(reg.registered_objects)-initial_length == len(obj_list) # registry should be empty
args = ( # Do we expect a registered pen (or 'None'?) for this parameter? args = ( # Do we expect a registered pen (or 'None'?) for this parameter?
( True, ('p0', 1, 255) ), ( True, ('p0', 1, 255) ),
( True, ('p1', None, 192) ), ( True, ('p1', None, 192) ),
@ -84,7 +85,7 @@ def test_specification_formats():
else: else:
assert not hasattr(color,'registration') assert not hasattr(color,'registration')
del color del color
assert len(reg.registered_objects) == len(obj_list) assert len(reg.registered_objects)-initial_length == len(obj_list)
new_colors = ( new_colors = (
('p0', QtGui.QColor('#000001') ), ('p0', QtGui.QColor('#000001') ),
@ -104,12 +105,12 @@ def test_specification_formats():
del obj del obj
del qcol # do not keep extra references del qcol # do not keep extra references
assert len(reg.registered_objects) == len(obj_list) assert len(reg.registered_objects)-initial_length == len(obj_list)
obj_list = [] # delete all objects obj_list = [] # delete all objects
print('remaining registered objects:', reg.registered_objects ) print('remaining registered objects:', reg.registered_objects )
assert ( assert (
len(reg.registered_objects) == 0 or # All cleared by finalize calls, except that len(reg.registered_objects)-initial_length == 0 or # All cleared by finalize calls, except that
len(reg.registered_objects) == 1 # PySide seems to be left with one surviving reference len(reg.registered_objects)-initial_length == 1 # PySide seems to be left with one surviving reference
) )
def test_mkColor_edge_case_specifications(): def test_mkColor_edge_case_specifications():