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

Commit01388dc

Browse files
committed
gh-106004: Add PyDict_GetItemRef() function
* Add PyDict_GetItemRef() and PyDict_GetItemStringRef() functions. Add these functions to the stable ABI version 3.13.* Add unit tests on the PyDict C API in test_capi.
1 parente6f96cf commit01388dc

File tree

10 files changed

+308
-18
lines changed

10 files changed

+308
-18
lines changed

‎Doc/c-api/dict.rst

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,26 @@ Dictionary Objects
9393
Return ``0`` on success or ``-1`` on failure.
9494
9595
96+
..c:function::intPyDict_GetItemRef(PyObject *p, PyObject *key, PyObject **result)
97+
98+
Return a new:term:`strong reference` to the object from dictionary *p*
99+
which has a key *key*:
100+
101+
* If the key is present, set *\*result* to a new:term:`strong reference`
102+
to the value and return ``1``.
103+
* If the key is missing, set *\*result* to ``NULL`` and return ``0``.
104+
* On error, raise an exception and return ``-1``.
105+
106+
..versionadded::3.13
107+
108+
See also the:c:func:`PyObject_GetItem` function.
109+
110+
96111
..c:function:: PyObject*PyDict_GetItem(PyObject *p, PyObject *key)
97112
98-
Return the object from dictionary *p* which has a key *key*. Return ``NULL``
99-
if the key *key* is not present, but *without* setting an exception.
113+
Return a:term:`borrowed reference` to the object from dictionary *p* which
114+
has a key *key*. Return ``NULL`` if the key *key* is missing *without*
115+
setting an exception.
100116
101117
..note::
102118
@@ -131,6 +147,14 @@ Dictionary Objects
131147
:c:func:`PyUnicode_FromString` *key* instead.
132148
133149
150+
..c:function::intPyDict_GetItemStringRef(PyObject *p, const char *key, PyObject **result)
151+
152+
Similar than:c:func:`PyDict_GetItemRef`, but *key* is specified as a
153+
:c:expr:`const char*`, rather than a:c:expr:`PyObject*`.
154+
155+
..versionadded::3.13
156+
157+
134158
..c:function:: PyObject*PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *defaultobj)
135159
136160
This is the same as the Python-level:meth:`dict.setdefault`. If present, it

‎Doc/data/stable_abi.dat

Lines changed: 2 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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,13 @@ New Features
786786
always steals a reference to the value.
787787
(Contributed by Serhiy Storchaka in:gh:`86493`.)
788788

789+
* Added:c:func:`PyDict_GetItemRef` and:c:func:`PyDict_GetItemStringRef`
790+
functions: similar to:c:func:`PyDict_GetItemWithError` but returning a
791+
:term:`strong reference` instead of a:term:`borrowed reference`. Moreover,
792+
these functions return -1 on error and so checking ``PyErr_Occurred()`` is
793+
not needed.
794+
(Contributed by Victor Stinner in:gh:`106004`.)
795+
789796
Porting to Python 3.13
790797
----------------------
791798

‎Include/dictobject.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ PyAPI_FUNC(int) PyDict_MergeFromSeq2(PyObject *d,
5757
PyAPI_FUNC(PyObject*)PyDict_GetItemString(PyObject*dp,constchar*key);
5858
PyAPI_FUNC(int)PyDict_SetItemString(PyObject*dp,constchar*key,PyObject*item);
5959
PyAPI_FUNC(int)PyDict_DelItemString(PyObject*dp,constchar*key);
60+
61+
// Return the object from dictionary *op* which has a key *key*.
62+
// - If the key is present, set *result to a new strong reference to the value
63+
// and return 1.
64+
// - If the key is missing, set *result to NULL and return 0 .
65+
// - On error, raise an exception and return -1.
66+
PyAPI_FUNC(int)PyDict_GetItemRef(PyObject*mp,PyObject*key,PyObject**result);
67+
PyAPI_FUNC(int)PyDict_GetItemStringRef(PyObject*mp,constchar*key,PyObject**result);
68+
6069
#if !defined(Py_LIMITED_API)||Py_LIMITED_API+0 >=0x030A0000
6170
PyAPI_FUNC(PyObject*)PyObject_GenericGetDict(PyObject*,void*);
6271
#endif

‎Lib/test/test_stable_abi_ctypes.py

Lines changed: 2 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+
Adds:c:func:`PyDict_GetItemRef` and:c:func:`PyDict_GetItemStringRef`
2+
functions: similar to:c:func:`PyDict_GetItemWithError` but returning a
3+
:term:`strong reference` instead of a:term:`borrowed reference`. Patch by
4+
Victor Stinner.

‎Misc/stable_abi.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,3 +2446,7 @@
24462446
added ='3.13'
24472447
[function.PyModule_Add]
24482448
added ='3.13'
2449+
[function.PyDict_GetItemRef]
2450+
added ='3.13'
2451+
[function.PyDict_GetItemStringRef]
2452+
added ='3.13'

‎Modules/_testcapimodule.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3464,6 +3464,196 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
34643464
}
34653465

34663466

3467+
staticPyObject*
3468+
test_dict_capi(PyObject*Py_UNUSED(module),PyObject*Py_UNUSED(args))
3469+
{
3470+
assert(!PyErr_Occurred());
3471+
3472+
PyObject*dict=NULL,*key=NULL,*missing_key=NULL,*value=NULL;
3473+
PyObject*invalid_key=NULL;
3474+
intres;
3475+
3476+
// test PyDict_New()
3477+
dict=PyDict_New();
3478+
if (dict==NULL) {
3479+
gotoerror;
3480+
}
3481+
3482+
key=PyUnicode_FromString("key");
3483+
if (key==NULL) {
3484+
gotoerror;
3485+
}
3486+
3487+
missing_key=PyUnicode_FromString("missing_key");
3488+
if (missing_key==NULL) {
3489+
gotoerror;
3490+
}
3491+
3492+
value=PyUnicode_FromString("value");
3493+
if (value==NULL) {
3494+
gotoerror;
3495+
}
3496+
3497+
// test PyDict_SetItem()
3498+
Py_ssize_tkey_refcnt=Py_REFCNT(key);
3499+
Py_ssize_tvalue_refcnt=Py_REFCNT(value);
3500+
res=PyDict_SetItem(dict,key,value);
3501+
if (res<0) {
3502+
gotoerror;
3503+
}
3504+
assert(res==0);
3505+
assert(Py_REFCNT(key)== (key_refcnt+1));
3506+
assert(Py_REFCNT(value)== (value_refcnt+1));
3507+
3508+
// test PyDict_SetItemString()
3509+
res=PyDict_SetItemString(dict,"key",value);
3510+
if (res<0) {
3511+
gotoerror;
3512+
}
3513+
assert(res==0);
3514+
assert(Py_REFCNT(key)== (key_refcnt+1));
3515+
assert(Py_REFCNT(value)== (value_refcnt+1));
3516+
3517+
// test PyDict_Size()
3518+
assert(PyDict_Size(dict)==1);
3519+
3520+
// test PyDict_Contains(), key is present
3521+
assert(PyDict_Contains(dict,key)==1);
3522+
3523+
// test PyDict_GetItem(), key is present
3524+
assert(PyDict_GetItem(dict,key)==value);
3525+
3526+
// test PyDict_GetItemString(), key is present
3527+
assert(PyDict_GetItemString(dict,"key")==value);
3528+
3529+
// test PyDict_GetItemWithError(), key is present
3530+
assert(PyDict_GetItemWithError(dict,key)==value);
3531+
assert(!PyErr_Occurred());
3532+
3533+
// test PyDict_GetItemRef(), key is present
3534+
PyObject*get_value=Py_Ellipsis;// marker value
3535+
assert(PyDict_GetItemRef(dict,key,&get_value)==1);
3536+
assert(get_value==value);
3537+
Py_DECREF(get_value);
3538+
3539+
// test PyDict_GetItemStringRef(), key is present
3540+
get_value=Py_Ellipsis;// marker value
3541+
assert(PyDict_GetItemStringRef(dict,"key",&get_value)==1);
3542+
assert(get_value==value);
3543+
Py_DECREF(get_value);
3544+
3545+
// test PyDict_Contains(), missing key
3546+
assert(PyDict_Contains(dict,missing_key)==0);
3547+
3548+
// test PyDict_GetItem(), missing key
3549+
assert(PyDict_GetItem(dict,missing_key)==NULL);
3550+
assert(!PyErr_Occurred());
3551+
3552+
// test PyDict_GetItemString(), missing key
3553+
assert(PyDict_GetItemString(dict,"missing_key")==NULL);
3554+
assert(!PyErr_Occurred());
3555+
3556+
// test PyDict_GetItemWithError(), missing key
3557+
assert(PyDict_GetItem(dict,missing_key)==NULL);
3558+
assert(!PyErr_Occurred());
3559+
3560+
// test PyDict_GetItemRef(), missing key
3561+
get_value=Py_Ellipsis;// marker value
3562+
assert(PyDict_GetItemRef(dict,missing_key,&get_value)==0);
3563+
assert(!PyErr_Occurred());
3564+
assert(get_value==NULL);
3565+
3566+
// test PyDict_GetItemStringRef(), missing key
3567+
get_value=Py_Ellipsis;// marker value
3568+
assert(PyDict_GetItemStringRef(dict,"missing_key",&get_value)==0);
3569+
assert(!PyErr_Occurred());
3570+
assert(get_value==NULL);
3571+
3572+
// test PyDict_GetItem(), invalid dict
3573+
PyObject*invalid_dict=key;// borrowed reference
3574+
assert(PyDict_GetItem(invalid_dict,key)==NULL);
3575+
assert(!PyErr_Occurred());
3576+
3577+
// test PyDict_GetItemWithError(), invalid dict
3578+
assert(PyDict_GetItemWithError(invalid_dict,key)==NULL);
3579+
assert(PyErr_ExceptionMatches(PyExc_SystemError));
3580+
PyErr_Clear();
3581+
3582+
// test PyDict_GetItemRef(), invalid dict
3583+
get_value=Py_Ellipsis;// marker value
3584+
assert(PyDict_GetItemRef(invalid_dict,key,&get_value)==-1);
3585+
assert(PyErr_ExceptionMatches(PyExc_SystemError));
3586+
PyErr_Clear();
3587+
assert(get_value==NULL);
3588+
3589+
// test PyDict_GetItemStringRef(), invalid dict
3590+
get_value=Py_Ellipsis;// marker value
3591+
assert(PyDict_GetItemStringRef(invalid_dict,"key",&get_value)==-1);
3592+
assert(PyErr_ExceptionMatches(PyExc_SystemError));
3593+
PyErr_Clear();
3594+
assert(get_value==NULL);
3595+
3596+
invalid_key=PyList_New(0);
3597+
if (invalid_key==NULL) {
3598+
gotoerror;
3599+
}
3600+
3601+
// test PyDict_Contains(), invalid key
3602+
assert(PyDict_Contains(dict,invalid_key)==-1);
3603+
assert(PyErr_ExceptionMatches(PyExc_TypeError));
3604+
PyErr_Clear();
3605+
3606+
// test PyDict_GetItem(), invalid key
3607+
assert(PyDict_GetItem(dict,invalid_key)==NULL);
3608+
assert(!PyErr_Occurred());
3609+
3610+
// test PyDict_GetItemWithError(), invalid key
3611+
assert(PyDict_GetItemWithError(dict,invalid_key)==NULL);
3612+
assert(PyErr_ExceptionMatches(PyExc_TypeError));
3613+
PyErr_Clear();
3614+
3615+
// test PyDict_GetItemRef(), invalid key
3616+
get_value=Py_Ellipsis;// marker value
3617+
assert(PyDict_GetItemRef(dict,invalid_key,&get_value)==-1);
3618+
assert(PyErr_ExceptionMatches(PyExc_TypeError));
3619+
PyErr_Clear();
3620+
assert(get_value==NULL);
3621+
3622+
// test PyDict_DelItem(), key is present
3623+
assert(PyDict_DelItem(dict,key)==0);
3624+
assert(PyDict_Size(dict)==0);
3625+
3626+
// test PyDict_DelItem(), missing key
3627+
assert(PyDict_DelItem(dict,missing_key)==-1);
3628+
assert(PyErr_ExceptionMatches(PyExc_KeyError));
3629+
PyErr_Clear();
3630+
3631+
// test PyDict_DelItem(), invalid key
3632+
assert(PyDict_DelItem(dict,invalid_key)==-1);
3633+
assert(PyErr_ExceptionMatches(PyExc_TypeError));
3634+
PyErr_Clear();
3635+
3636+
// test PyDict_Clear()
3637+
PyDict_Clear(dict);
3638+
3639+
Py_DECREF(dict);
3640+
Py_DECREF(key);
3641+
Py_DECREF(missing_key);
3642+
Py_DECREF(value);
3643+
Py_DECREF(invalid_key);
3644+
3645+
Py_RETURN_NONE;
3646+
3647+
error:
3648+
Py_XDECREF(dict);
3649+
Py_XDECREF(key);
3650+
Py_XDECREF(missing_key);
3651+
Py_XDECREF(value);
3652+
Py_XDECREF(invalid_key);
3653+
returnNULL;
3654+
}
3655+
3656+
34673657
staticPyMethodDefTestMethods[]= {
34683658
{"set_errno",set_errno,METH_VARARGS},
34693659
{"test_config",test_config,METH_NOARGS},
@@ -3609,6 +3799,7 @@ static PyMethodDef TestMethods[] = {
36093799
{"function_set_kw_defaults",function_set_kw_defaults,METH_VARARGS,NULL},
36103800
{"check_pyimport_addmodule",check_pyimport_addmodule,METH_VARARGS},
36113801
{"test_weakref_capi",test_weakref_capi,METH_NOARGS},
3802+
{"test_dict_capi",test_dict_capi,METH_NOARGS},
36123803
{NULL,NULL}/* sentinel */
36133804
};
36143805

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp