Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r76789:494280f37b17 Date: 2015-04-14 13:01 +0200 http://bitbucket.org/pypy/pypy/changeset/494280f37b17/
Log: issue 2029: try a bit harder to hide the "default_factory" attribute diff --git a/pypy/module/_collections/app_defaultdict.py b/pypy/module/_collections/app_defaultdict.py --- a/pypy/module/_collections/app_defaultdict.py +++ b/pypy/module/_collections/app_defaultdict.py @@ -11,6 +11,7 @@ class defaultdict(dict): + __slots__ = ['__default_factory'] def __init__(self, *args, **kwds): if len(args) > 0: @@ -20,7 +21,7 @@ raise TypeError("first argument must be callable") else: default_factory = None - self.default_factory = default_factory + defaultdict.__default_factory.__set__(self, default_factory) super(defaultdict, self).__init__(*args, **kwds) def __missing__(self, key): @@ -33,15 +34,15 @@ return "defaultdict(...)" try: recurse.add(id(self)) - return "defaultdict(%s, %s)" % (repr(self.default_factory), super(defaultdict, self).__repr__()) + return "defaultdict(%s, %s)" % (self.__default_factory, + super(defaultdict, self).__repr__()) finally: recurse.remove(id(self)) def copy(self): - return type(self)(self.default_factory, self) + return type(self)(self.__default_factory, self) - def __copy__(self): - return self.copy() + __copy__ = copy def __reduce__(self): """ @@ -55,4 +56,5 @@ This API is used by pickle.py and copy.py. """ - return (type(self), (self.default_factory,), None, None, self.iteritems()) + return (type(self), (self.__default_factory,), None, None, + defaultdict.iteritems(self)) diff --git a/pypy/module/_collections/interp_defaultdict.py b/pypy/module/_collections/interp_defaultdict.py --- a/pypy/module/_collections/interp_defaultdict.py +++ b/pypy/module/_collections/interp_defaultdict.py @@ -4,7 +4,8 @@ # An interp-level version of this method. This is mostly only # useful because it can be executed atomically in the presence of # threads. - w_default_factory = space.getattr(w_self, space.wrap('default_factory')) + w_default_factory = space.getattr(w_self, + space.wrap('_defaultdict__default_factory')) if space.is_w(w_default_factory, space.w_None): raise OperationError(space.w_KeyError, space.newtuple([w_key])) w_value = space.call_function(w_default_factory) diff --git a/pypy/module/_collections/test/test_defaultdict.py b/pypy/module/_collections/test/test_defaultdict.py --- a/pypy/module/_collections/test/test_defaultdict.py +++ b/pypy/module/_collections/test/test_defaultdict.py @@ -54,3 +54,17 @@ assert len(d2) == 1 assert d2[2] == 3 assert d2[3] == 42 + + def test_no_dict(self): + import _collections + assert not hasattr(_collections.defaultdict(), '__dict__') + + def test_no_setattr(self): + import _collections + class D(_collections.defaultdict): + def __setattr__(self, attr, name): + raise AssertionError + d = D(int) + assert d['5'] == 0 + d['6'] += 3 + assert d['6'] == 3 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit