# HG changeset patch # User Yuya Nishihara # Date 2017-12-05 12:50:33 # Node ID c752fbe228fb5fb5338b4b90efcfed7c2046ef7b # Parent 9ce4e01f58ee04d754c9d0dc6887492d2ce37c15 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. diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -502,9 +502,6 @@ class localrepository(object): # 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 @@ class localrepository(object): 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): diff --git a/mercurial/repoview.py b/mercurial/repoview.py --- a/mercurial/repoview.py +++ b/mercurial/repoview.py @@ -9,6 +9,7 @@ from __future__ import absolute_import import copy +import weakref from .node import nullrev from . import ( @@ -240,3 +241,16 @@ class repoview(object): 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] diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py --- a/mercurial/statichttprepo.py +++ b/mercurial/statichttprepo.py @@ -166,8 +166,6 @@ class statichttprepository(localrepo.loc 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)