| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1027,9 +1027,7 @@ def __init__(self, func): | |||
| 1027 | 1027 | ||
| 1028 | 1028 | self.dispatcher = singledispatch(func) | |
| 1029 | 1029 | self.func = func | |
| 1030 | - | ||
| 1031 | - import weakref # see comment in singledispatch function | ||
| 1032 | - self._method_cache = weakref.WeakKeyDictionary() | ||
| 1030 | + self._method_cache = {} | ||
| 1033 | 1031 | ||
| 1034 | 1032 | def register(self, cls, method=None): | |
| 1035 | 1033 | """generic_method.register(cls, func) -> func | |
@@ -1039,30 +1037,48 @@ def register(self, cls, method=None): | |||
| 1039 | 1037 | return self.dispatcher.register(cls, func=method) | |
| 1040 | 1038 | ||
| 1041 | 1039 | def __get__(self, obj, cls=None): | |
| 1042 | - if self._method_cache is not None: | ||
| 1043 | - try: | ||
| 1044 | - _method = self._method_cache[obj] | ||
| 1045 | - except TypeError: | ||
| 1046 | - self._method_cache = None | ||
| 1047 | - except KeyError: | ||
| 1048 | - pass | ||
| 1049 | - else: | ||
| 1040 | + cache_key = id(obj) | ||
| 1041 | + | ||
| 1042 | + try: | ||
| 1043 | + _obj_ref, _method = self._method_cache[id(obj)] | ||
| 1044 | + except KeyError: | ||
| 1045 | + pass | ||
| 1046 | + else: | ||
| 1047 | + if _obj_ref() is obj: | ||
| 1050 | 1048 | return _method | |
| 1051 | 1049 | ||
| 1052 | 1050 | dispatch = self.dispatcher.dispatch | |
| 1053 | 1051 | funcname = getattr(self.func, '__name__', 'singledispatchmethod method') | |
| 1054 | - def _method(*args, **kwargs): | ||
| 1055 | - if not args: | ||
| 1056 | - raise TypeError(f'{funcname} requires at least ' | ||
| 1057 | - '1 positional argument') | ||
| 1058 | - return dispatch(args[0].__class__).__get__(obj, cls)(*args, **kwargs) | ||
| 1052 | + | ||
| 1053 | + def _remove(_): | ||
| 1054 | + self._method_cache.pop(cache_key, None) | ||
| 1055 | + | ||
| 1056 | + import weakref # see comment in singledispatch function | ||
| 1057 | + try: | ||
| 1058 | + obj_ref = weakref.ref(obj, _remove) | ||
| 1059 | + except TypeError: | ||
| 1060 | + cache_key = None | ||
| 1061 | + | ||
| 1062 | + def _method(*args, **kwargs): | ||
| 1063 | + if not args: | ||
| 1064 | + raise TypeError(f'{funcname} requires at least ' | ||
| 1065 | + '1 positional argument') | ||
| 1066 | + return dispatch(args[0].__class__).__get__(obj, cls)(*args, **kwargs) | ||
| 1067 | + else: | ||
| 1068 | + def _method(*args, **kwargs): | ||
| 1069 | + if not args: | ||
| 1070 | + raise TypeError(f'{funcname} requires at least ' | ||
| 1071 | + '1 positional argument') | ||
| 1072 | + # Make sure to use the weakref here to prevent storing | ||
| 1073 | + # a strong reference to obj in the cache | ||
| 1074 | + return dispatch(args[0].__class__).__get__(obj_ref(), cls)(*args, **kwargs) | ||
| 1059 | 1075 | ||
| 1060 | 1076 | _method.__isabstractmethod__ = self.__isabstractmethod__ | |
| 1061 | 1077 | _method.register = self.register | |
| 1062 | 1078 | update_wrapper(_method, self.func) | |
| 1063 | 1079 | ||
| 1064 | - if self._method_cache is not None: | ||
| 1065 | - self._method_cache[obj] = _method | ||
| 1080 | + if cache_key: | ||
| 1081 | + self._method_cache[cache_key] = (obj_ref, _method) | ||
| 1066 | 1082 | ||
| 1067 | 1083 | return _method | |
| 1068 | 1084 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Improve caching of :class:`functools.singledispatchmethod` to fix issues | ||
| 2 | + where sometimes different object instances could collide with each other. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments