diff options
author | Armin Rigo <arigo@tunes.org> | 2007-05-02 19:23:31 (GMT) |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2007-05-02 19:23:31 (GMT) |
commit | 9790a2706573359e02fcfc5f18f9907467f4ec49 (patch) | |
tree | d953c06fbbb8325b8ed86e707ed17f0b43b870dd /Lib/test/test_descr.py | |
parent | d83eb316dce49606041304afb6b68e85fb1794af (diff) | |
download | cpython-9790a2706573359e02fcfc5f18f9907467f4ec49.zip cpython-9790a2706573359e02fcfc5f18f9907467f4ec49.tar.gz cpython-9790a2706573359e02fcfc5f18f9907467f4ec49.tar.bz2 |
Fix for #1303614 and #1174712:
- __dict__ descriptor abuse for subclasses of built-in types
- subclassing from both ModuleType and another built-in types
Thanks zseil for the patch.
Diffstat (limited to 'Lib/test/test_descr.py')
-rw-r--r-- | Lib/test/test_descr.py | 80 |
1 files changed, 78 insertions, 2 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 53181ac..57cef44 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3,6 +3,7 @@ from test.test_support import verify, vereq, verbose, TestFailed, TESTFN, get_original_stdout from copy import deepcopy import warnings +import types warnings.filterwarnings("ignore", r'complex divmod\(\), // and % are deprecated$', @@ -861,6 +862,16 @@ def pymods(): ("getattr", "foo"), ("delattr", "foo")]) + # http://python.org/sf/1174712 + try: + class Module(types.ModuleType, str): + pass + except TypeError: + pass + else: + raise TestFailed("inheriting from ModuleType and str at the " + "same time should fail") + def multi(): if verbose: print "Testing multiple inheritance..." class C(object): @@ -2907,8 +2918,73 @@ def setdict(): cant(a, []) cant(a, 1) del a.__dict__ # Deleting __dict__ is allowed - # Classes don't allow __dict__ assignment - cant(C, {}) + + class Base(object): + pass + def verify_dict_readonly(x): + """ + x has to be an instance of a class inheriting from Base. + """ + cant(x, {}) + try: + del x.__dict__ + except (AttributeError, TypeError): + pass + else: + raise TestFailed, "shouldn't allow del %r.__dict__" % x + dict_descr = Base.__dict__["__dict__"] + try: + dict_descr.__set__(x, {}) + except (AttributeError, TypeError): + pass + else: + raise TestFailed, "dict_descr allowed access to %r's dict" % x + + # Classes don't allow __dict__ assignment and have readonly dicts + class Meta1(type, Base): + pass + class Meta2(Base, type): + pass + class D(object): + __metaclass__ = Meta1 + class E(object): + __metaclass__ = Meta2 + for cls in C, D, E: + verify_dict_readonly(cls) + class_dict = cls.__dict__ + try: + class_dict["spam"] = "eggs" + except TypeError: + pass + else: + raise TestFailed, "%r's __dict__ can be modified" % cls + + # Modules also disallow __dict__ assignment + class Module1(types.ModuleType, Base): + pass + class Module2(Base, types.ModuleType): + pass + for ModuleType in Module1, Module2: + mod = ModuleType("spam") + verify_dict_readonly(mod) + mod.__dict__["spam"] = "eggs" + + # Exception's __dict__ can be replaced, but not deleted + class Exception1(Exception, Base): + pass + class Exception2(Base, Exception): + pass + for ExceptionType in Exception, Exception1, Exception2: + e = ExceptionType() + e.__dict__ = {"a": 1} + vereq(e.a, 1) + try: + del e.__dict__ + except (TypeError, AttributeError): + pass + else: + raise TestFaied, "%r's __dict__ can be deleted" % e + def pickles(): if verbose: |