summaryrefslogtreecommitdiffstats
path: root/Objects/descrobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/descrobject.c')
-rw-r--r--Objects/descrobject.c272
1 files changed, 209 insertions, 63 deletions
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 9934f23..abcc002 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -9,6 +9,7 @@ descr_dealloc(PyDescrObject *descr)
_PyObject_GC_UNTRACK(descr);
Py_XDECREF(descr->d_type);
Py_XDECREF(descr->d_name);
+ Py_XDECREF(descr->d_qualname);
PyObject_GC_Del(descr);
}
@@ -359,6 +360,44 @@ method_get_doc(PyMethodDescrObject *descr, void *closure)
return PyUnicode_FromString(descr->d_method->ml_doc);
}
+static PyObject *
+calculate_qualname(PyDescrObject *descr)
+{
+ PyObject *type_qualname, *res;
+ _Py_IDENTIFIER(__qualname__);
+
+ if (descr->d_name == NULL || !PyUnicode_Check(descr->d_name)) {
+ PyErr_SetString(PyExc_TypeError,
+ "<descriptor>.__name__ is not a unicode object");
+ return NULL;
+ }
+
+ type_qualname = _PyObject_GetAttrId((PyObject *)descr->d_type,
+ &PyId___qualname__);
+ if (type_qualname == NULL)
+ return NULL;
+
+ if (!PyUnicode_Check(type_qualname)) {
+ PyErr_SetString(PyExc_TypeError, "<descriptor>.__objclass__."
+ "__qualname__ is not a unicode object");
+ Py_XDECREF(type_qualname);
+ return NULL;
+ }
+
+ res = PyUnicode_FromFormat("%S.%S", type_qualname, descr->d_name);
+ Py_DECREF(type_qualname);
+ return res;
+}
+
+static PyObject *
+descr_get_qualname(PyDescrObject *descr)
+{
+ if (descr->d_qualname == NULL)
+ descr->d_qualname = calculate_qualname(descr);
+ Py_XINCREF(descr->d_qualname);
+ return descr->d_qualname;
+}
+
static PyMemberDef descr_members[] = {
{"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
{"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
@@ -367,6 +406,7 @@ static PyMemberDef descr_members[] = {
static PyGetSetDef method_getset[] = {
{"__doc__", (getter)method_get_doc},
+ {"__qualname__", (getter)descr_get_qualname},
{0}
};
@@ -382,6 +422,7 @@ member_get_doc(PyMemberDescrObject *descr, void *closure)
static PyGetSetDef member_getset[] = {
{"__doc__", (getter)member_get_doc},
+ {"__qualname__", (getter)descr_get_qualname},
{0}
};
@@ -397,6 +438,7 @@ getset_get_doc(PyGetSetDescrObject *descr, void *closure)
static PyGetSetDef getset_getset[] = {
{"__doc__", (getter)getset_get_doc},
+ {"__qualname__", (getter)descr_get_qualname},
{0}
};
@@ -412,6 +454,7 @@ wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure)
static PyGetSetDef wrapperdescr_getset[] = {
{"__doc__", (getter)wrapperdescr_get_doc},
+ {"__qualname__", (getter)descr_get_qualname},
{0}
};
@@ -623,6 +666,9 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
Py_DECREF(descr);
descr = NULL;
}
+ else {
+ descr->d_qualname = NULL;
+ }
}
return descr;
}
@@ -690,41 +736,44 @@ PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
}
-/* --- Readonly proxy for dictionaries (actually any mapping) --- */
+/* --- mappingproxy: read-only proxy for mappings --- */
/* This has no reason to be in this file except that adding new files is a
bit of a pain */
typedef struct {
PyObject_HEAD
- PyObject *dict;
-} proxyobject;
+ PyObject *mapping;
+} mappingproxyobject;
static Py_ssize_t
-proxy_len(proxyobject *pp)
+mappingproxy_len(mappingproxyobject *pp)
{
- return PyObject_Size(pp->dict);
+ return PyObject_Size(pp->mapping);
}
static PyObject *
-proxy_getitem(proxyobject *pp, PyObject *key)
+mappingproxy_getitem(mappingproxyobject *pp, PyObject *key)
{
- return PyObject_GetItem(pp->dict, key);
+ return PyObject_GetItem(pp->mapping, key);
}
-static PyMappingMethods proxy_as_mapping = {
- (lenfunc)proxy_len, /* mp_length */
- (binaryfunc)proxy_getitem, /* mp_subscript */
+static PyMappingMethods mappingproxy_as_mapping = {
+ (lenfunc)mappingproxy_len, /* mp_length */
+ (binaryfunc)mappingproxy_getitem, /* mp_subscript */
0, /* mp_ass_subscript */
};
static int
-proxy_contains(proxyobject *pp, PyObject *key)
+mappingproxy_contains(mappingproxyobject *pp, PyObject *key)
{
- return PyDict_Contains(pp->dict, key);
+ if (PyDict_CheckExact(pp->mapping))
+ return PyDict_Contains(pp->mapping, key);
+ else
+ return PySequence_Contains(pp->mapping, key);
}
-static PySequenceMethods proxy_as_sequence = {
+static PySequenceMethods mappingproxy_as_sequence = {
0, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
@@ -732,147 +781,199 @@ static PySequenceMethods proxy_as_sequence = {
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
- (objobjproc)proxy_contains, /* sq_contains */
+ (objobjproc)mappingproxy_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};
static PyObject *
-proxy_get(proxyobject *pp, PyObject *args)
+mappingproxy_get(mappingproxyobject *pp, PyObject *args)
{
PyObject *key, *def = Py_None;
+ _Py_IDENTIFIER(get);
if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))
return NULL;
- return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_get, "(OO)", key, def);
}
static PyObject *
-proxy_keys(proxyobject *pp)
+mappingproxy_keys(mappingproxyobject *pp)
{
- return PyObject_CallMethod(pp->dict, "keys", NULL);
+ _Py_IDENTIFIER(keys);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_keys, NULL);
}
static PyObject *
-proxy_values(proxyobject *pp)
+mappingproxy_values(mappingproxyobject *pp)
{
- return PyObject_CallMethod(pp->dict, "values", NULL);
+ _Py_IDENTIFIER(values);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_values, NULL);
}
static PyObject *
-proxy_items(proxyobject *pp)
+mappingproxy_items(mappingproxyobject *pp)
{
- return PyObject_CallMethod(pp->dict, "items", NULL);
+ _Py_IDENTIFIER(items);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_items, NULL);
}
static PyObject *
-proxy_copy(proxyobject *pp)
+mappingproxy_copy(mappingproxyobject *pp)
{
- return PyObject_CallMethod(pp->dict, "copy", NULL);
+ _Py_IDENTIFIER(copy);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_copy, NULL);
}
-static PyMethodDef proxy_methods[] = {
- {"get", (PyCFunction)proxy_get, METH_VARARGS,
+/* WARNING: mappingproxy methods must not give access
+ to the underlying mapping */
+
+static PyMethodDef mappingproxy_methods[] = {
+ {"get", (PyCFunction)mappingproxy_get, METH_VARARGS,
PyDoc_STR("D.get(k[,d]) -> D[k] if k in D, else d."
- " d defaults to None.")},
- {"keys", (PyCFunction)proxy_keys, METH_NOARGS,
+ " d defaults to None.")},
+ {"keys", (PyCFunction)mappingproxy_keys, METH_NOARGS,
PyDoc_STR("D.keys() -> list of D's keys")},
- {"values", (PyCFunction)proxy_values, METH_NOARGS,
+ {"values", (PyCFunction)mappingproxy_values, METH_NOARGS,
PyDoc_STR("D.values() -> list of D's values")},
- {"items", (PyCFunction)proxy_items, METH_NOARGS,
+ {"items", (PyCFunction)mappingproxy_items, METH_NOARGS,
PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
- {"copy", (PyCFunction)proxy_copy, METH_NOARGS,
+ {"copy", (PyCFunction)mappingproxy_copy, METH_NOARGS,
PyDoc_STR("D.copy() -> a shallow copy of D")},
{0}
};
static void
-proxy_dealloc(proxyobject *pp)
+mappingproxy_dealloc(mappingproxyobject *pp)
{
_PyObject_GC_UNTRACK(pp);
- Py_DECREF(pp->dict);
+ Py_DECREF(pp->mapping);
PyObject_GC_Del(pp);
}
static PyObject *
-proxy_getiter(proxyobject *pp)
+mappingproxy_getiter(mappingproxyobject *pp)
{
- return PyObject_GetIter(pp->dict);
+ return PyObject_GetIter(pp->mapping);
}
static PyObject *
-proxy_str(proxyobject *pp)
+mappingproxy_str(mappingproxyobject *pp)
{
- return PyObject_Str(pp->dict);
+ return PyObject_Str(pp->mapping);
}
static PyObject *
-proxy_repr(proxyobject *pp)
+mappingproxy_repr(mappingproxyobject *pp)
{
- return PyUnicode_FromFormat("dict_proxy(%R)", pp->dict);
+ return PyUnicode_FromFormat("mappingproxy(%R)", pp->mapping);
}
static int
-proxy_traverse(PyObject *self, visitproc visit, void *arg)
+mappingproxy_traverse(PyObject *self, visitproc visit, void *arg)
{
- proxyobject *pp = (proxyobject *)self;
- Py_VISIT(pp->dict);
+ mappingproxyobject *pp = (mappingproxyobject *)self;
+ Py_VISIT(pp->mapping);
return 0;
}
static PyObject *
-proxy_richcompare(proxyobject *v, PyObject *w, int op)
+mappingproxy_richcompare(mappingproxyobject *v, PyObject *w, int op)
+{
+ return PyObject_RichCompare(v->mapping, w, op);
+}
+
+static int
+mappingproxy_check_mapping(PyObject *mapping)
{
- return PyObject_RichCompare(v->dict, w, op);
+ if (!PyMapping_Check(mapping)
+ || PyList_Check(mapping)
+ || PyTuple_Check(mapping)) {
+ PyErr_Format(PyExc_TypeError,
+ "mappingproxy() argument must be a mapping, not %s",
+ Py_TYPE(mapping)->tp_name);
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject*
+mappingproxy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"mapping", NULL};
+ PyObject *mapping;
+ mappingproxyobject *mappingproxy;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:mappingproxy",
+ kwlist, &mapping))
+ return NULL;
+
+ if (mappingproxy_check_mapping(mapping) == -1)
+ return NULL;
+
+ mappingproxy = PyObject_GC_New(mappingproxyobject, &PyDictProxy_Type);
+ if (mappingproxy == NULL)
+ return NULL;
+ Py_INCREF(mapping);
+ mappingproxy->mapping = mapping;
+ _PyObject_GC_TRACK(mappingproxy);
+ return (PyObject *)mappingproxy;
}
PyTypeObject PyDictProxy_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_proxy", /* tp_name */
- sizeof(proxyobject), /* tp_basicsize */
+ "mappingproxy", /* tp_name */
+ sizeof(mappingproxyobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- (destructor)proxy_dealloc, /* tp_dealloc */
+ (destructor)mappingproxy_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
- (reprfunc)proxy_repr, /* tp_repr */
+ (reprfunc)mappingproxy_repr, /* tp_repr */
0, /* tp_as_number */
- &proxy_as_sequence, /* tp_as_sequence */
- &proxy_as_mapping, /* tp_as_mapping */
+ &mappingproxy_as_sequence, /* tp_as_sequence */
+ &mappingproxy_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
- (reprfunc)proxy_str, /* tp_str */
+ (reprfunc)mappingproxy_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
- proxy_traverse, /* tp_traverse */
+ mappingproxy_traverse, /* tp_traverse */
0, /* tp_clear */
- (richcmpfunc)proxy_richcompare, /* tp_richcompare */
+ (richcmpfunc)mappingproxy_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
- (getiterfunc)proxy_getiter, /* tp_iter */
+ (getiterfunc)mappingproxy_getiter, /* tp_iter */
0, /* tp_iternext */
- proxy_methods, /* tp_methods */
+ mappingproxy_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ mappingproxy_new, /* tp_new */
};
PyObject *
-PyDictProxy_New(PyObject *dict)
+PyDictProxy_New(PyObject *mapping)
{
- proxyobject *pp;
+ mappingproxyobject *pp;
+
+ if (mappingproxy_check_mapping(mapping) == -1)
+ return NULL;
- pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type);
+ pp = PyObject_GC_New(mappingproxyobject, &PyDictProxy_Type);
if (pp != NULL) {
- Py_INCREF(dict);
- pp->dict = dict;
+ Py_INCREF(mapping);
+ pp->mapping = mapping;
_PyObject_GC_TRACK(pp);
}
return (PyObject *)pp;
@@ -1020,9 +1121,16 @@ wrapper_doc(wrapperobject *wp)
}
}
+static PyObject *
+wrapper_qualname(wrapperobject *wp)
+{
+ return descr_get_qualname((PyDescrObject *)wp->descr);
+}
+
static PyGetSetDef wrapper_getsets[] = {
{"__objclass__", (getter)wrapper_objclass},
{"__name__", (getter)wrapper_name},
+ {"__qualname__", (getter)wrapper_qualname},
{"__doc__", (getter)wrapper_doc},
{0}
};
@@ -1332,7 +1440,8 @@ property_init(PyObject *self, PyObject *args, PyObject *kwds)
/* if no docstring given and the getter has one, use that one */
if ((doc == NULL || doc == Py_None) && get != NULL) {
- PyObject *get_doc = PyObject_GetAttrString(get, "__doc__");
+ _Py_IDENTIFIER(__doc__);
+ PyObject *get_doc = _PyObject_GetAttrId(get, &PyId___doc__);
if (get_doc) {
if (Py_TYPE(self) == &PyProperty_Type) {
Py_XDECREF(prop->prop_doc);
@@ -1343,7 +1452,7 @@ property_init(PyObject *self, PyObject *args, PyObject *kwds)
in dict of the subclass instance instead,
otherwise it gets shadowed by __doc__ in the
class's dict. */
- int err = PyObject_SetAttrString(self, "__doc__", get_doc);
+ int err = _PyObject_SetAttrId(self, &PyId___doc__, get_doc);
Py_DECREF(get_doc);
if (err < 0)
return -1;
@@ -1361,6 +1470,43 @@ property_init(PyObject *self, PyObject *args, PyObject *kwds)
return 0;
}
+static PyObject *
+property_get___isabstractmethod__(propertyobject *prop, void *closure)
+{
+ int res = _PyObject_IsAbstract(prop->prop_get);
+ if (res == -1) {
+ return NULL;
+ }
+ else if (res) {
+ Py_RETURN_TRUE;
+ }
+
+ res = _PyObject_IsAbstract(prop->prop_set);
+ if (res == -1) {
+ return NULL;
+ }
+ else if (res) {
+ Py_RETURN_TRUE;
+ }
+
+ res = _PyObject_IsAbstract(prop->prop_del);
+ if (res == -1) {
+ return NULL;
+ }
+ else if (res) {
+ Py_RETURN_TRUE;
+ }
+ Py_RETURN_FALSE;
+}
+
+static PyGetSetDef property_getsetlist[] = {
+ {"__isabstractmethod__",
+ (getter)property_get___isabstractmethod__, NULL,
+ NULL,
+ NULL},
+ {NULL} /* Sentinel */
+};
+
PyDoc_STRVAR(property_doc,
"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
"\n"
@@ -1426,7 +1572,7 @@ PyTypeObject PyProperty_Type = {
0, /* tp_iternext */
property_methods, /* tp_methods */
property_members, /* tp_members */
- 0, /* tp_getset */
+ property_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
property_descr_get, /* tp_descr_get */