1
#ifndef __GET_ATTR_STRING_H
2
#define __GET_ATTR_STRING_H
3

4
static NPY_INLINE npy_bool
5 1
_is_basic_python_type(PyTypeObject *tp)
6
{
7
    return (
8
        /* Basic number types */
9 1
        tp == &PyBool_Type ||
10 1
        tp == &PyLong_Type ||
11 1
        tp == &PyFloat_Type ||
12 1
        tp == &PyComplex_Type ||
13

14
        /* Basic sequence types */
15 1
        tp == &PyList_Type ||
16 1
        tp == &PyTuple_Type ||
17 1
        tp == &PyDict_Type ||
18 1
        tp == &PySet_Type ||
19 1
        tp == &PyFrozenSet_Type ||
20 1
        tp == &PyUnicode_Type ||
21 1
        tp == &PyBytes_Type ||
22

23
        /* other builtins */
24 1
        tp == &PySlice_Type ||
25 1
        tp == Py_TYPE(Py_None) ||
26 1
        tp == Py_TYPE(Py_Ellipsis) ||
27 1
        tp == Py_TYPE(Py_NotImplemented) ||
28

29
        /* TODO: ndarray, but we can't see PyArray_Type here */
30

31
        /* sentinel to swallow trailing || */
32
        NPY_FALSE
33
    );
34
}
35

36
/*
37
 * Stripped down version of PyObject_GetAttrString(obj, name) that does not
38
 * raise PyExc_AttributeError.
39
 *
40
 * This allows it to avoid creating then discarding exception objects when
41
 * performing lookups on objects without any attributes.
42
 *
43
 * Returns attribute value on success, NULL without an exception set if
44
 * there is no such attribute, and NULL with an exception on failure.
45
 */
46
static NPY_INLINE PyObject *
47 1
maybe_get_attr(PyObject *obj, char const *name)
48
{
49 1
    PyTypeObject *tp = Py_TYPE(obj);
50 1
    PyObject *res = (PyObject *)NULL;
51

52
    /* Attribute referenced by (char *)name */
53 1
    if (tp->tp_getattr != NULL) {
54 0
        res = (*tp->tp_getattr)(obj, (char *)name);
55 0
        if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
56 0
            PyErr_Clear();
57
        }
58
    }
59
    /* Attribute referenced by (PyObject *)name */
60 1
    else if (tp->tp_getattro != NULL) {
61 1
        PyObject *w = PyUnicode_InternFromString(name);
62 1
        if (w == NULL) {
63
            return (PyObject *)NULL;
64
        }
65 1
        res = (*tp->tp_getattro)(obj, w);
66 1
        Py_DECREF(w);
67 1
        if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
68 1
            PyErr_Clear();
69
        }
70
    }
71
    return res;
72
}
73

74
/*
75
 * Lookup a special method, following the python approach of looking up
76
 * on the type object, rather than on the instance itself.
77
 *
78
 * Assumes that the special method is a numpy-specific one, so does not look
79
 * at builtin types, nor does it look at a base ndarray.
80
 *
81
 * In future, could be made more like _Py_LookupSpecial
82
 */
83
static NPY_INLINE PyObject *
84 1
PyArray_LookupSpecial(PyObject *obj, char const *name)
85
{
86 1
    PyTypeObject *tp = Py_TYPE(obj);
87

88
    /* We do not need to check for special attributes on trivial types */
89 1
    if (_is_basic_python_type(tp)) {
90
        return NULL;
91
    }
92 1
    return maybe_get_attr((PyObject *)tp, name);
93
}
94

95
/*
96
 * PyArray_LookupSpecial_OnInstance:
97
 *
98
 * Implements incorrect special method lookup rules, that break the python
99
 * convention, and looks on the instance, not the type.
100
 *
101
 * Kept for backwards compatibility. In future, we should deprecate this.
102
 */
103
static NPY_INLINE PyObject *
104 1
PyArray_LookupSpecial_OnInstance(PyObject *obj, char const *name)
105
{
106 1
    PyTypeObject *tp = Py_TYPE(obj);
107

108
    /* We do not need to check for special attributes on trivial types */
109 1
    if (_is_basic_python_type(tp)) {
110
        return NULL;
111
    }
112

113 1
    return maybe_get_attr(obj, name);
114
}
115

116
#endif

Read our documentation on viewing source code .

Loading