Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb14d608

Browse files
serhiy-storchakacsm10495
authored andcommitted
pythongh-108511: Add C API functions which do not silently ignore errors (pythonGH-109025)
Add the following functions:* PyObject_HasAttrWithError()* PyObject_HasAttrStringWithError()* PyMapping_HasKeyWithError()* PyMapping_HasKeyStringWithError()
1 parent0174f87 commitb14d608

28 files changed

+330
-111
lines changed

‎Doc/c-api/mapping.rst

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and
7676
rather than a:c:expr:`PyObject*`.
7777
7878
79+
..c:function::intPyMapping_HasKeyWithError(PyObject *o, PyObject *key)
80+
81+
Return ``1`` if the mapping object has the key *key* and ``0`` otherwise.
82+
This is equivalent to the Python expression ``key in o``.
83+
On failure, return ``-1``.
84+
85+
..versionadded::3.13
86+
87+
88+
..c:function::intPyMapping_HasKeyStringWithError(PyObject *o, const char *key)
89+
90+
This is the same as:c:func:`PyMapping_HasKeyWithError`, but *key* is
91+
specified as a:c:expr:`const char*` UTF-8 encoded bytes string,
92+
rather than a:c:expr:`PyObject*`.
93+
94+
..versionadded::3.13
95+
96+
7997
..c:function::intPyMapping_HasKey(PyObject *o, PyObject *key)
8098
8199
Return ``1`` if the mapping object has the key *key* and ``0`` otherwise.
@@ -86,8 +104,8 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and
86104
87105
Exceptions which occur when this calls:meth:`~object.__getitem__`
88106
method are silently ignored.
89-
For proper error handling, use:c:func:`PyMapping_GetOptionalItem` or
90-
:c:func:`PyObject_GetItem()` instead.
107+
For proper error handling, use:c:func:`PyMapping_HasKeyWithError`,
108+
:c:func:`PyMapping_GetOptionalItem` or:c:func:`PyObject_GetItem()` instead.
91109
92110
93111
..c:function::intPyMapping_HasKeyString(PyObject *o, const char *key)
@@ -101,7 +119,8 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and
101119
Exceptions that occur when this calls:meth:`~object.__getitem__`
102120
method or while creating the temporary:class:`str`
103121
object are silently ignored.
104-
For proper error handling, use:c:func:`PyMapping_GetOptionalItemString` or
122+
For proper error handling, use:c:func:`PyMapping_HasKeyStringWithError`,
123+
:c:func:`PyMapping_GetOptionalItemString` or
105124
:c:func:`PyMapping_GetItemString` instead.
106125
107126

‎Doc/c-api/object.rst

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ Object Protocol
2727
instead of the:func:`repr`.
2828
2929
30+
..c:function::intPyObject_HasAttrWithError(PyObject *o, const char *attr_name)
31+
32+
Returns ``1`` if *o* has the attribute *attr_name*, and ``0`` otherwise.
33+
This is equivalent to the Python expression ``hasattr(o, attr_name)``.
34+
On failure, return ``-1``.
35+
36+
..versionadded::3.13
37+
38+
39+
..c:function::intPyObject_HasAttrStringWithError(PyObject *o, const char *attr_name)
40+
41+
This is the same as:c:func:`PyObject_HasAttrWithError`, but *attr_name* is
42+
specified as a:c:expr:`const char*` UTF-8 encoded bytes string,
43+
rather than a:c:expr:`PyObject*`.
44+
45+
..versionadded::3.13
46+
47+
3048
..c:function::intPyObject_HasAttr(PyObject *o, PyObject *attr_name)
3149
3250
Returns ``1`` if *o* has the attribute *attr_name*, and ``0`` otherwise. This
@@ -37,8 +55,8 @@ Object Protocol
3755
3856
Exceptions that occur when this calls:meth:`~object.__getattr__` and
3957
:meth:`~object.__getattribute__` methods are silently ignored.
40-
For proper error handling, use:c:func:`PyObject_GetOptionalAttr` or
41-
:c:func:`PyObject_GetAttr` instead.
58+
For proper error handling, use:c:func:`PyObject_HasAttrWithError`,
59+
:c:func:`PyObject_GetOptionalAttr` or:c:func:`PyObject_GetAttr` instead.
4260
4361
4462
..c:function::intPyObject_HasAttrString(PyObject *o, const char *attr_name)
@@ -52,7 +70,8 @@ Object Protocol
5270
Exceptions that occur when this calls:meth:`~object.__getattr__` and
5371
:meth:`~object.__getattribute__` methods or while creating the temporary
5472
:class:`str` object are silently ignored.
55-
For proper error handling, use:c:func:`PyObject_GetOptionalAttrString`
73+
For proper error handling, use:c:func:`PyObject_HasAttrStringWithError`,
74+
:c:func:`PyObject_GetOptionalAttrString`
5675
or:c:func:`PyObject_GetAttrString` instead.
5776
5877

‎Doc/data/stable_abi.dat

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Doc/whatsnew/3.13.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,18 @@ New Features
926926
be treated as a failure.
927927
(Contributed by Serhiy Storchaka in:gh:`106307`.)
928928

929+
* Add fixed variants of functions which silently ignore errors:
930+
931+
-:c:func:`PyObject_HasAttrWithError` replaces:c:func:`PyObject_HasAttr`.
932+
-:c:func:`PyObject_HasAttrStringWithError` replaces:c:func:`PyObject_HasAttrString`.
933+
-:c:func:`PyMapping_HasKeyWithError` replaces:c:func:`PyMapping_HasKey`.
934+
-:c:func:`PyMapping_HasKeyStringWithError` replaces:c:func:`PyMapping_HasKeyString`.
935+
936+
New functions return not only ``1`` for true and ``0`` for false, but also
937+
``-1`` for error.
938+
939+
(Contributed by Serhiy Storchaka in:gh:`108511`.)
940+
929941
* If Python is built in:ref:`debug mode<debug-build>` or:option:`with
930942
assertions <--with-assertions>`,:c:func:`PyTuple_SET_ITEM` and
931943
:c:func:`PyList_SET_ITEM` now check the index argument with an assertion.

‎Include/abstract.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,25 @@ extern "C" {
5050
5151
This function always succeeds. */
5252

53+
54+
/* Implemented elsewhere:
55+
56+
int PyObject_HasAttrStringWithError(PyObject *o, const char *attr_name);
57+
58+
Returns 1 if object 'o' has the attribute attr_name, and 0 otherwise.
59+
This is equivalent to the Python expression: hasattr(o,attr_name).
60+
Returns -1 on failure. */
61+
62+
63+
/* Implemented elsewhere:
64+
65+
int PyObject_HasAttrWithError(PyObject *o, PyObject *attr_name);
66+
67+
Returns 1 if o has the attribute attr_name, and 0 otherwise.
68+
This is equivalent to the Python expression: hasattr(o,attr_name).
69+
Returns -1 on failure. */
70+
71+
5372
/* Implemented elsewhere:
5473
5574
PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name);
@@ -821,6 +840,18 @@ PyAPI_FUNC(int) PyMapping_HasKeyString(PyObject *o, const char *key);
821840
This function always succeeds. */
822841
PyAPI_FUNC(int)PyMapping_HasKey(PyObject*o,PyObject*key);
823842

843+
/* Return 1 if the mapping object has the key 'key', and 0 otherwise.
844+
This is equivalent to the Python expression: key in o.
845+
On failure, return -1. */
846+
847+
PyAPI_FUNC(int)PyMapping_HasKeyWithError(PyObject*o,PyObject*key);
848+
849+
/* Return 1 if the mapping object has the key 'key', and 0 otherwise.
850+
This is equivalent to the Python expression: key in o.
851+
On failure, return -1. */
852+
853+
PyAPI_FUNC(int)PyMapping_HasKeyStringWithError(PyObject*o,constchar*key);
854+
824855
/* On success, return a list or tuple of the keys in mapping object 'o'.
825856
On failure, return NULL. */
826857
PyAPI_FUNC(PyObject*)PyMapping_Keys(PyObject*o);

‎Include/object.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,10 @@ PyAPI_FUNC(int) PyObject_GetOptionalAttrString(PyObject *, const char *, PyObjec
394394
PyAPI_FUNC(int)PyObject_SetAttr(PyObject*,PyObject*,PyObject*);
395395
PyAPI_FUNC(int)PyObject_DelAttr(PyObject*v,PyObject*name);
396396
PyAPI_FUNC(int)PyObject_HasAttr(PyObject*,PyObject*);
397+
#if !defined(Py_LIMITED_API)||Py_LIMITED_API+0 >=0x030d0000
398+
PyAPI_FUNC(int)PyObject_HasAttrWithError(PyObject*,PyObject*);
399+
PyAPI_FUNC(int)PyObject_HasAttrStringWithError(PyObject*,constchar*);
400+
#endif
397401
PyAPI_FUNC(PyObject*)PyObject_SelfIter(PyObject*);
398402
PyAPI_FUNC(PyObject*)PyObject_GenericGetAttr(PyObject*,PyObject*);
399403
PyAPI_FUNC(int)PyObject_GenericSetAttr(PyObject*,PyObject*,PyObject*);

‎Lib/test/test_capi/test_abstract.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,34 @@ def test_object_hasattrstring(self):
129129
# CRASHES hasattrstring(obj, NULL)
130130
# CRASHES hasattrstring(NULL, b'a')
131131

132+
deftest_object_hasattrwitherror(self):
133+
xhasattr=_testcapi.object_hasattrwitherror
134+
obj=TestObject()
135+
obj.a=1
136+
setattr(obj,'\U0001f40d',2)
137+
self.assertTrue(xhasattr(obj,'a'))
138+
self.assertFalse(xhasattr(obj,'b'))
139+
self.assertTrue(xhasattr(obj,'\U0001f40d'))
140+
141+
self.assertRaises(RuntimeError,xhasattr,obj,'evil')
142+
self.assertRaises(TypeError,xhasattr,obj,1)
143+
# CRASHES xhasattr(obj, NULL)
144+
# CRASHES xhasattr(NULL, 'a')
145+
146+
deftest_object_hasattrstringwitherror(self):
147+
hasattrstring=_testcapi.object_hasattrstringwitherror
148+
obj=TestObject()
149+
obj.a=1
150+
setattr(obj,'\U0001f40d',2)
151+
self.assertTrue(hasattrstring(obj,b'a'))
152+
self.assertFalse(hasattrstring(obj,b'b'))
153+
self.assertTrue(hasattrstring(obj,'\U0001f40d'.encode()))
154+
155+
self.assertRaises(RuntimeError,hasattrstring,obj,b'evil')
156+
self.assertRaises(UnicodeDecodeError,hasattrstring,obj,b'\xff')
157+
# CRASHES hasattrstring(obj, NULL)
158+
# CRASHES hasattrstring(NULL, b'a')
159+
132160
deftest_object_setattr(self):
133161
xsetattr=_testcapi.object_setattr
134162
obj=TestObject()
@@ -339,6 +367,44 @@ def test_mapping_haskeystring(self):
339367
self.assertFalse(haskeystring([],b'a'))
340368
self.assertFalse(haskeystring(NULL,b'a'))
341369

370+
deftest_mapping_haskeywitherror(self):
371+
haskey=_testcapi.mapping_haskeywitherror
372+
dct= {'a':1,'\U0001f40d':2}
373+
self.assertTrue(haskey(dct,'a'))
374+
self.assertFalse(haskey(dct,'b'))
375+
self.assertTrue(haskey(dct,'\U0001f40d'))
376+
377+
dct2=ProxyGetItem(dct)
378+
self.assertTrue(haskey(dct2,'a'))
379+
self.assertFalse(haskey(dct2,'b'))
380+
381+
self.assertTrue(haskey(['a','b','c'],1))
382+
383+
self.assertRaises(TypeError,haskey,42,'a')
384+
self.assertRaises(TypeError,haskey, {}, [])# unhashable
385+
self.assertRaises(IndexError,haskey, [],1)
386+
self.assertRaises(TypeError,haskey, [],'a')
387+
388+
# CRASHES haskey({}, NULL))
389+
# CRASHES haskey(NULL, 'a'))
390+
391+
deftest_mapping_haskeystringwitherror(self):
392+
haskeystring=_testcapi.mapping_haskeystringwitherror
393+
dct= {'a':1,'\U0001f40d':2}
394+
self.assertTrue(haskeystring(dct,b'a'))
395+
self.assertFalse(haskeystring(dct,b'b'))
396+
self.assertTrue(haskeystring(dct,'\U0001f40d'.encode()))
397+
398+
dct2=ProxyGetItem(dct)
399+
self.assertTrue(haskeystring(dct2,b'a'))
400+
self.assertFalse(haskeystring(dct2,b'b'))
401+
402+
self.assertRaises(TypeError,haskeystring,42,b'a')
403+
self.assertRaises(UnicodeDecodeError,haskeystring, {},b'\xff')
404+
self.assertRaises(SystemError,haskeystring, {},NULL)
405+
self.assertRaises(TypeError,haskeystring, [],b'a')
406+
# CRASHES haskeystring(NULL, b'a')
407+
342408
deftest_object_setitem(self):
343409
setitem=_testcapi.object_setitem
344410
dct= {}

‎Lib/test/test_stable_abi_ctypes.py

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add functions:c:func:`PyObject_HasAttrWithError`,
2+
:c:func:`PyObject_HasAttrStringWithError`,
3+
:c:func:`PyMapping_HasKeyWithError` and
4+
:c:func:`PyMapping_HasKeyStringWithError`.

‎Misc/stable_abi.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,3 +2452,11 @@
24522452
added ='3.13'
24532453
[function.PyLong_AsInt]
24542454
added ='3.13'
2455+
[function.PyObject_HasAttrWithError]
2456+
added ='3.13'
2457+
[function.PyObject_HasAttrStringWithError]
2458+
added ='3.13'
2459+
[function.PyMapping_HasKeyWithError]
2460+
added ='3.13'
2461+
[function.PyMapping_HasKeyStringWithError]
2462+
added ='3.13'

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp