repoview: extract a factory function of proxy class
authorYuya Nishihara <yuya@tcha.org>
Tue, 05 Dec 2017 21:50:33 +0900
changeset 35248 c752fbe228fb
parent 35247 9ce4e01f58ee
child 35249 d4ad9d695a9e
repoview: extract a factory function of proxy class This makes sure that dynamically-created class objects are isolated from local binding of repo instances. The type cache is moved to module level as it isn't tied to each instance.
mercurial/localrepo.py
mercurial/repoview.py
mercurial/statichttprepo.py
--- a/mercurial/localrepo.py	Tue Dec 05 21:37:30 2017 +0900
+++ b/mercurial/localrepo.py	Tue Dec 05 21:50:33 2017 +0900
@@ -502,9 +502,6 @@
         # post-dirstate-status hooks
         self._postdsstatus = []
 
-        # Cache of types representing filtered repos.
-        self._filteredrepotypes = weakref.WeakKeyDictionary()
-
         # generic mapping between names and nodes
         self.names = namespaces.namespaces()
 
@@ -680,20 +677,8 @@
 
     def filtered(self, name):
         """Return a filtered version of a repository"""
-        # Python <3.4 easily leaks types via __mro__. See
-        # https://bugs.python.org/issue17950. We cache dynamically
-        # created types so this method doesn't leak on every
-        # invocation.
-
-        key = self.unfiltered().__class__
-        if key not in self._filteredrepotypes:
-            # Build a new type with the repoview mixin and the base
-            # class of this repo.
-            class filteredrepo(repoview.repoview, key):
-                pass
-            self._filteredrepotypes[key] = filteredrepo
-
-        return self._filteredrepotypes[key](self, name)
+        cls = repoview.newtype(self.unfiltered().__class__)
+        return cls(self, name)
 
     @repofilecache('bookmarks', 'bookmarks.current')
     def _bookmarks(self):
--- a/mercurial/repoview.py	Tue Dec 05 21:37:30 2017 +0900
+++ b/mercurial/repoview.py	Tue Dec 05 21:50:33 2017 +0900
@@ -9,6 +9,7 @@
 from __future__ import absolute_import
 
 import copy
+import weakref
 
 from .node import nullrev
 from . import (
@@ -240,3 +241,16 @@
 
     def __delattr__(self, attr):
         return delattr(self._unfilteredrepo, attr)
+
+# Python <3.4 easily leaks types via __mro__. See
+# https://bugs.python.org/issue17950. We cache dynamically created types
+# so they won't be leaked on every invocation of repo.filtered().
+_filteredrepotypes = weakref.WeakKeyDictionary()
+
+def newtype(base):
+    """Create a new type with the repoview mixin and the given base class"""
+    if base not in _filteredrepotypes:
+        class filteredrepo(repoview, base):
+            pass
+        _filteredrepotypes[base] = filteredrepo
+    return _filteredrepotypes[base]
--- a/mercurial/statichttprepo.py	Tue Dec 05 21:37:30 2017 +0900
+++ b/mercurial/statichttprepo.py	Tue Dec 05 21:50:33 2017 +0900
@@ -166,8 +166,6 @@
         self.encodepats = None
         self.decodepats = None
         self._transref = None
-        # Cache of types representing filtered repos.
-        self._filteredrepotypes = {}
 
     def _restrictcapabilities(self, caps):
         caps = super(statichttprepository, self)._restrictcapabilities(caps)