Close #14857: fix regression in references to PEP 3135 implicit __class__ closure variable. Reopens issue #12370, but also updates unittest.mock to workaround that issue
This commit is contained in:
parent
5c6eba3a93
commit
0b43bcf528
@ -81,6 +81,7 @@ class TestSuper(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(E().f(), 'AE')
|
self.assertEqual(E().f(), 'AE')
|
||||||
|
|
||||||
|
@unittest.expectedFailure
|
||||||
def test___class___set(self):
|
def test___class___set(self):
|
||||||
# See issue #12370
|
# See issue #12370
|
||||||
class X(A):
|
class X(A):
|
||||||
@ -91,6 +92,29 @@ class TestSuper(unittest.TestCase):
|
|||||||
self.assertEqual(x.f(), 'A')
|
self.assertEqual(x.f(), 'A')
|
||||||
self.assertEqual(x.__class__, 413)
|
self.assertEqual(x.__class__, 413)
|
||||||
|
|
||||||
|
def test___class___instancemethod(self):
|
||||||
|
# See issue #14857
|
||||||
|
class X:
|
||||||
|
def f(self):
|
||||||
|
return __class__
|
||||||
|
self.assertIs(X().f(), X)
|
||||||
|
|
||||||
|
def test___class___classmethod(self):
|
||||||
|
# See issue #14857
|
||||||
|
class X:
|
||||||
|
@classmethod
|
||||||
|
def f(cls):
|
||||||
|
return __class__
|
||||||
|
self.assertIs(X.f(), X)
|
||||||
|
|
||||||
|
def test___class___staticmethod(self):
|
||||||
|
# See issue #14857
|
||||||
|
class X:
|
||||||
|
@staticmethod
|
||||||
|
def f():
|
||||||
|
return __class__
|
||||||
|
self.assertIs(X.f(), X)
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(TestSuper)
|
support.run_unittest(TestSuper)
|
||||||
|
@ -39,6 +39,9 @@ if 'java' in sys.platform:
|
|||||||
|
|
||||||
FILTER_DIR = True
|
FILTER_DIR = True
|
||||||
|
|
||||||
|
# Workaround for issue #12370
|
||||||
|
# Without this, the __class__ properties wouldn't be set correctly
|
||||||
|
_safe_super = super
|
||||||
|
|
||||||
def _is_instance_mock(obj):
|
def _is_instance_mock(obj):
|
||||||
# can't use isinstance on Mock objects because they override __class__
|
# can't use isinstance on Mock objects because they override __class__
|
||||||
@ -397,7 +400,7 @@ class NonCallableMock(Base):
|
|||||||
if kwargs:
|
if kwargs:
|
||||||
self.configure_mock(**kwargs)
|
self.configure_mock(**kwargs)
|
||||||
|
|
||||||
super(NonCallableMock, self).__init__(
|
_safe_super(NonCallableMock, self).__init__(
|
||||||
spec, wraps, name, spec_set, parent,
|
spec, wraps, name, spec_set, parent,
|
||||||
_spec_state
|
_spec_state
|
||||||
)
|
)
|
||||||
@ -820,7 +823,7 @@ class CallableMixin(Base):
|
|||||||
_spec_state=None, _new_name='', _new_parent=None, **kwargs):
|
_spec_state=None, _new_name='', _new_parent=None, **kwargs):
|
||||||
self.__dict__['_mock_return_value'] = return_value
|
self.__dict__['_mock_return_value'] = return_value
|
||||||
|
|
||||||
super(CallableMixin, self).__init__(
|
_safe_super(CallableMixin, self).__init__(
|
||||||
spec, wraps, name, spec_set, parent,
|
spec, wraps, name, spec_set, parent,
|
||||||
_spec_state, _new_name, _new_parent, **kwargs
|
_spec_state, _new_name, _new_parent, **kwargs
|
||||||
)
|
)
|
||||||
@ -1690,7 +1693,7 @@ def _set_return_value(mock, method, name):
|
|||||||
|
|
||||||
class MagicMixin(object):
|
class MagicMixin(object):
|
||||||
def __init__(self, *args, **kw):
|
def __init__(self, *args, **kw):
|
||||||
super(MagicMixin, self).__init__(*args, **kw)
|
_safe_super(MagicMixin, self).__init__(*args, **kw)
|
||||||
self._mock_set_magics()
|
self._mock_set_magics()
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ What's New in Python 3.3.0 Alpha 4?
|
|||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #14857: fix regression in references to PEP 3135 implicit __class__
|
||||||
|
closure variable (Reopens issue #12370)
|
||||||
|
|
||||||
- Issue #14712 (PEP 405): Virtual environments. Implemented by Vinay Sajip.
|
- Issue #14712 (PEP 405): Virtual environments. Implemented by Vinay Sajip.
|
||||||
|
|
||||||
- Issue #14660 (PEP 420): Namespace packages. Implemented by Eric Smith.
|
- Issue #14660 (PEP 420): Namespace packages. Implemented by Eric Smith.
|
||||||
|
@ -6436,7 +6436,7 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|||||||
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
|
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
|
||||||
assert(PyUnicode_Check(name));
|
assert(PyUnicode_Check(name));
|
||||||
if (!PyUnicode_CompareWithASCIIString(name,
|
if (!PyUnicode_CompareWithASCIIString(name,
|
||||||
"@__class__")) {
|
"__class__")) {
|
||||||
Py_ssize_t index = co->co_nlocals +
|
Py_ssize_t index = co->co_nlocals +
|
||||||
PyTuple_GET_SIZE(co->co_cellvars) + i;
|
PyTuple_GET_SIZE(co->co_cellvars) + i;
|
||||||
PyObject *cell = f->f_localsplus[index];
|
PyObject *cell = f->f_localsplus[index];
|
||||||
|
@ -1676,7 +1676,7 @@ compiler_class(struct compiler *c, stmt_ty s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* return the (empty) __class__ cell */
|
/* return the (empty) __class__ cell */
|
||||||
str = PyUnicode_InternFromString("@__class__");
|
str = PyUnicode_InternFromString("__class__");
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
compiler_exit_scope(c);
|
compiler_exit_scope(c);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -106,6 +106,7 @@ typedef unsigned short mode_t;
|
|||||||
Python 3.3a0 3200 (__qualname__ added)
|
Python 3.3a0 3200 (__qualname__ added)
|
||||||
3210 (added size modulo 2**32 to the pyc header)
|
3210 (added size modulo 2**32 to the pyc header)
|
||||||
Python 3.3a1 3220 (changed PEP 380 implementation)
|
Python 3.3a1 3220 (changed PEP 380 implementation)
|
||||||
|
Python 3.3a4 3230 (revert changes to implicit __class__ closure)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* MAGIC must change whenever the bytecode emitted by the compiler may no
|
/* MAGIC must change whenever the bytecode emitted by the compiler may no
|
||||||
@ -118,7 +119,7 @@ typedef unsigned short mode_t;
|
|||||||
#define STRIFY(name) QUOTE(name)
|
#define STRIFY(name) QUOTE(name)
|
||||||
#define MAJOR STRIFY(PY_MAJOR_VERSION)
|
#define MAJOR STRIFY(PY_MAJOR_VERSION)
|
||||||
#define MINOR STRIFY(PY_MINOR_VERSION)
|
#define MINOR STRIFY(PY_MINOR_VERSION)
|
||||||
#define MAGIC (3220 | ((long)'\r'<<16) | ((long)'\n'<<24))
|
#define MAGIC (3230 | ((long)'\r'<<16) | ((long)'\n'<<24))
|
||||||
#define TAG "cpython-" MAJOR MINOR;
|
#define TAG "cpython-" MAJOR MINOR;
|
||||||
#define CACHEDIR "__pycache__"
|
#define CACHEDIR "__pycache__"
|
||||||
/* Current magic word and string tag as globals. */
|
/* Current magic word and string tag as globals. */
|
||||||
|
@ -221,17 +221,10 @@ symtable_new(void)
|
|||||||
struct symtable *
|
struct symtable *
|
||||||
PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future)
|
PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future)
|
||||||
{
|
{
|
||||||
struct symtable *st;
|
struct symtable *st = symtable_new();
|
||||||
asdl_seq *seq;
|
asdl_seq *seq;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (__class__ == NULL) {
|
|
||||||
__class__ = PyUnicode_InternFromString("@__class__");
|
|
||||||
if (__class__ == NULL)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
st = symtable_new();
|
|
||||||
if (st == NULL)
|
if (st == NULL)
|
||||||
return st;
|
return st;
|
||||||
st->st_filename = filename;
|
st->st_filename = filename;
|
||||||
@ -747,6 +740,8 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Special-case __class__ */
|
/* Special-case __class__ */
|
||||||
|
if (!GET_IDENTIFIER(__class__))
|
||||||
|
goto error;
|
||||||
assert(PySet_Contains(local, __class__) == 1);
|
assert(PySet_Contains(local, __class__) == 1);
|
||||||
if (PySet_Add(newbound, __class__) < 0)
|
if (PySet_Add(newbound, __class__) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
@ -784,7 +779,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
|
|||||||
NULL))
|
NULL))
|
||||||
goto error;
|
goto error;
|
||||||
else if (ste->ste_type == ClassBlock && !analyze_cells(scopes, newfree,
|
else if (ste->ste_type == ClassBlock && !analyze_cells(scopes, newfree,
|
||||||
"@__class__"))
|
"__class__"))
|
||||||
goto error;
|
goto error;
|
||||||
/* Records the results of the analysis in the symbol table entry */
|
/* Records the results of the analysis in the symbol table entry */
|
||||||
if (!update_symbols(ste->ste_symbols, scopes, bound, newfree,
|
if (!update_symbols(ste->ste_symbols, scopes, bound, newfree,
|
||||||
@ -1111,7 +1106,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
|||||||
if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
|
if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
|
||||||
(void *)s, s->lineno, s->col_offset))
|
(void *)s, s->lineno, s->col_offset))
|
||||||
return 0;
|
return 0;
|
||||||
if (!symtable_add_def(st, __class__, DEF_LOCAL) ||
|
if (!GET_IDENTIFIER(__class__) ||
|
||||||
|
!symtable_add_def(st, __class__, DEF_LOCAL) ||
|
||||||
!GET_IDENTIFIER(__locals__) ||
|
!GET_IDENTIFIER(__locals__) ||
|
||||||
!symtable_add_def(st, __locals__, DEF_PARAM)) {
|
!symtable_add_def(st, __locals__, DEF_PARAM)) {
|
||||||
symtable_exit_block(st, s);
|
symtable_exit_block(st, s);
|
||||||
@ -1376,7 +1372,8 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
|
|||||||
if (e->v.Name.ctx == Load &&
|
if (e->v.Name.ctx == Load &&
|
||||||
st->st_cur->ste_type == FunctionBlock &&
|
st->st_cur->ste_type == FunctionBlock &&
|
||||||
!PyUnicode_CompareWithASCIIString(e->v.Name.id, "super")) {
|
!PyUnicode_CompareWithASCIIString(e->v.Name.id, "super")) {
|
||||||
if (!symtable_add_def(st, __class__, USE))
|
if (!GET_IDENTIFIER(__class__) ||
|
||||||
|
!symtable_add_def(st, __class__, USE))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user