FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-106521: Add PyObject_GetOptionalAttr() function by serhiy-storchaka · Pull Request #106522 · python/cpython · GitHub

/ cpython Public
Merged
41 changes: 39 additions & 2 deletions Doc/c-api/object.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -60,13 +62,48 @@ 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)

Retrieve an attribute named *attr_name* from object *o*. Returns the attribute
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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

You may just say:

Similar to :c:func:`PyObject_GetOptionalAttr`, but *name* is a UTF-8 encoded string.

To not copy/paste the documentation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

In all other functions with String suffix the documentation is repeated. If we are going to change this, it should be changed for all function at once.

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)

Expand Down
2 changes: 2 additions & 0 deletions Doc/data/stable_abi.dat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Doc/whatsnew/3.13.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
32 changes: 32 additions & 0 deletions Include/abstract.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 1 addition & 11 deletions Include/cpython/object.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
4 changes: 4 additions & 0 deletions Include/object.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_stable_abi_ctypes.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :c:func:`PyObject_GetOptionalAttr` and :c:func:`PyObject_GetOptionalAttrString` functions.
4 changes: 4 additions & 0 deletions Misc/stable_abi.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -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'
34 changes: 24 additions & 10 deletions Objects/object.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions PC/python3dll.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.


Back | FazBrowse Home | New Git URL