Commit 4f29e752 authored by Eric Snow's avatar Eric Snow

Issue #24254: Drop cls.__definition_order__.

parent 7f730cf0
This diff is collapsed.
...@@ -53,19 +53,13 @@ Dynamic Type Creation ...@@ -53,19 +53,13 @@ Dynamic Type Creation
in *kwds* argument with any ``'metaclass'`` entry removed. If no *kwds* in *kwds* argument with any ``'metaclass'`` entry removed. If no *kwds*
argument is passed in, this will be an empty dict. argument is passed in, this will be an empty dict.
.. impl-detail::
CPython uses :class:`collections.OrderedDict` for the default
namespace.
.. versionadded:: 3.3 .. versionadded:: 3.3
.. versionchanged:: 3.6 .. versionchanged:: 3.6
The default value for the ``namespace`` element of the returned The default value for the ``namespace`` element of the returned
tuple has changed from :func:`dict`. Now an insertion-order- tuple has changed. Now an insertion-order-preserving mapping is
preserving mapping is used when the metaclass does not have a used when the metaclass does not have a ``__prepare__`` method,
``__prepare__`` method,
.. seealso:: .. seealso::
......
...@@ -634,15 +634,9 @@ dictionary. The class name is bound to this class object in the original local ...@@ -634,15 +634,9 @@ dictionary. The class name is bound to this class object in the original local
namespace. namespace.
The order in which attributes are defined in the class body is preserved The order in which attributes are defined in the class body is preserved
in the ``__definition_order__`` attribute on the new class. If that order in the new class's ``__dict__``. Note that this is reliable only right
is not known then the attribute is set to :const:`None`. The class body after the class is created and only for classes that were defined using
may include a ``__definition_order__`` attribute. In that case it is used the definition syntax.
directly. The value must be a tuple of identifiers or ``None``, otherwise
:exc:`TypeError` will be raised when the class statement is executed.
.. versionchanged:: 3.6
Add ``__definition_order__`` to classes.
Class creation can be customized heavily using :ref:`metaclasses <metaclasses>`. Class creation can be customized heavily using :ref:`metaclasses <metaclasses>`.
......
...@@ -1752,13 +1752,6 @@ additional keyword arguments, if any, come from the class definition). ...@@ -1752,13 +1752,6 @@ additional keyword arguments, if any, come from the class definition).
If the metaclass has no ``__prepare__`` attribute, then the class namespace If the metaclass has no ``__prepare__`` attribute, then the class namespace
is initialised as an empty ordered mapping. is initialised as an empty ordered mapping.
.. impl-detail::
In CPython the default is :class:`collections.OrderedDict`.
.. versionchanged:: 3.6
Defaults to :class:`collections.OrderedDict` instead of :func:`dict`.
.. seealso:: .. seealso::
:pep:`3115` - Metaclasses in Python 3000 :pep:`3115` - Metaclasses in Python 3000
......
...@@ -421,8 +421,6 @@ typedef struct _typeobject { ...@@ -421,8 +421,6 @@ typedef struct _typeobject {
destructor tp_finalize; destructor tp_finalize;
PyObject *tp_deforder;
#ifdef COUNT_ALLOCS #ifdef COUNT_ALLOCS
/* these must be last and never explicitly initialized */ /* these must be last and never explicitly initialized */
Py_ssize_t tp_allocs; Py_ssize_t tp_allocs;
......
...@@ -28,10 +28,6 @@ PyAPI_FUNC(PyObject *) PyODict_New(void); ...@@ -28,10 +28,6 @@ PyAPI_FUNC(PyObject *) PyODict_New(void);
PyAPI_FUNC(int) PyODict_SetItem(PyObject *od, PyObject *key, PyObject *item); PyAPI_FUNC(int) PyODict_SetItem(PyObject *od, PyObject *key, PyObject *item);
PyAPI_FUNC(int) PyODict_DelItem(PyObject *od, PyObject *key); PyAPI_FUNC(int) PyODict_DelItem(PyObject *od, PyObject *key);
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyODict_KeysAsTuple(PyObject *od);
#endif
/* wrappers around PyDict* functions */ /* wrappers around PyDict* functions */
#define PyODict_GetItem(od, key) PyDict_GetItem((PyObject *)od, key) #define PyODict_GetItem(od, key) PyDict_GetItem((PyObject *)od, key)
#define PyODict_GetItemWithError(od, key) \ #define PyODict_GetItemWithError(od, key) \
......
...@@ -16,10 +16,8 @@ import traceback ...@@ -16,10 +16,8 @@ import traceback
import types import types
import unittest import unittest
import warnings import warnings
from collections import OrderedDict
from operator import neg from operator import neg
from test.support import (TESTFN, unlink, run_unittest, check_warnings, from test.support import TESTFN, unlink, run_unittest, check_warnings
cpython_only)
from test.support.script_helper import assert_python_ok from test.support.script_helper import assert_python_ok
try: try:
import pty, signal import pty, signal
...@@ -1780,194 +1778,6 @@ class TestType(unittest.TestCase): ...@@ -1780,194 +1778,6 @@ class TestType(unittest.TestCase):
A.__doc__ = doc A.__doc__ = doc
self.assertEqual(A.__doc__, doc) self.assertEqual(A.__doc__, doc)
def test_type_definition_order_nonempty(self):
class Spam:
b = 1
c = 3
a = 2
d = 4
eggs = 2
e = 5
b = 42
self.assertEqual(Spam.__definition_order__,
('__module__', '__qualname__',
'b', 'c', 'a', 'd', 'eggs', 'e'))
def test_type_definition_order_empty(self):
class Empty:
pass
self.assertEqual(Empty.__definition_order__,
('__module__', '__qualname__'))
def test_type_definition_order_on_instance(self):
class Spam:
a = 2
b = 1
c = 3
with self.assertRaises(AttributeError):
Spam().__definition_order__
def test_type_definition_order_set_to_None(self):
class Spam:
a = 2
b = 1
c = 3
Spam.__definition_order__ = None
self.assertEqual(Spam.__definition_order__, None)
def test_type_definition_order_set_to_tuple(self):
class Spam:
a = 2
b = 1
c = 3
Spam.__definition_order__ = ('x', 'y', 'z')
self.assertEqual(Spam.__definition_order__, ('x', 'y', 'z'))
def test_type_definition_order_deleted(self):
class Spam:
a = 2
b = 1
c = 3
del Spam.__definition_order__
self.assertEqual(Spam.__definition_order__, None)
def test_type_definition_order_set_to_bad_type(self):
class Spam:
a = 2
b = 1
c = 3
Spam.__definition_order__ = 42
self.assertEqual(Spam.__definition_order__, 42)
def test_type_definition_order_builtins(self):
self.assertEqual(object.__definition_order__, None)
self.assertEqual(type.__definition_order__, None)
self.assertEqual(dict.__definition_order__, None)
self.assertEqual(type(None).__definition_order__, None)
def test_type_definition_order_dunder_names_included(self):
class Dunder:
VAR = 3
def __init__(self):
pass
self.assertEqual(Dunder.__definition_order__,
('__module__', '__qualname__',
'VAR', '__init__'))
def test_type_definition_order_only_dunder_names(self):
class DunderOnly:
__xyz__ = None
def __init__(self):
pass
self.assertEqual(DunderOnly.__definition_order__,
('__module__', '__qualname__',
'__xyz__', '__init__'))
def test_type_definition_order_underscore_names(self):
class HalfDunder:
__whether_to_be = True
or_not_to_be__ = False
self.assertEqual(HalfDunder.__definition_order__,
('__module__', '__qualname__',
'_HalfDunder__whether_to_be', 'or_not_to_be__'))
def test_type_definition_order_with_slots(self):
class Slots:
__slots__ = ('x', 'y')
a = 1
b = 2
self.assertEqual(Slots.__definition_order__,
('__module__', '__qualname__',
'__slots__', 'a', 'b'))
def test_type_definition_order_overwritten_None(self):
class OverwrittenNone:
__definition_order__ = None
a = 1
b = 2
c = 3
self.assertEqual(OverwrittenNone.__definition_order__, None)
def test_type_definition_order_overwritten_tuple(self):
class OverwrittenTuple:
__definition_order__ = ('x', 'y', 'z')
a = 1
b = 2
c = 3
self.assertEqual(OverwrittenTuple.__definition_order__,
('x', 'y', 'z'))
def test_type_definition_order_overwritten_bad_item(self):
with self.assertRaises(TypeError):
class PoorlyOverwritten:
__definition_order__ = ('a', 2, 'c')
a = 1
b = 2
c = 3
def test_type_definition_order_overwritten_bad_type(self):
with self.assertRaises(TypeError):
class PoorlyOverwritten:
__definition_order__ = ['a', 2, 'c']
a = 1
b = 2
c = 3
def test_type_definition_order_metaclass(self):
class Meta(type):
SPAM = 42
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.assertEqual(Meta.__definition_order__,
('__module__', '__qualname__',
'SPAM', '__init__'))
def test_type_definition_order_OrderedDict(self):
class Meta(type):
def __prepare__(self, *args, **kwargs):
return OrderedDict()
class WithODict(metaclass=Meta):
x='y'
self.assertEqual(WithODict.__definition_order__,
('__module__', '__qualname__', 'x'))
class Meta(type):
def __prepare__(self, *args, **kwargs):
class ODictSub(OrderedDict):
pass
return ODictSub()
class WithODictSub(metaclass=Meta):
x='y'
self.assertEqual(WithODictSub.__definition_order__,
('__module__', '__qualname__', 'x'))
@cpython_only
def test_type_definition_order_cpython(self):
# some implementations will have an ordered-by-default dict.
class Meta(type):
def __prepare__(self, *args, **kwargs):
return {}
class NotOrdered(metaclass=Meta):
x='y'
self.assertEqual(NotOrdered.__definition_order__, None)
def test_bad_args(self): def test_bad_args(self):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
type() type()
......
...@@ -180,7 +180,7 @@ Use a metaclass that doesn't derive from type. ...@@ -180,7 +180,7 @@ Use a metaclass that doesn't derive from type.
meta: C () meta: C ()
ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)] ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
kw: [] kw: []
>>> type(C) is types._DefaultClassNamespaceType >>> type(C) is dict
True True
>>> print(sorted(C.items())) >>> print(sorted(C.items()))
[('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)] [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
...@@ -211,11 +211,8 @@ And again, with a __prepare__ attribute. ...@@ -211,11 +211,8 @@ And again, with a __prepare__ attribute.
The default metaclass must define a __prepare__() method. The default metaclass must define a __prepare__() method.
>>> ns = type.__prepare__() >>> type.__prepare__()
>>> type(ns) is types._DefaultClassNamespaceType {}
True
>>> list(ns) == []
True
>>> >>>
Make sure it works with subclassing. Make sure it works with subclassing.
...@@ -251,9 +248,7 @@ Test failures in looking up the __prepare__ method work. ...@@ -251,9 +248,7 @@ Test failures in looking up the __prepare__ method work.
""" """
from collections import OrderedDict
import sys import sys
import types
# Trace function introduces __locals__ which causes various tests to fail. # Trace function introduces __locals__ which causes various tests to fail.
if hasattr(sys, 'gettrace') and sys.gettrace(): if hasattr(sys, 'gettrace') and sys.gettrace():
......
...@@ -427,7 +427,6 @@ class PydocDocTest(unittest.TestCase): ...@@ -427,7 +427,6 @@ class PydocDocTest(unittest.TestCase):
expected_html = expected_html_pattern % ( expected_html = expected_html_pattern % (
(mod_url, mod_file, doc_loc) + (mod_url, mod_file, doc_loc) +
expected_html_data_docstrings) expected_html_data_docstrings)
self.maxDiff = None
self.assertEqual(result, expected_html) self.assertEqual(result, expected_html)
@unittest.skipIf(sys.flags.optimize >= 2, @unittest.skipIf(sys.flags.optimize >= 2,
...@@ -474,18 +473,13 @@ class PydocDocTest(unittest.TestCase): ...@@ -474,18 +473,13 @@ class PydocDocTest(unittest.TestCase):
def test_non_str_name(self): def test_non_str_name(self):
# issue14638 # issue14638
# Treat illegal (non-str) name like no name # Treat illegal (non-str) name like no name
# Definition order is set to None so it looks the same in both
# cases.
class A: class A:
__definition_order__ = None
__name__ = 42 __name__ = 42
class B: class B:
pass pass
adoc = pydoc.render_doc(A()) adoc = pydoc.render_doc(A())
bdoc = pydoc.render_doc(B()) bdoc = pydoc.render_doc(B())
self.maxDiff = None self.assertEqual(adoc.replace("A", "B"), bdoc)
expected = adoc.replace("A", "B")
self.assertEqual(bdoc, expected)
def test_not_here(self): def test_not_here(self):
missing_module = "test.i_am_not_here" missing_module = "test.i_am_not_here"
......
...@@ -1085,7 +1085,7 @@ class SizeofTest(unittest.TestCase): ...@@ -1085,7 +1085,7 @@ class SizeofTest(unittest.TestCase):
check((1,2,3), vsize('') + 3*self.P) check((1,2,3), vsize('') + 3*self.P)
# type # type
# static type: PyTypeObject # static type: PyTypeObject
fmt = 'P2n15Pl4Pn9Pn11PIPP' fmt = 'P2n15Pl4Pn9Pn11PIP'
if hasattr(sys, 'getcounts'): if hasattr(sys, 'getcounts'):
fmt += '3n2P' fmt += '3n2P'
s = vsize(fmt) s = vsize(fmt)
......
...@@ -825,28 +825,6 @@ class ClassCreationTests(unittest.TestCase): ...@@ -825,28 +825,6 @@ class ClassCreationTests(unittest.TestCase):
self.assertEqual(C.y, 1) self.assertEqual(C.y, 1)
self.assertEqual(C.z, 2) self.assertEqual(C.z, 2)
def test_new_class_deforder(self):
C = types.new_class("C")
self.assertEqual(C.__definition_order__, tuple())
Meta = self.Meta
def func(ns):
ns["x"] = 0
D = types.new_class("D", (), {"metaclass": Meta, "z": 2}, func)
self.assertEqual(D.__definition_order__, ('y', 'z', 'x'))
def func(ns):
ns["__definition_order__"] = None
ns["x"] = 0
D = types.new_class("D", (), {"metaclass": Meta, "z": 2}, func)
self.assertEqual(D.__definition_order__, None)
def func(ns):
ns["__definition_order__"] = ('a', 'b', 'c')
ns["x"] = 0
D = types.new_class("D", (), {"metaclass": Meta, "z": 2}, func)
self.assertEqual(D.__definition_order__, ('a', 'b', 'c'))
# Many of the following tests are derived from test_descr.py # Many of the following tests are derived from test_descr.py
def test_prepare_class(self): def test_prepare_class(self):
# Basic test of metaclass derivation # Basic test of metaclass derivation
......
...@@ -25,11 +25,8 @@ CoroutineType = type(_c) ...@@ -25,11 +25,8 @@ CoroutineType = type(_c)
_c.close() # Prevent ResourceWarning _c.close() # Prevent ResourceWarning
class _C: class _C:
_nsType = type(locals())
def _m(self): pass def _m(self): pass
MethodType = type(_C()._m) MethodType = type(_C()._m)
# In CPython, this should end up as OrderedDict.
_DefaultClassNamespaceType = _C._nsType
BuiltinFunctionType = type(len) BuiltinFunctionType = type(len)
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
...@@ -88,7 +85,7 @@ def prepare_class(name, bases=(), kwds=None): ...@@ -88,7 +85,7 @@ def prepare_class(name, bases=(), kwds=None):
if hasattr(meta, '__prepare__'): if hasattr(meta, '__prepare__'):
ns = meta.__prepare__(name, bases, **kwds) ns = meta.__prepare__(name, bases, **kwds)
else: else:
ns = _DefaultClassNamespaceType() ns = {}
return meta, ns, kwds return meta, ns, kwds
def _calculate_meta(meta, bases): def _calculate_meta(meta, bases):
......
...@@ -1301,7 +1301,6 @@ class _ProtocolMeta(GenericMeta): ...@@ -1301,7 +1301,6 @@ class _ProtocolMeta(GenericMeta):
if (not attr.startswith('_abc_') and if (not attr.startswith('_abc_') and
attr != '__abstractmethods__' and attr != '__abstractmethods__' and
attr != '_is_protocol' and attr != '_is_protocol' and
attr != '__definition_order__' and
attr != '__dict__' and attr != '__dict__' and
attr != '__args__' and attr != '__args__' and
attr != '__slots__' and attr != '__slots__' and
......
...@@ -1765,21 +1765,6 @@ PyODict_DelItem(PyObject *od, PyObject *key) ...@@ -1765,21 +1765,6 @@ PyODict_DelItem(PyObject *od, PyObject *key)
return _PyDict_DelItem_KnownHash(od, key, hash); return _PyDict_DelItem_KnownHash(od, key, hash);
} }
PyObject *
_PyODict_KeysAsTuple(PyObject *od) {
Py_ssize_t i = 0;
_ODictNode *node;
PyObject *keys = PyTuple_New(PyODict_Size(od));
if (keys == NULL)
return NULL;
_odict_FOREACH((PyODictObject *)od, node) {
Py_INCREF(_odictnode_KEY(node));
PyTuple_SET_ITEM(keys, i, _odictnode_KEY(node));
i++;
}
return keys;
}
/* ------------------------------------------- /* -------------------------------------------
* The OrderedDict views (keys/values/items) * The OrderedDict views (keys/values/items)
......
...@@ -48,7 +48,6 @@ static size_t method_cache_collisions = 0; ...@@ -48,7 +48,6 @@ static size_t method_cache_collisions = 0;
_Py_IDENTIFIER(__abstractmethods__); _Py_IDENTIFIER(__abstractmethods__);
_Py_IDENTIFIER(__class__); _Py_IDENTIFIER(__class__);
_Py_IDENTIFIER(__delitem__); _Py_IDENTIFIER(__delitem__);
_Py_IDENTIFIER(__definition_order__);
_Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__dict__);
_Py_IDENTIFIER(__doc__); _Py_IDENTIFIER(__doc__);
_Py_IDENTIFIER(__getattribute__); _Py_IDENTIFIER(__getattribute__);
...@@ -489,23 +488,6 @@ type_set_module(PyTypeObject *type, PyObject *value, void *context) ...@@ -489,23 +488,6 @@ type_set_module(PyTypeObject *type, PyObject *value, void *context)
return _PyDict_SetItemId(type->tp_dict, &PyId___module__, value); return _PyDict_SetItemId(type->tp_dict, &PyId___module__, value);
} }
static PyObject *
type_deforder(PyTypeObject *type, void *context)
{
if (type->tp_deforder == NULL)
Py_RETURN_NONE;
Py_INCREF(type->tp_deforder);
return type->tp_deforder;
}
static int
type_set_deforder(PyTypeObject *type, PyObject *value, void *context)
{
Py_XINCREF(value);
Py_XSETREF(type->tp_deforder, value);
return 0;
}
static PyObject * static PyObject *
type_abstractmethods(PyTypeObject *type, void *context) type_abstractmethods(PyTypeObject *type, void *context)
{ {
...@@ -852,8 +834,6 @@ static PyGetSetDef type_getsets[] = { ...@@ -852,8 +834,6 @@ static PyGetSetDef type_getsets[] = {
{"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL}, {"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL},
{"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL},
{"__module__", (getter)type_module, (setter)type_set_module, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL},
{"__definition_order__", (getter)type_deforder,
(setter)type_set_deforder, NULL},
{"__abstractmethods__", (getter)type_abstractmethods, {"__abstractmethods__", (getter)type_abstractmethods,
(setter)type_set_abstractmethods, NULL}, (setter)type_set_abstractmethods, NULL},
{"__dict__", (getter)type_dict, NULL, NULL}, {"__dict__", (getter)type_dict, NULL, NULL},
...@@ -2371,7 +2351,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -2371,7 +2351,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
goto error; goto error;
} }
/* Copy the definition namespace into a new dict. */
dict = PyDict_Copy(orig_dict); dict = PyDict_Copy(orig_dict);
if (dict == NULL) if (dict == NULL)
goto error; goto error;
...@@ -2580,48 +2559,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -2580,48 +2559,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
if (qualname != NULL && PyDict_DelItem(dict, PyId___qualname__.object) < 0) if (qualname != NULL && PyDict_DelItem(dict, PyId___qualname__.object) < 0)
goto error; goto error;
/* Set tp_deforder to the extracted definition order, if any. */
type->tp_deforder = _PyDict_GetItemId(dict, &PyId___definition_order__);
if (type->tp_deforder != NULL) {
Py_INCREF(type->tp_deforder);
// Due to subclass lookup, __definition_order__ can't be in __dict__.
if (_PyDict_DelItemId(dict, &PyId___definition_order__) != 0) {
goto error;
}
if (type->tp_deforder != Py_None) {
Py_ssize_t numnames;
if (!PyTuple_Check(type->tp_deforder)) {
PyErr_SetString(PyExc_TypeError,
"__definition_order__ must be a tuple or None");
goto error;
}
// Make sure they are identifers.
numnames = PyTuple_Size(type->tp_deforder);
for (i = 0; i < numnames; i++) {
PyObject *name = PyTuple_GET_ITEM(type->tp_deforder, i);
if (name == NULL) {
goto error;
}
if (!PyUnicode_Check(name) || !PyUnicode_IsIdentifier(name)) {
PyErr_Format(PyExc_TypeError,
"__definition_order__ must "
"contain only identifiers, got '%s'",
name);
goto error;
}
}
}
}
else if (PyODict_Check(orig_dict)) {
type->tp_deforder = _PyODict_KeysAsTuple(orig_dict);
if (type->tp_deforder == NULL)
goto error;
}
/* Set tp_doc to a copy of dict['__doc__'], if the latter is there /* Set tp_doc to a copy of dict['__doc__'], if the latter is there
and is a string. The __doc__ accessor will first look for tp_doc; and is a string. The __doc__ accessor will first look for tp_doc;
if that fails, it will still look into __dict__. if that fails, it will still look into __dict__.
...@@ -3136,7 +3073,6 @@ type_dealloc(PyTypeObject *type) ...@@ -3136,7 +3073,6 @@ type_dealloc(PyTypeObject *type)
Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_mro);
Py_XDECREF(type->tp_cache); Py_XDECREF(type->tp_cache);
Py_XDECREF(type->tp_subclasses); Py_XDECREF(type->tp_subclasses);
Py_XDECREF(type->tp_deforder);
/* A type's tp_doc is heap allocated, unlike the tp_doc slots /* A type's tp_doc is heap allocated, unlike the tp_doc slots
* of most other objects. It's okay to cast it to char *. * of most other objects. It's okay to cast it to char *.
*/ */
...@@ -3179,7 +3115,7 @@ type_subclasses(PyTypeObject *type, PyObject *args_ignored) ...@@ -3179,7 +3115,7 @@ type_subclasses(PyTypeObject *type, PyObject *args_ignored)
static PyObject * static PyObject *
type_prepare(PyObject *self, PyObject *args, PyObject *kwds) type_prepare(PyObject *self, PyObject *args, PyObject *kwds)
{ {
return PyODict_New(); return PyDict_New();
} }
/* /*
......
...@@ -147,7 +147,7 @@ builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -147,7 +147,7 @@ builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds)
if (prep == NULL) { if (prep == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError)) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear(); PyErr_Clear();
ns = PyODict_New(); ns = PyDict_New();
} }
else { else {
Py_DECREF(meta); Py_DECREF(meta);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment