use a invalid name for the __class__ closure for super() (closes #12370)
This prevents the assignment of __class__ in the class body from breaking super. (Although a determined person could do locals()["@__class__"] = 4)
This commit is contained in:
parent
019d0f27a3
commit
f5ff22329b
|
@ -81,6 +81,16 @@ class TestSuper(unittest.TestCase):
|
|||
|
||||
self.assertEqual(E().f(), 'AE')
|
||||
|
||||
def test___class___set(self):
|
||||
# See issue #12370
|
||||
class X(A):
|
||||
def f(self):
|
||||
return super().f()
|
||||
__class__ = 413
|
||||
x = X()
|
||||
self.assertEqual(x.f(), 'A')
|
||||
self.assertEqual(x.__class__, 413)
|
||||
|
||||
|
||||
def test_main():
|
||||
support.run_unittest(TestSuper)
|
||||
|
|
|
@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #12370: Fix super with not arguments when __class__ is overriden in the
|
||||
class body.
|
||||
|
||||
- Issue #12084: os.stat on Windows now works properly with relative symbolic
|
||||
links when called from any directory.
|
||||
|
||||
|
|
|
@ -6399,7 +6399,7 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
|
||||
assert(PyUnicode_Check(name));
|
||||
if (!PyUnicode_CompareWithASCIIString(name,
|
||||
"__class__")) {
|
||||
"@__class__")) {
|
||||
Py_ssize_t index = co->co_nlocals +
|
||||
PyTuple_GET_SIZE(co->co_cellvars) + i;
|
||||
PyObject *cell = f->f_localsplus[index];
|
||||
|
|
|
@ -1566,7 +1566,7 @@ compiler_class(struct compiler *c, stmt_ty s)
|
|||
return 0;
|
||||
}
|
||||
/* return the (empty) __class__ cell */
|
||||
str = PyUnicode_InternFromString("__class__");
|
||||
str = PyUnicode_InternFromString("@__class__");
|
||||
if (str == NULL) {
|
||||
compiler_exit_scope(c);
|
||||
return 0;
|
||||
|
|
|
@ -225,10 +225,17 @@ symtable_new(void)
|
|||
struct symtable *
|
||||
PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future)
|
||||
{
|
||||
struct symtable *st = symtable_new();
|
||||
struct symtable *st;
|
||||
asdl_seq *seq;
|
||||
int i;
|
||||
|
||||
if (__class__ == NULL) {
|
||||
__class__ = PyUnicode_InternFromString("@__class__");
|
||||
if (__class__ == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
st = symtable_new();
|
||||
if (st == NULL)
|
||||
return st;
|
||||
st->st_filename = filename;
|
||||
|
@ -744,8 +751,6 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
|
|||
}
|
||||
else {
|
||||
/* Special-case __class__ */
|
||||
if (!GET_IDENTIFIER(__class__))
|
||||
goto error;
|
||||
assert(PySet_Contains(local, __class__) == 1);
|
||||
if (PySet_Add(newbound, __class__) < 0)
|
||||
goto error;
|
||||
|
@ -783,7 +788,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
|
|||
NULL))
|
||||
goto error;
|
||||
else if (ste->ste_type == ClassBlock && !analyze_cells(scopes, newfree,
|
||||
"__class__"))
|
||||
"@__class__"))
|
||||
goto error;
|
||||
/* Records the results of the analysis in the symbol table entry */
|
||||
if (!update_symbols(ste->ste_symbols, scopes, bound, newfree,
|
||||
|
@ -1143,8 +1148,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
|||
if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
|
||||
(void *)s, s->lineno, s->col_offset))
|
||||
return 0;
|
||||
if (!GET_IDENTIFIER(__class__) ||
|
||||
!symtable_add_def(st, __class__, DEF_LOCAL) ||
|
||||
if (!symtable_add_def(st, __class__, DEF_LOCAL) ||
|
||||
!GET_IDENTIFIER(__locals__) ||
|
||||
!symtable_add_def(st, __locals__, DEF_PARAM)) {
|
||||
symtable_exit_block(st, s);
|
||||
|
@ -1417,8 +1421,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
|
|||
if (e->v.Name.ctx == Load &&
|
||||
st->st_cur->ste_type == FunctionBlock &&
|
||||
!PyUnicode_CompareWithASCIIString(e->v.Name.id, "super")) {
|
||||
if (!GET_IDENTIFIER(__class__) ||
|
||||
!symtable_add_def(st, __class__, USE))
|
||||
if (!symtable_add_def(st, __class__, USE))
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue