mirror of https://github.com/python/cpython
gh-106521: Add PyObject_GetOptionalAttr() function (GH-106522)
It is a new name of former _PyObject_LookupAttr(). Add also PyObject_GetOptionalAttrString().
This commit is contained in:
parent
cabd6e8a10
commit
579aa89e68
|
@ -37,7 +37,8 @@ Object Protocol
|
|||
|
||||
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)
|
||||
|
@ -51,7 +52,8 @@ Object Protocol
|
|||
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)
|
||||
|
@ -60,6 +62,9 @@ Object Protocol
|
|||
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)
|
||||
|
||||
|
@ -67,6 +72,38 @@ Object Protocol
|
|||
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)
|
||||
|
||||
|
|
|
@ -512,6 +512,8 @@ function,PyObject_GetAttrString,3.2,,
|
|||
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,,
|
||||
|
|
|
@ -734,6 +734,14 @@ New Features
|
|||
``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.
|
||||
|
|
|
@ -60,6 +60,38 @@ extern "C" {
|
|||
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);
|
||||
|
|
|
@ -294,17 +294,7 @@ PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *);
|
|||
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);
|
||||
|
||||
|
|
|
@ -394,6 +394,10 @@ PyAPI_FUNC(int) PyObject_SetAttrString(PyObject *, const char *, PyObject *);
|
|||
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 *);
|
||||
|
|
|
@ -531,6 +531,8 @@ SYMBOL_NAMES = (
|
|||
"PyObject_GetBuffer",
|
||||
"PyObject_GetItem",
|
||||
"PyObject_GetIter",
|
||||
"PyObject_GetOptionalAttr",
|
||||
"PyObject_GetOptionalAttrString",
|
||||
"PyObject_GetTypeData",
|
||||
"PyObject_HasAttr",
|
||||
"PyObject_HasAttrString",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Add :c:func:`PyObject_GetOptionalAttr` and :c:func:`PyObject_GetOptionalAttrString` functions.
|
|
@ -2436,3 +2436,7 @@
|
|||
added = '3.13'
|
||||
[function.PyObject_DelAttrString]
|
||||
added = '3.13'
|
||||
[function.PyObject_GetOptionalAttr]
|
||||
added = '3.13'
|
||||
[function.PyObject_GetOptionalAttrString]
|
||||
added = '3.13'
|
||||
|
|
|
@ -692,7 +692,7 @@ _PyObject_FunctionStr(PyObject *x)
|
|||
{
|
||||
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;
|
||||
|
@ -701,7 +701,7 @@ _PyObject_FunctionStr(PyObject *x)
|
|||
}
|
||||
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) {
|
||||
|
@ -957,7 +957,7 @@ _PyObject_IsAbstract(PyObject *obj)
|
|||
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);
|
||||
|
@ -1049,7 +1049,7 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
|
|||
}
|
||||
|
||||
int
|
||||
_PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result)
|
||||
PyObject_GetOptionalAttr(PyObject *v, PyObject *name, PyObject **result)
|
||||
{
|
||||
PyTypeObject *tp = Py_TYPE(v);
|
||||
|
||||
|
@ -1117,21 +1117,35 @@ _PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -469,6 +469,8 @@ EXPORT_FUNC(PyObject_GetAttrString)
|
|||
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)
|
||||
|
|
Loading…
Reference in New Issue