It is a new name of former _PyObject_LookupAttr().
Add also PyObject_GetOptionalAttrString().
Exceptions that occur when this calls :meth:`~object.__getattr__` and
:meth:`~object.__getattribute__` methods are silently ignored.
- For proper error handling, use :c:func:`PyObject_GetAttr` instead.
+ For proper error handling, use :c:func:`PyObject_GetOptionalAttr` or
+ :c:func:`PyObject_GetAttr` instead.
.. c:function:: int PyObject_HasAttrString(PyObject *o, const char *attr_name)
Exceptions that occur when this calls :meth:`~object.__getattr__` and
:meth:`~object.__getattribute__` methods or while creating the temporary :class:`str`
object are silently ignored.
- For proper error handling, use :c:func:`PyObject_GetAttrString` instead.
+ For proper error handling, use :c:func:`PyObject_GetOptionalAttrString`
+ or :c:func:`PyObject_GetAttrString` instead.
.. c:function:: PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name)
value on success, or ``NULL`` on failure. This is the equivalent of the Python
expression ``o.attr_name``.
+ If the missing attribute should not be treated as a failure, you can use
+ :c:func:`PyObject_GetOptionalAttr` instead.
+
.. c:function:: PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name)
value on success, or ``NULL`` on failure. This is the equivalent of the Python
expression ``o.attr_name``.
+ If the missing attribute should not be treated as a failure, you can use
+ :c:func:`PyObject_GetOptionalAttrString` instead.
+
+
+.. c:function:: int PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result);
+
+ Variant of :c:func:`PyObject_GetAttr` which doesn't raise
+ :exc:`AttributeError` if the attribute is not found.
+
+ If the attribute is found, return ``1`` and set *\*result* to a new
+ :term:`strong reference` to the attribute.
+ If the attribute is not found, return ``0`` and set *\*result* to ``NULL``;
+ the :exc:`AttributeError` is silenced.
+ If an error other than :exc:`AttributeError` is raised, return ``-1`` and
+ set *\*result* to ``NULL``.
+
+ .. versionadded:: 3.13
+
+
+.. c:function:: int PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result);
+
+ Variant of :c:func:`PyObject_GetAttrString` which doesn't raise
+ :exc:`AttributeError` if the attribute is not found.
+
+ If the attribute is found, return ``1`` and set *\*result* to a new
+ :term:`strong reference` to the attribute.
+ If the attribute is not found, return ``0`` and set *\*result* to ``NULL``;
+ the :exc:`AttributeError` is silenced.
+ If an error other than :exc:`AttributeError` is raised, return ``-1`` and
+ set *\*result* to ``NULL``.
+
+ .. versionadded:: 3.13
.. c:function:: PyObject* PyObject_GenericGetAttr(PyObject *o, PyObject *name)
function,PyObject_GetBuffer,3.11,,
function,PyObject_GetItem,3.2,,
function,PyObject_GetIter,3.2,,
+function,PyObject_GetOptionalAttr,3.13,,
+function,PyObject_GetOptionalAttrString,3.13,,
function,PyObject_GetTypeData,3.12,,
function,PyObject_HasAttr,3.2,,
function,PyObject_HasAttrString,3.2,,
``NULL`` if the referent is no longer live.
(Contributed by Victor Stinner in :gh:`105927`.)
+* Add :c:func:`PyObject_GetOptionalAttr` and
+ :c:func:`PyObject_GetOptionalAttrString`, variants of
+ :c:func:`PyObject_GetAttr` and :c:func:`PyObject_GetAttrString` which
+ don't raise :exc:`AttributeError` if the attribute is not found.
+ These variants are more convenient and faster if the missing attribute
+ should not be treated as a failure.
+ (Contributed by Serhiy Storchaka in :gh:`106521`.)
+
* If Python is built in :ref:`debug mode <debug-build>` or :option:`with
assertions <--with-assertions>`, :c:func:`PyTuple_SET_ITEM` and
:c:func:`PyList_SET_ITEM` now check the index argument with an assertion.
This is the equivalent of the Python expression: o.attr_name. */
+/* Implemented elsewhere:
+
+ int PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result);
+
+ Variant of PyObject_GetAttr() which doesn't raise AttributeError
+ if the attribute is not found.
+
+ If the attribute is found, return 1 and set *result to a new strong
+ reference to the attribute.
+ If the attribute is not found, return 0 and set *result to NULL;
+ the AttributeError is silenced.
+ If an error other than AttributeError is raised, return -1 and
+ set *result to NULL.
+*/
+
+
+/* Implemented elsewhere:
+
+ int PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result);
+
+ Variant of PyObject_GetAttrString() which doesn't raise AttributeError
+ if the attribute is not found.
+
+ If the attribute is found, return 1 and set *result to a new strong
+ reference to the attribute.
+ If the attribute is not found, return 0 and set *result to NULL;
+ the AttributeError is silenced.
+ If an error other than AttributeError is raised, return -1 and
+ set *result to NULL.
+*/
+
+
/* Implemented elsewhere:
int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v);
PyAPI_FUNC(int) _PyObject_IsAbstract(PyObject *);
PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, _Py_Identifier *);
PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, _Py_Identifier *, PyObject *);
-/* Replacements of PyObject_GetAttr() and _PyObject_GetAttrId() which
- don't raise AttributeError.
-
- Return 1 and set *result != NULL if an attribute is found.
- Return 0 and set *result == NULL if an attribute is not found;
- an AttributeError is silenced.
- Return -1 and set *result == NULL if an error other than AttributeError
- is raised.
-*/
-PyAPI_FUNC(int) _PyObject_LookupAttr(PyObject *, PyObject *, PyObject **);
-PyAPI_FUNC(int) _PyObject_LookupAttrId(PyObject *, _Py_Identifier *, PyObject **);
+#define _PyObject_LookupAttr PyObject_GetOptionalAttr
PyAPI_FUNC(int) _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method);
PyAPI_FUNC(int) PyObject_DelAttrString(PyObject *v, const char *name);
PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *);
PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *);
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
+PyAPI_FUNC(int) PyObject_GetOptionalAttr(PyObject *, PyObject *, PyObject **);
+PyAPI_FUNC(int) PyObject_GetOptionalAttrString(PyObject *, const char *, PyObject **);
+#endif
PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
PyAPI_FUNC(int) PyObject_DelAttr(PyObject *v, PyObject *name);
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
"PyObject_GetBuffer",
"PyObject_GetItem",
"PyObject_GetIter",
+ "PyObject_GetOptionalAttr",
+ "PyObject_GetOptionalAttrString",
"PyObject_GetTypeData",
"PyObject_HasAttr",
"PyObject_HasAttrString",
--- /dev/null
+Add :c:func:`PyObject_GetOptionalAttr` and :c:func:`PyObject_GetOptionalAttrString` functions.
added = '3.13'
[function.PyObject_DelAttrString]
added = '3.13'
+[function.PyObject_GetOptionalAttr]
+ added = '3.13'
+[function.PyObject_GetOptionalAttrString]
+ added = '3.13'
{
assert(!PyErr_Occurred());
PyObject *qualname;
- int ret = _PyObject_LookupAttr(x, &_Py_ID(__qualname__), &qualname);
+ int ret = PyObject_GetOptionalAttr(x, &_Py_ID(__qualname__), &qualname);
if (qualname == NULL) {
if (ret < 0) {
return NULL;
}
PyObject *module;
PyObject *result = NULL;
- ret = _PyObject_LookupAttr(x, &_Py_ID(__module__), &module);
+ ret = PyObject_GetOptionalAttr(x, &_Py_ID(__module__), &module);
if (module != NULL && module != Py_None) {
ret = PyObject_RichCompareBool(module, &_Py_ID(builtins), Py_NE);
if (ret < 0) {
if (obj == NULL)
return 0;
- res = _PyObject_LookupAttr(obj, &_Py_ID(__isabstractmethod__), &isabstract);
+ res = PyObject_GetOptionalAttr(obj, &_Py_ID(__isabstractmethod__), &isabstract);
if (res > 0) {
res = PyObject_IsTrue(isabstract);
Py_DECREF(isabstract);
}
int
-_PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result)
+PyObject_GetOptionalAttr(PyObject *v, PyObject *name, PyObject **result)
{
PyTypeObject *tp = Py_TYPE(v);
}
int
-_PyObject_LookupAttrId(PyObject *v, _Py_Identifier *name, PyObject **result)
+PyObject_GetOptionalAttrString(PyObject *obj, const char *name, PyObject **result)
{
- PyObject *oname = _PyUnicode_FromId(name); /* borrowed */
- if (!oname) {
- *result = NULL;
+ if (Py_TYPE(obj)->tp_getattr == NULL) {
+ PyObject *oname = PyUnicode_FromString(name);
+ if (oname == NULL) {
+ *result = NULL;
+ return -1;
+ }
+ int rc = PyObject_GetOptionalAttr(obj, oname, result);
+ Py_DECREF(oname);
+ return rc;
+ }
+
+ *result = (*Py_TYPE(obj)->tp_getattr)(obj, (char*)name);
+ if (*result != NULL) {
+ return 1;
+ }
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
return -1;
}
- return _PyObject_LookupAttr(v, oname, result);
+ PyErr_Clear();
+ return 0;
}
int
PyObject_HasAttr(PyObject *v, PyObject *name)
{
PyObject *res;
- if (_PyObject_LookupAttr(v, name, &res) < 0) {
+ if (PyObject_GetOptionalAttr(v, name, &res) < 0) {
PyErr_Clear();
return 0;
}
EXPORT_FUNC(PyObject_GetBuffer)
EXPORT_FUNC(PyObject_GetItem)
EXPORT_FUNC(PyObject_GetIter)
+EXPORT_FUNC(PyObject_GetOptionalAttr)
+EXPORT_FUNC(PyObject_GetOptionalAttrString)
EXPORT_FUNC(PyObject_GetTypeData)
EXPORT_FUNC(PyObject_HasAttr)
EXPORT_FUNC(PyObject_HasAttrString)