X Tutup
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *, PyObject* exc
PyAPI_FUNC(void) _PyEval_FormatAwaitableError(PyThreadState *tstate, PyTypeObject *type, int oparg);
PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj);
PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg);
PyAPI_FUNC(void) _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwargs);
PyAPI_FUNC(void) _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwargs, PyObject *dupkey);
PyAPI_FUNC(PyObject *) _PyEval_ImportFrom(PyThreadState *, PyObject *, PyObject *);

PyAPI_FUNC(PyObject *) _PyEval_LazyImportName(
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_dict.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ extern Py_ssize_t _PyDict_SizeOf_LockHeld(PyDictObject *);
of a key wins, if override is 2, a KeyError with conflicting key as
argument is raised.
*/
PyAPI_FUNC(int) _PyDict_MergeEx(PyObject *mp, PyObject *other, int override);
PyAPI_FUNC(int) _PyDict_MergeUniq(PyObject *mp, PyObject *other, PyObject **dupkey);

extern void _PyDict_DebugMallocStats(FILE *out);

Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_extcall.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,11 +634,11 @@ def test_errors_in_keys():
...
AttributeError: some error
>>> exc = TypeError('some error')
>>> exc = KeyError('some error')
>>> f(**D())
Traceback (most recent call last):
...
TypeError: some error
KeyError: 'some error'
"""

def test_errors_in_keys_next():
Expand Down Expand Up @@ -666,11 +666,11 @@ def test_errors_in_keys_next():
...
AttributeError: some error
>>> exc = TypeError('some error')
>>> exc = KeyError('some error')
>>> f(**D())
Traceback (most recent call last):
...
TypeError: some error
KeyError: 'some error'
"""

def test_errors_in_getitem():
Expand All @@ -694,11 +694,11 @@ def test_errors_in_getitem():
...
AttributeError: some error
>>> exc = TypeError('some error')
>>> exc = KeyError('some error')
>>> f(**D())
Traceback (most recent call last):
...
TypeError: some error
KeyError: 'some error'
"""

import doctest
Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_unpack_ex.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,11 +681,11 @@ def test_errors_in_keys():
...
AttributeError: some error

>>> exc = TypeError('some error')
>>> exc = KeyError('some error')
>>> {**D()}
Traceback (most recent call last):
...
TypeError: some error
KeyError: 'some error'
"""

def test_errors_in_keys_next():
Expand All @@ -712,11 +712,11 @@ def test_errors_in_keys_next():
...
AttributeError: some error

>>> exc = TypeError('some error')
>>> exc = KeyError('some error')
>>> {**D()}
Traceback (most recent call last):
...
TypeError: some error
KeyError: 'some error'
"""

def test_errors_in_getitem():
Expand All @@ -739,11 +739,11 @@ def test_errors_in_getitem():
...
AttributeError: some error

>>> exc = TypeError('some error')
>>> exc = KeyError('some error')
>>> {**D()}
Traceback (most recent call last):
...
TypeError: some error
KeyError: 'some error'
"""

__test__ = {'doctests' : doctests}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
:exc:`AttributeError`\ s raised in :meth:`!keys` or :meth:`!__getitem__`
:exc:`AttributeError`\ s and :exc:`KeyError`\ s raised in :meth:`!keys` or :meth:`!__getitem__`
during dictionary unpacking (``{**mymapping}`` or ``func(**mymapping)``) are
no longer masked by :exc:`TypeError`.
6 changes: 4 additions & 2 deletions Modules/_testinternalcapi/test_cases.c.h

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

56 changes: 29 additions & 27 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ As a consequence of this, split keys have a maximum size of 16.
static PyObject* frozendict_new(PyTypeObject *type, PyObject *args,
PyObject *kwds);
static PyObject* dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static int dict_merge(PyObject *a, PyObject *b, int override);
static int dict_merge(PyObject *a, PyObject *b, int override, PyObject **dupkey);
static int dict_contains(PyObject *op, PyObject *key);
static int dict_merge_from_seq2(PyObject *d, PyObject *seq2, int override);

Expand Down Expand Up @@ -3391,7 +3391,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
Py_DECREF(d);
return NULL;
}
if (dict_merge(copy, d, 1) < 0) {
if (dict_merge(copy, d, 1, NULL) < 0) {
Py_DECREF(d);
Py_DECREF(copy);
return NULL;
Expand Down Expand Up @@ -3887,14 +3887,14 @@ static int
dict_update_arg(PyObject *self, PyObject *arg)
{
if (PyAnyDict_CheckExact(arg)) {
return dict_merge(self, arg, 1);
return dict_merge(self, arg, 1, NULL);
}
int has_keys = PyObject_HasAttrWithError(arg, &_Py_ID(keys));
if (has_keys < 0) {
return -1;
}
if (has_keys) {
return dict_merge(self, arg, 1);
return dict_merge(self, arg, 1, NULL);
}
return dict_merge_from_seq2(self, arg, 1);
}
Expand All @@ -3915,7 +3915,7 @@ dict_update_common(PyObject *self, PyObject *args, PyObject *kwds,

if (result == 0 && kwds != NULL) {
if (PyArg_ValidateKeywordArguments(kwds))
result = dict_merge(self, kwds, 1);
result = dict_merge(self, kwds, 1, NULL);
else
result = -1;
}
Expand Down Expand Up @@ -4059,7 +4059,7 @@ PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override)
}

static int
dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override)
dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override, PyObject **dupkey)
{
assert(can_modify_dict(mp));
ASSERT_DICT_LOCKED(other);
Expand All @@ -4068,10 +4068,10 @@ dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override)
/* a.update(a) or a.update({}); nothing to do */
return 0;
if (mp->ma_used == 0) {
/* Since the target dict is empty, PyDict_GetItem()
* always returns NULL. Setting override to 1
* skips the unnecessary test.
*/
/* Since the target dict is empty, _PyDict_Contains_KnownHash()
* always returns 0. Setting override to 1
* skips the unnecessary test.
*/
override = 1;
PyDictKeysObject *okeys = other->ma_keys;

Expand Down Expand Up @@ -4131,11 +4131,10 @@ dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override)
err = insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value));
}
else if (err > 0) {
if (override != 0) {
_PyErr_SetKeyError(key);
if (dupkey != NULL) {
*dupkey = key;
Py_DECREF(value);
Py_DECREF(key);
return -1;
return -2;
}
err = 0;
}
Expand All @@ -4155,7 +4154,7 @@ dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override)
}

static int
dict_merge(PyObject *a, PyObject *b, int override)
dict_merge(PyObject *a, PyObject *b, int override, PyObject **dupkey)
{
assert(a != NULL);
assert(b != NULL);
Expand All @@ -4167,7 +4166,7 @@ dict_merge(PyObject *a, PyObject *b, int override)
PyDictObject *other = (PyDictObject*)b;
int res;
Py_BEGIN_CRITICAL_SECTION2(a, b);
res = dict_dict_merge((PyDictObject *)a, other, override);
res = dict_dict_merge((PyDictObject *)a, other, override, dupkey);
ASSERT_CONSISTENT(a);
Py_END_CRITICAL_SECTION2();
return res;
Expand Down Expand Up @@ -4202,15 +4201,18 @@ dict_merge(PyObject *a, PyObject *b, int override)
status = dict_contains(a, key);
if (status != 0) {
if (status > 0) {
if (override == 0) {
if (dupkey == NULL) {
Py_DECREF(key);
continue;
}
_PyErr_SetKeyError(key);
*dupkey = key;
res = -2;
}
else {
Py_DECREF(key);
res = -1;
}
Py_DECREF(key);
Py_DECREF(iter);
res = -1;
goto slow_exit;
}
}
Expand Down Expand Up @@ -4246,7 +4248,7 @@ dict_merge(PyObject *a, PyObject *b, int override)
}

static int
dict_merge_api(PyObject *a, PyObject *b, int override)
dict_merge_api(PyObject *a, PyObject *b, int override, PyObject **dupkey)
{
/* We accept for the argument either a concrete dictionary object,
* or an abstract "mapping" object. For the former, we can do
Expand All @@ -4262,26 +4264,26 @@ dict_merge_api(PyObject *a, PyObject *b, int override)
}
return -1;
}
return dict_merge(a, b, override);
return dict_merge(a, b, override, dupkey);
}

int
PyDict_Update(PyObject *a, PyObject *b)
{
return dict_merge_api(a, b, 1);
return dict_merge_api(a, b, 1, NULL);
}

int
PyDict_Merge(PyObject *a, PyObject *b, int override)
{
/* XXX Deprecate override not in (0, 1). */
return dict_merge_api(a, b, override != 0);
return dict_merge_api(a, b, override != 0, NULL);
}

int
_PyDict_MergeEx(PyObject *a, PyObject *b, int override)
_PyDict_MergeUniq(PyObject *a, PyObject *b, PyObject **dupkey)
{
return dict_merge_api(a, b, override);
return dict_merge_api(a, b, 2, dupkey);
}

/*[clinic input]
Expand Down Expand Up @@ -4421,7 +4423,7 @@ copy_lock_held(PyObject *o, int as_frozendict)
}
if (copy == NULL)
return NULL;
if (dict_merge(copy, o, 1) == 0)
if (dict_merge(copy, o, 1, NULL) == 0)
return copy;
Py_DECREF(copy);
return NULL;
Expand Down
6 changes: 4 additions & 2 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2414,10 +2414,12 @@ dummy_func(
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict);
PyObject *update_o = PyStackRef_AsPyObjectBorrow(update);
PyObject *dupkey = NULL;

int err = _PyDict_MergeEx(dict_o, update_o, 2);
int err = _PyDict_MergeUniq(dict_o, update_o, &dupkey);
if (err < 0) {
_PyEval_FormatKwargsError(tstate, callable_o, update_o);
_PyEval_FormatKwargsError(tstate, callable_o, update_o, dupkey);
Py_XDECREF(dupkey);
ERROR_NO_POP();
}
u = update;
Expand Down
36 changes: 12 additions & 24 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -3443,9 +3443,18 @@ _Py_Check_ArgsIterable(PyThreadState *tstate, PyObject *func, PyObject *args)
}

void
_PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwargs)
{
/* _PyDict_MergeEx raises attribute
_PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwargs, PyObject *dupkey)
{
if (dupkey != NULL) {
PyObject *funcstr = _PyObject_FunctionStr(func);
_PyErr_Format(
tstate, PyExc_TypeError,
"%V got multiple values for keyword argument '%S'",
funcstr, "finction", dupkey);
Py_XDECREF(funcstr);
return;
}
/* _PyDict_MergeUniq raises attribute
* error (percolated from an attempt
* to get 'keys' attribute) instead of
* a type error if its second argument
Expand All @@ -3465,27 +3474,6 @@ _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwarg
_PyErr_ChainExceptions1Tstate(tstate, exc);
}
}
else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
PyObject *exc = _PyErr_GetRaisedException(tstate);
PyObject *args = PyException_GetArgs(exc);
if (PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1) {
_PyErr_Clear(tstate);
PyObject *funcstr = _PyObject_FunctionStr(func);
if (funcstr != NULL) {
PyObject *key = PyTuple_GET_ITEM(args, 0);
_PyErr_Format(
tstate, PyExc_TypeError,
"%U got multiple values for keyword argument '%S'",
funcstr, key);
Py_DECREF(funcstr);
}
Py_XDECREF(exc);
}
else {
_PyErr_SetRaisedException(tstate, exc);
}
Py_DECREF(args);
}
}

void
Expand Down
6 changes: 4 additions & 2 deletions Python/executor_cases.c.h

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

6 changes: 4 additions & 2 deletions Python/generated_cases.c.h

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

Loading
X Tutup