diff --git a/source/baseObject.py b/source/baseObject.py index 865ff75cd17..e1ed50c2cf0 100755 --- a/source/baseObject.py +++ b/source/baseObject.py @@ -122,8 +122,11 @@ class AutoPropertyObject(with_metaclass(AutoPropertyType, object)): """ #: Tracks the instances of this class; used by L{invalidateCaches}. - #: @type: weakref.WeakKeyDictionary - __instances=weakref.WeakKeyDictionary() + #: @type: weakref.WeakValueDictionary + # We really just want to store the instances as a set of weak references, + # but as there is no easy way to have NVDAObjects and TextInfos remain hashable in Python3, as they override equality, + # We store them on a WeakValueDictionary, keyed by their id (address). + __instances=weakref.WeakValueDictionary() #: Specifies whether properties are cached by default; #: can be overridden for individual properties by setting _cache_propertyName. #: @type: bool @@ -135,7 +138,7 @@ def __new__(cls, *args, **kwargs): #: Maps properties to cached values. #: @type: dict self._propertyCache={} - self.__instances[self]=None + self.__instances[id(self)]=self return self def _getPropertyViaCache(self,getterMethod=None): @@ -158,7 +161,7 @@ def invalidateCaches(cls): # We use keys() here instead of iterkeys(), as invalidating the cache on an object may cause instances to disappear, # which would in turn cause an exception due to the dictionary changing size during iteration. # #9067 (Py3 review required): because of this, wrap this in a list, as dict.keys() in Python 3 returns iterators. - for instance in list(cls.__instances.keys()): + for instance in list(cls.__instances.values()): instance.invalidateCache() class ScriptableType(AutoPropertyType): diff --git a/source/eventHandler.py b/source/eventHandler.py index 6f724c293ef..3d99e30e643 100755 --- a/source/eventHandler.py +++ b/source/eventHandler.py @@ -20,8 +20,10 @@ #Some dicts to store event counts by name and or obj _pendingEventCountsByName={} -_pendingEventCountsByObj={} -_pendingEventCountsByNameAndObj={} +# Note that due to the fact it is hard to keep NVDAObjects remaining hashable in Python3 due to their equality method being overridden, +# the id (address) of the NVDAObject will be used as the key in the dict, not the NVDAObject itself. +_pendingEventCountsByObjID={} +_pendingEventCountsByNameAndObjID={} # Needed to ensure updates are atomic, as these might be updated from multiple threads simultaneously. _pendingEventCountsLock=threading.RLock() @@ -38,8 +40,8 @@ def queueEvent(eventName,obj,**kwargs): lastQueuedFocusObject=obj with _pendingEventCountsLock: _pendingEventCountsByName[eventName]=_pendingEventCountsByName.get(eventName,0)+1 - _pendingEventCountsByObj[obj]=_pendingEventCountsByObj.get(obj,0)+1 - _pendingEventCountsByNameAndObj[(eventName,obj)]=_pendingEventCountsByNameAndObj.get((eventName,obj),0)+1 + _pendingEventCountsByObjID[id(obj)]=_pendingEventCountsByObjID.get(id(obj),0)+1 + _pendingEventCountsByNameAndObjID[(eventName,id(obj))]=_pendingEventCountsByNameAndObjID.get((eventName,id(obj)),0)+1 queueHandler.queueFunction(queueHandler.eventQueue,_queueEventCallback,eventName,obj,kwargs) def _queueEventCallback(eventName,obj,kwargs): @@ -49,16 +51,16 @@ def _queueEventCallback(eventName,obj,kwargs): _pendingEventCountsByName[eventName]=(curCount-1) elif curCount==1: del _pendingEventCountsByName[eventName] - curCount=_pendingEventCountsByObj.get(obj,0) + curCount=_pendingEventCountsByObjID.get(id(obj),0) if curCount>1: - _pendingEventCountsByObj[obj]=(curCount-1) + _pendingEventCountsByObjID[id(obj)]=(curCount-1) elif curCount==1: - del _pendingEventCountsByObj[obj] - curCount=_pendingEventCountsByNameAndObj.get((eventName,obj),0) + del _pendingEventCountsByObjID[id(obj)] + curCount=_pendingEventCountsByNameAndObjID.get((eventName,id(obj)),0) if curCount>1: - _pendingEventCountsByNameAndObj[(eventName,obj)]=(curCount-1) + _pendingEventCountsByNameAndObjID[(eventName,id(obj))]=(curCount-1) elif curCount==1: - del _pendingEventCountsByNameAndObj[(eventName,obj)] + del _pendingEventCountsByNameAndObjID[(eventName,id(obj))] executeEvent(eventName,obj,**kwargs) def isPendingEvents(eventName=None,obj=None): @@ -73,11 +75,11 @@ def isPendingEvents(eventName=None,obj=None): if not eventName and not obj: return bool(len(_pendingEventCountsByName)) elif not eventName and obj: - return obj in _pendingEventCountsByObj + return id(obj) in _pendingEventCountsByObjID elif eventName and not obj: return eventName in _pendingEventCountsByName elif eventName and obj: - return (eventName,obj) in _pendingEventCountsByNameAndObj + return (eventName,id(obj)) in _pendingEventCountsByNameAndObjID class _EventExecuter(object): """Facilitates execution of a chain of event functions.