--- a/mercurial/localrepo.py Tue Jul 11 02:10:04 2017 +0900
+++ b/mercurial/localrepo.py Sat Jul 01 20:51:19 2017 -0700
@@ -430,6 +430,9 @@
# 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()
@@ -539,11 +542,21 @@
def filtered(self, name):
"""Return a filtered version of a repository"""
- # build a new class with the mixin and the current class
- # (possibly subclass of the repo)
- class filteredrepo(repoview.repoview, self.unfiltered().__class__):
- pass
- return filteredrepo(self, name)
+ # 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. Give it a name containing the
+ # filter name to aid debugging.
+ bases = (repoview.repoview, key)
+ cls = type('%sfilteredrepo' % name, bases, {})
+ self._filteredrepotypes[key] = cls
+
+ return self._filteredrepotypes[key](self, name)
@repofilecache('bookmarks', 'bookmarks.current')
def _bookmarks(self):