Compare commits

...

11 Commits

Author SHA1 Message Date
Andre Delfino 2edfc86f69
bpo-41224: Add versionadded for Symbol.is_annotated (GH-23861) 2020-12-29 15:32:10 +02:00
Erlend Egeberg Aasland 84d79cfda9
bpo-40956: Convert _sqlite3.Row to Argument Clinic (GH-23964) 2020-12-29 15:22:55 +02:00
Jakub Kulík 0159e5efee
bpo-42655: Fix subprocess extra_groups gid conversion (GH-23762) 2020-12-29 14:58:27 +02:00
Hai Shi dd39123970
bpo-40137: Convert _functools module to use PyType_FromModuleAndSpec. (GH-23405) 2020-12-29 04:45:07 -08:00
Michael Wayne Goodman 84402eb110
bpo-42700: Swap descriptions in pyexpat.errors (GH-23876)
The descriptions of the `codes` and `messages` dictionaries in
`xml.parsers.expat.errors` were swapped, and this commit swaps them
back. For example, `codes` maps string descriptions of errors to numeric
error codes, not the other way around.
2020-12-29 14:33:15 +02:00
Jero Bado a4258e8cd7
Fix minor typo in comments in readline.c (GH-23911) 2020-12-29 14:26:57 +02:00
Senthil Kumaran 030a713183
Allow / character in username,password fields in _PROXY envvars. (#23973) 2020-12-29 04:18:42 -08:00
Ross c1af128f5a
bpo-41781: Fix typo in internal function name in typing (GH-23957) 2020-12-29 13:55:28 +02:00
Zackery Spytz 40c2c83899
Fix typo in NEWS (GH23958) 2020-12-29 13:50:22 +02:00
Serhiy Storchaka 1df56bc059
bpo-42759: Fix equality comparison of Variable and Font in Tkinter (GH-23968)
Objects which belong to different Tcl interpreters are now always
different, even if they have the same name.
2020-12-29 12:56:55 +02:00
Serhiy Storchaka 156b7f7052
bpo-42749: Use dynamic version to test for unsupported bignum in Tk (GH-23966)
Tk can internally support bignum even if Tkinter is built without
support of bignum.
2020-12-29 12:55:55 +02:00
23 changed files with 402 additions and 277 deletions

View File

@ -665,14 +665,14 @@ The ``errors`` module has the following attributes:
.. data:: codes
A dictionary mapping numeric error codes to their string descriptions.
A dictionary mapping string descriptions to their error codes.
.. versionadded:: 3.2
.. data:: messages
A dictionary mapping string descriptions to their error codes.
A dictionary mapping numeric error codes to their string descriptions.
.. versionadded:: 3.2

View File

@ -160,6 +160,8 @@ Examining Symbol Tables
Return ``True`` if the symbol is annotated.
.. versionadded:: 3.6
.. method:: is_free()
Return ``True`` if the symbol is referenced in its block, but not assigned

View File

@ -27,8 +27,7 @@ import functools
py_functools = import_helper.import_fresh_module('functools',
blocked=['_functools'])
c_functools = import_helper.import_fresh_module('functools',
fresh=['_functools'])
c_functools = import_helper.import_fresh_module('functools')
decimal = import_helper.import_fresh_module('decimal', fresh=['_decimal'])

View File

@ -449,7 +449,7 @@ class TclTest(unittest.TestCase):
else:
self.assertEqual(result, str(i))
self.assertIsInstance(result, str)
if tcl_version < (8, 5): # bignum was added in Tcl 8.5
if get_tk_patchlevel() < (8, 5): # bignum was added in Tcl 8.5
self.assertRaises(TclError, tcl.call, 'expr', str(2**1000))
def test_passing_values(self):

View File

@ -1851,9 +1851,17 @@ class MiscTests(unittest.TestCase):
('ftp', 'joe', 'password', 'proxy.example.com')),
# Test for no trailing '/' case
('http://joe:password@proxy.example.com',
('http', 'joe', 'password', 'proxy.example.com'))
('http', 'joe', 'password', 'proxy.example.com')),
# Testcases with '/' character in username, password
('http://user/name:password@localhost:22',
('http', 'user/name', 'password', 'localhost:22')),
('http://username:pass/word@localhost:22',
('http', 'username', 'pass/word', 'localhost:22')),
('http://user/name:pass/word@localhost:22',
('http', 'user/name', 'pass/word', 'localhost:22')),
]
for tc, expected in parse_proxy_test_cases:
self.assertEqual(_parse_proxy(tc), expected)

View File

@ -516,15 +516,11 @@ class Variable:
self._tk.call("trace", "vinfo", self._name))]
def __eq__(self, other):
"""Comparison for equality (==).
Note: if the Variable's master matters to behavior
also compare self._master == other._master
"""
if not isinstance(other, Variable):
return NotImplemented
return self.__class__.__name__ == other.__class__.__name__ \
and self._name == other._name
return (self._name == other._name
and self.__class__.__name__ == other.__class__.__name__
and self._tk == other._tk)
class StringVar(Variable):

View File

@ -107,7 +107,7 @@ class Font:
def __eq__(self, other):
if not isinstance(other, Font):
return NotImplemented
return self.name == other.name
return self.name == other.name and self._tk == other._tk
def __getitem__(self, key):
return self.cget(key)

View File

@ -63,15 +63,22 @@ class FontTest(AbstractTkTest, unittest.TestCase):
self.assertEqual(self.font.name, fontname)
self.assertEqual(str(self.font), fontname)
def test_eq(self):
def test_equality(self):
font1 = font.Font(root=self.root, name=fontname, exists=True)
font2 = font.Font(root=self.root, name=fontname, exists=True)
self.assertIsNot(font1, font2)
self.assertEqual(font1, font2)
self.assertNotEqual(font1, font1.copy())
self.assertNotEqual(font1, 0)
self.assertEqual(font1, ALWAYS_EQ)
root2 = tkinter.Tk()
self.addCleanup(root2.destroy)
font3 = font.Font(root=root2, name=fontname, exists=True)
self.assertEqual(str(font1), str(font3))
self.assertNotEqual(font1, font3)
def test_measure(self):
self.assertIsInstance(self.font.measure('abc'), int)

View File

@ -58,22 +58,32 @@ class TestVariable(TestBase):
del v2
self.assertFalse(self.info_exists("name"))
def test___eq__(self):
def test_equality(self):
# values doesn't matter, only class and name are checked
v1 = Variable(self.root, name="abc")
v2 = Variable(self.root, name="abc")
self.assertIsNot(v1, v2)
self.assertEqual(v1, v2)
v3 = StringVar(self.root, name="abc")
v3 = Variable(self.root, name="cba")
self.assertNotEqual(v1, v3)
v4 = StringVar(self.root, name="abc")
self.assertEqual(str(v1), str(v4))
self.assertNotEqual(v1, v4)
V = type('Variable', (), {})
self.assertNotEqual(v1, V())
self.assertNotEqual(v1, object())
self.assertEqual(v1, ALWAYS_EQ)
root2 = tkinter.Tk()
self.addCleanup(root2.destroy)
v5 = Variable(root2, name="abc")
self.assertEqual(str(v1), str(v5))
self.assertNotEqual(v1, v5)
def test_invalid_name(self):
with self.assertRaises(TypeError):
Variable(self.root, name=123)

View File

@ -1249,7 +1249,7 @@ def _no_init(self, *args, **kwargs):
raise TypeError('Protocols cannot be instantiated')
def _allow_reckless_class_cheks():
def _allow_reckless_class_checks():
"""Allow instance and class checks for special stdlib modules.
The abc and functools modules indiscriminately call isinstance() and
@ -1338,12 +1338,12 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
# First, perform various sanity checks.
if not getattr(cls, '_is_runtime_protocol', False):
if _allow_reckless_class_cheks():
if _allow_reckless_class_checks():
return NotImplemented
raise TypeError("Instance and class checks can only be used with"
" @runtime_checkable protocols")
if not _is_callable_members_only(cls):
if _allow_reckless_class_cheks():
if _allow_reckless_class_checks():
return NotImplemented
raise TypeError("Protocols with non-method members"
" don't support issubclass()")

View File

@ -773,6 +773,10 @@ def _parse_proxy(proxy):
raise ValueError("proxy URL with no authority: %r" % proxy)
# We have an authority, so for RFC 3986-compliant URLs (by ss 3.
# and 3.3.), path is empty or starts with '/'
if '@' in r_scheme:
host_separator = r_scheme.find('@')
end = r_scheme.find("/", host_separator)
else:
end = r_scheme.find("/", 2)
if end == -1:
end = None

View File

@ -1784,7 +1784,7 @@ instead of an OrderedDict.
.. nonce: Q0ktFC
.. section: Library
An ExitStack is now used internally within subprocess.POpen to clean up pipe
An ExitStack is now used internally within subprocess.Popen to clean up pipe
file handles. No behavior change in normal operation. But if closing one
handle were ever to cause an exception, the others will now be closed
instead of leaked. (patch by Giampaolo Rodola)

View File

@ -0,0 +1 @@
Convert functools module to use :c:func:`PyType_FromModuleAndSpec`.

View File

@ -0,0 +1,2 @@
:mod:`subprocess` *extra_groups* is now correctly passed into setgroups()
system call.

View File

@ -0,0 +1 @@
Allow / character in username, password fields on _PROXY envars.

View File

@ -0,0 +1,3 @@
Fixed equality comparison of :class:`tkinter.Variable` and
:class:`tkinter.font.Font`. Objects which belong to different Tcl
interpreters are now always different, even if they have the same name.

View File

@ -24,9 +24,37 @@ typedef struct {
vectorcallfunc vectorcall;
} partialobject;
static PyTypeObject partial_type;
typedef struct _functools_state {
/* this object is used delimit args and keywords in the cache keys */
PyObject *kwd_mark;
PyTypeObject *partial_type;
PyTypeObject *keyobject_type;
PyTypeObject *lru_list_elem_type;
} _functools_state;
static inline _functools_state *
get_functools_state(PyObject *module)
{
void *state = PyModule_GetState(module);
assert(state != NULL);
return (_functools_state *)state;
}
static void partial_setvectorcall(partialobject *pto);
static struct PyModuleDef _functools_module;
static PyObject *
partial_call(partialobject *pto, PyObject *args, PyObject *kwargs);
static inline _functools_state *
get_functools_state_by_type(PyTypeObject *type)
{
PyObject *module = _PyType_GetModuleByDef(type, &_functools_module);
if (module == NULL) {
return NULL;
}
_functools_state *state = get_functools_state(module);
return state;
}
static PyObject *
partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
@ -42,7 +70,11 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
pargs = pkw = NULL;
func = PyTuple_GET_ITEM(args, 0);
if (Py_IS_TYPE(func, &partial_type) && type == &partial_type) {
if (Py_TYPE(func)->tp_call == (ternaryfunc)partial_call) {
// The type of "func" might not be exactly the same type object
// as "type", but if it is called using partial_call, it must have the
// same memory layout (fn, args and kw members).
// We can use its underlying function directly and merge the arguments.
partialobject *part = (partialobject *)func;
if (part->dict == NULL) {
pargs = part->args;
@ -117,6 +149,7 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
static void
partial_dealloc(partialobject *pto)
{
PyTypeObject *tp = Py_TYPE(pto);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(pto);
if (pto->weakreflist != NULL)
@ -125,7 +158,8 @@ partial_dealloc(partialobject *pto)
Py_XDECREF(pto->args);
Py_XDECREF(pto->kw);
Py_XDECREF(pto->dict);
Py_TYPE(pto)->tp_free(pto);
tp->tp_free(pto);
Py_DECREF(tp);
}
@ -294,6 +328,12 @@ static PyMemberDef partial_memberlist[] = {
"tuple of arguments to future partial calls"},
{"keywords", T_OBJECT, OFF(kw), READONLY,
"dictionary of keyword arguments to future partial calls"},
{"__weaklistoffset__", T_PYSSIZET,
offsetof(partialobject, weakreflist), READONLY},
{"__dictoffset__", T_PYSSIZET,
offsetof(partialobject, dict), READONLY},
{"__vectorcalloffset__", T_PYSSIZET,
offsetof(partialobject, vectorcall), READONLY},
{NULL} /* Sentinel */
};
@ -420,49 +460,28 @@ static PyMethodDef partial_methods[] = {
{NULL, NULL} /* sentinel */
};
static PyTypeObject partial_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"functools.partial", /* tp_name */
sizeof(partialobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)partial_dealloc, /* tp_dealloc */
offsetof(partialobject, vectorcall),/* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
(reprfunc)partial_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)partial_call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_VECTORCALL, /* tp_flags */
partial_doc, /* tp_doc */
(traverseproc)partial_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
offsetof(partialobject, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
partial_methods, /* tp_methods */
partial_memberlist, /* tp_members */
partial_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(partialobject, dict), /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
partial_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
static PyType_Slot partial_type_slots[] = {
{Py_tp_dealloc, partial_dealloc},
{Py_tp_repr, partial_repr},
{Py_tp_call, partial_call},
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_setattro, PyObject_GenericSetAttr},
{Py_tp_doc, (void *)partial_doc},
{Py_tp_traverse, partial_traverse},
{Py_tp_methods, partial_methods},
{Py_tp_members, partial_memberlist},
{Py_tp_getset, partial_getsetlist},
{Py_tp_new, partial_new},
{Py_tp_free, PyObject_GC_Del},
{0, 0}
};
static PyType_Spec partial_type_spec = {
.name = "functools.partial",
.basicsize = sizeof(partialobject),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
.slots = partial_type_slots
};
@ -474,12 +493,21 @@ typedef struct {
PyObject *object;
} keyobject;
static int
keyobject_clear(keyobject *ko)
{
Py_CLEAR(ko->cmp);
Py_CLEAR(ko->object);
return 0;
}
static void
keyobject_dealloc(keyobject *ko)
{
Py_DECREF(ko->cmp);
Py_XDECREF(ko->object);
PyTypeObject *tp = Py_TYPE(ko);
keyobject_clear(ko);
PyObject_Free(ko);
Py_DECREF(tp);
}
static int
@ -490,15 +518,6 @@ keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
return 0;
}
static int
keyobject_clear(keyobject *ko)
{
Py_CLEAR(ko->cmp);
if (ko->object)
Py_CLEAR(ko->object);
return 0;
}
static PyMemberDef keyobject_members[] = {
{"obj", T_OBJECT,
offsetof(keyobject, object), 0,
@ -512,38 +531,22 @@ keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
static PyObject *
keyobject_richcompare(PyObject *ko, PyObject *other, int op);
static PyTypeObject keyobject_type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"functools.KeyWrapper", /* tp_name */
sizeof(keyobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)keyobject_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)keyobject_call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
(traverseproc)keyobject_traverse, /* tp_traverse */
(inquiry)keyobject_clear, /* tp_clear */
keyobject_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
keyobject_members, /* tp_members */
0, /* tp_getset */
static PyType_Slot keyobject_type_slots[] = {
{Py_tp_dealloc, keyobject_dealloc},
{Py_tp_call, keyobject_call},
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_traverse, keyobject_traverse},
{Py_tp_clear, keyobject_clear},
{Py_tp_richcompare, keyobject_richcompare},
{Py_tp_members, keyobject_members},
{0, 0}
};
static PyType_Spec keyobject_type_spec = {
.name = "functools.KeyWrapper",
.basicsize = sizeof(keyobject),
.flags = Py_TPFLAGS_DEFAULT,
.slots = keyobject_type_slots
};
static PyObject *
@ -555,9 +558,11 @@ keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
return NULL;
result = PyObject_New(keyobject, &keyobject_type);
if (!result)
result = PyObject_New(keyobject, Py_TYPE(ko));
if (result == NULL) {
return NULL;
}
Py_INCREF(ko->cmp);
result->cmp = ko->cmp;
Py_INCREF(object);
@ -575,7 +580,7 @@ keyobject_richcompare(PyObject *ko, PyObject *other, int op)
PyObject *answer;
PyObject* stack[2];
if (!Py_IS_TYPE(other, &keyobject_type)) {
if (!Py_IS_TYPE(other, Py_TYPE(ko))) {
PyErr_Format(PyExc_TypeError, "other argument must be K instance");
return NULL;
}
@ -609,10 +614,13 @@ functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *cmp;
static char *kwargs[] = {"mycmp", NULL};
keyobject *object;
_functools_state *state;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
return NULL;
object = PyObject_New(keyobject, &keyobject_type);
state = get_functools_state(self);
object = PyObject_New(keyobject, state->keyobject_type);
if (!object)
return NULL;
Py_INCREF(cmp);
@ -729,10 +737,6 @@ iterable is empty.");
*/
/* this object is used delimit args and keywords in the cache keys */
static PyObject *kwd_mark = NULL;
struct lru_list_elem;
struct lru_cache_object;
@ -746,33 +750,23 @@ typedef struct lru_list_elem {
static void
lru_list_elem_dealloc(lru_list_elem *link)
{
PyTypeObject *tp = Py_TYPE(link);
Py_XDECREF(link->key);
Py_XDECREF(link->result);
PyObject_Free(link);
Py_DECREF(tp);
}
static PyTypeObject lru_list_elem_type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"functools._lru_list_elem", /* tp_name */
sizeof(lru_list_elem), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)lru_list_elem_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
static PyType_Slot lru_list_elem_type_slots[] = {
{Py_tp_dealloc, lru_list_elem_dealloc},
{0, 0}
};
static PyType_Spec lru_list_elem_type_spec = {
.name = "functools._lru_list_elem",
.basicsize = sizeof(lru_list_elem),
.flags = Py_TPFLAGS_DEFAULT,
.slots = lru_list_elem_type_slots
};
@ -792,10 +786,9 @@ typedef struct lru_cache_object {
PyObject *weakreflist;
} lru_cache_object;
static PyTypeObject lru_cache_type;
static PyObject *
lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
lru_cache_make_key(_functools_state *state, PyObject *args,
PyObject *kwds, int typed)
{
PyObject *key, *keyword, *value;
Py_ssize_t key_size, pos, key_pos, kwds_size;
@ -834,8 +827,8 @@ lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
PyTuple_SET_ITEM(key, key_pos++, item);
}
if (kwds_size) {
Py_INCREF(kwd_mark);
PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
Py_INCREF(state->kwd_mark);
PyTuple_SET_ITEM(key, key_pos++, state->kwd_mark);
for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
Py_INCREF(keyword);
PyTuple_SET_ITEM(key, key_pos++, keyword);
@ -879,7 +872,12 @@ infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd
{
PyObject *result;
Py_hash_t hash;
PyObject *key = lru_cache_make_key(args, kwds, self->typed);
_functools_state *state;
state = get_functools_state_by_type(Py_TYPE(self));
if (state == NULL) {
return NULL;
}
PyObject *key = lru_cache_make_key(state, args, kwds, self->typed);
if (!key)
return NULL;
hash = PyObject_Hash(key);
@ -979,8 +977,13 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
lru_list_elem *link;
PyObject *key, *result, *testresult;
Py_hash_t hash;
_functools_state *state;
key = lru_cache_make_key(args, kwds, self->typed);
state = get_functools_state_by_type(Py_TYPE(self));
if (state == NULL) {
return NULL;
}
key = lru_cache_make_key(state, args, kwds, self->typed);
if (!key)
return NULL;
hash = PyObject_Hash(key);
@ -1035,7 +1038,7 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
{
/* Cache is not full, so put the result in a new link */
link = (lru_list_elem *)PyObject_New(lru_list_elem,
&lru_list_elem_type);
state->lru_list_elem_type);
if (link == NULL) {
Py_DECREF(key);
Py_DECREF(result);
@ -1229,22 +1232,31 @@ lru_cache_clear_list(lru_list_elem *link)
}
}
static int
lru_cache_tp_clear(lru_cache_object *self)
{
lru_list_elem *list = lru_cache_unlink_list(self);
Py_CLEAR(self->func);
Py_CLEAR(self->cache);
Py_CLEAR(self->cache_info_type);
Py_CLEAR(self->dict);
lru_cache_clear_list(list);
return 0;
}
static void
lru_cache_dealloc(lru_cache_object *obj)
{
lru_list_elem *list;
PyTypeObject *tp = Py_TYPE(obj);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(obj);
if (obj->weakreflist != NULL)
if (obj->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*)obj);
}
list = lru_cache_unlink_list(obj);
Py_XDECREF(obj->cache);
Py_XDECREF(obj->func);
Py_XDECREF(obj->cache_info_type);
Py_XDECREF(obj->dict);
lru_cache_clear_list(list);
Py_TYPE(obj)->tp_free(obj);
lru_cache_tp_clear(obj);
tp->tp_free(obj);
Py_DECREF(tp);
}
static PyObject *
@ -1323,18 +1335,6 @@ lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
return 0;
}
static int
lru_cache_tp_clear(lru_cache_object *self)
{
lru_list_elem *list = lru_cache_unlink_list(self);
Py_CLEAR(self->func);
Py_CLEAR(self->cache);
Py_CLEAR(self->cache_info_type);
Py_CLEAR(self->dict);
lru_cache_clear_list(list);
return 0;
}
PyDoc_STRVAR(lru_cache_doc,
"Create a cached callable that wraps another function.\n\
@ -1366,51 +1366,37 @@ static PyGetSetDef lru_cache_getsetlist[] = {
{NULL}
};
static PyTypeObject lru_cache_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"functools._lru_cache_wrapper", /* tp_name */
sizeof(lru_cache_object), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)lru_cache_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)lru_cache_call, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_METHOD_DESCRIPTOR,
/* tp_flags */
lru_cache_doc, /* tp_doc */
(traverseproc)lru_cache_tp_traverse,/* tp_traverse */
(inquiry)lru_cache_tp_clear, /* tp_clear */
0, /* tp_richcompare */
offsetof(lru_cache_object, weakreflist),
/* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
lru_cache_methods, /* tp_methods */
0, /* tp_members */
lru_cache_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
lru_cache_descr_get, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(lru_cache_object, dict), /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
lru_cache_new, /* tp_new */
static PyMemberDef lru_cache_memberlist[] = {
{"__dictoffset__", T_PYSSIZET,
offsetof(lru_cache_object, dict), READONLY},
{"__weaklistoffset__", T_PYSSIZET,
offsetof(lru_cache_object, weakreflist), READONLY},
{NULL} /* Sentinel */
};
static PyType_Slot lru_cache_type_slots[] = {
{Py_tp_dealloc, lru_cache_dealloc},
{Py_tp_call, lru_cache_call},
{Py_tp_doc, (void *)lru_cache_doc},
{Py_tp_traverse, lru_cache_tp_traverse},
{Py_tp_clear, lru_cache_tp_clear},
{Py_tp_methods, lru_cache_methods},
{Py_tp_members, lru_cache_memberlist},
{Py_tp_getset, lru_cache_getsetlist},
{Py_tp_descr_get, lru_cache_descr_get},
{Py_tp_new, lru_cache_new},
{0, 0}
};
static PyType_Spec lru_cache_type_spec = {
.name = "functools._lru_cache_wrapper",
.basicsize = sizeof(lru_cache_object),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_METHOD_DESCRIPTOR,
.slots = lru_cache_type_slots
};
/* module level code ********************************************************/
PyDoc_STRVAR(_functools_doc,
@ -1423,38 +1409,83 @@ static PyMethodDef _functools_methods[] = {
{NULL, NULL} /* sentinel */
};
static void
_functools_free(void *m)
{
// FIXME: Do not clear kwd_mark to avoid NULL pointer dereferencing if we have
// other modules instances that could use it. Will fix when PEP-573 land
// and we could move kwd_mark to a per-module state.
// Py_CLEAR(kwd_mark);
}
static int
_functools_exec(PyObject *module)
{
PyTypeObject *typelist[] = {
&partial_type,
&lru_cache_type
};
if (!kwd_mark) {
kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
if (!kwd_mark) {
_functools_state *state = get_functools_state(module);
state->kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
if (state->kwd_mark == NULL) {
return -1;
}
}
for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) {
if (PyModule_AddType(module, typelist[i]) < 0) {
state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
&partial_type_spec, NULL);
if (state->partial_type == NULL) {
return -1;
}
if (PyModule_AddType(module, state->partial_type) < 0) {
return -1;
}
PyObject *lru_cache_type = PyType_FromModuleAndSpec(module,
&lru_cache_type_spec, NULL);
if (lru_cache_type == NULL) {
return -1;
}
if (PyModule_AddType(module, (PyTypeObject *)lru_cache_type) < 0) {
Py_DECREF(lru_cache_type);
return -1;
}
state->keyobject_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
&keyobject_type_spec, NULL);
if (state->keyobject_type == NULL) {
return -1;
}
if (PyModule_AddType(module, state->keyobject_type) < 0) {
return -1;
}
state->lru_list_elem_type = (PyTypeObject *)PyType_FromModuleAndSpec(
module, &lru_list_elem_type_spec, NULL);
if (state->lru_list_elem_type == NULL) {
return -1;
}
if (PyModule_AddType(module, state->lru_list_elem_type) < 0) {
return -1;
}
return 0;
}
static int
_functools_traverse(PyObject *module, visitproc visit, void *arg)
{
_functools_state *state = get_functools_state(module);
Py_VISIT(state->kwd_mark);
Py_VISIT(state->partial_type);
Py_VISIT(state->keyobject_type);
Py_VISIT(state->lru_list_elem_type);
return 0;
}
static int
_functools_clear(PyObject *module)
{
_functools_state *state = get_functools_state(module);
Py_CLEAR(state->kwd_mark);
Py_CLEAR(state->partial_type);
Py_CLEAR(state->keyobject_type);
Py_CLEAR(state->lru_list_elem_type);
return 0;
}
static void
_functools_free(void *module)
{
_functools_clear((PyObject *)module);
}
static struct PyModuleDef_Slot _functools_slots[] = {
{Py_mod_exec, _functools_exec},
{0, NULL}
@ -1462,14 +1493,14 @@ static struct PyModuleDef_Slot _functools_slots[] = {
static struct PyModuleDef _functools_module = {
PyModuleDef_HEAD_INIT,
"_functools",
_functools_doc,
0,
_functools_methods,
_functools_slots,
NULL,
NULL,
_functools_free,
.m_name = "_functools",
.m_doc = _functools_doc,
.m_size = sizeof(_functools_state),
.m_methods = _functools_methods,
.m_slots = _functools_slots,
.m_traverse = _functools_traverse,
.m_clear = _functools_clear,
.m_free = _functools_free,
};
PyMODINIT_FUNC

View File

@ -900,7 +900,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
if (groups_list != Py_None) {
#ifdef HAVE_SETGROUPS
Py_ssize_t i;
unsigned long gid;
gid_t gid;
if (!PyList_Check(groups_list)) {
PyErr_SetString(PyExc_TypeError,
@ -934,10 +934,6 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
Py_DECREF(elem);
goto cleanup;
} else {
/* In posixmodule.c UnsignedLong is used as a fallback value
* if the value provided does not fit in a Long. Since we are
* already doing the bounds checking on the Python side, we
* can go directly to an UnsignedLong here. */
if (!_Py_Gid_Converter(elem, &gid)) {
Py_DECREF(elem);
PyErr_SetString(PyExc_ValueError, "invalid group id");

View File

@ -0,0 +1,56 @@
/*[clinic input]
preserve
[clinic start generated code]*/
static PyObject *
pysqlite_row_new_impl(PyTypeObject *type, pysqlite_Cursor *cursor,
PyObject *data);
static PyObject *
pysqlite_row_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
pysqlite_Cursor *cursor;
PyObject *data;
if ((type == pysqlite_RowType) &&
!_PyArg_NoKeywords("Row", kwargs)) {
goto exit;
}
if (!_PyArg_CheckPositional("Row", PyTuple_GET_SIZE(args), 2, 2)) {
goto exit;
}
if (!PyObject_TypeCheck(PyTuple_GET_ITEM(args, 0), pysqlite_CursorType)) {
_PyArg_BadArgument("Row", "argument 1", (pysqlite_CursorType)->tp_name, PyTuple_GET_ITEM(args, 0));
goto exit;
}
cursor = (pysqlite_Cursor *)PyTuple_GET_ITEM(args, 0);
if (!PyTuple_Check(PyTuple_GET_ITEM(args, 1))) {
_PyArg_BadArgument("Row", "argument 2", "tuple", PyTuple_GET_ITEM(args, 1));
goto exit;
}
data = PyTuple_GET_ITEM(args, 1);
return_value = pysqlite_row_new_impl(type, cursor, data);
exit:
return return_value;
}
PyDoc_STRVAR(pysqlite_row_keys__doc__,
"keys($self, /)\n"
"--\n"
"\n"
"Returns the keys of the row.");
#define PYSQLITE_ROW_KEYS_METHODDEF \
{"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS, pysqlite_row_keys__doc__},
static PyObject *
pysqlite_row_keys_impl(pysqlite_Row *self);
static PyObject *
pysqlite_row_keys(pysqlite_Row *self, PyObject *Py_UNUSED(ignored))
{
return pysqlite_row_keys_impl(self);
}
/*[clinic end generated code: output=8d29220b9cde035d input=a9049054013a1b77]*/

View File

@ -23,6 +23,13 @@
#include "row.h"
#include "cursor.h"
#include "clinic/row.c.h"
/*[clinic input]
module _sqlite3
class _sqlite3.Row "pysqlite_Row *" "pysqlite_RowType"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=384227da65f250fd]*/
void pysqlite_row_dealloc(pysqlite_Row* self)
{
@ -35,30 +42,25 @@ void pysqlite_row_dealloc(pysqlite_Row* self)
Py_DECREF(tp);
}
/*[clinic input]
@classmethod
_sqlite3.Row.__new__ as pysqlite_row_new
cursor: object(type='pysqlite_Cursor *', subclass_of='pysqlite_CursorType')
data: object(subclass_of='&PyTuple_Type')
/
[clinic start generated code]*/
static PyObject *
pysqlite_row_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
pysqlite_row_new_impl(PyTypeObject *type, pysqlite_Cursor *cursor,
PyObject *data)
/*[clinic end generated code: output=10d58b09a819a4c1 input=f6cd7e6e0935828d]*/
{
pysqlite_Row *self;
PyObject* data;
pysqlite_Cursor* cursor;
assert(type != NULL && type->tp_alloc != NULL);
if (!_PyArg_NoKeywords("Row", kwargs))
return NULL;
if (!PyArg_ParseTuple(args, "OO", &cursor, &data))
return NULL;
if (!PyObject_TypeCheck((PyObject*)cursor, pysqlite_CursorType)) {
PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument");
return NULL;
}
if (!PyTuple_Check(data)) {
PyErr_SetString(PyExc_TypeError, "tuple required for second argument");
return NULL;
}
self = (pysqlite_Row *) type->tp_alloc(type, 0);
if (self == NULL)
return NULL;
@ -153,7 +155,15 @@ pysqlite_row_length(pysqlite_Row* self)
return PyTuple_GET_SIZE(self->data);
}
PyObject* pysqlite_row_keys(pysqlite_Row* self, PyObject *Py_UNUSED(ignored))
/*[clinic input]
_sqlite3.Row.keys as pysqlite_row_keys
Returns the keys of the row.
[clinic start generated code]*/
static PyObject *
pysqlite_row_keys_impl(pysqlite_Row *self)
/*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/
{
PyObject* list;
Py_ssize_t nitems, i;
@ -204,8 +214,7 @@ static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other,
}
static PyMethodDef row_methods[] = {
{"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
PyDoc_STR("Returns the keys of the row.")},
PYSQLITE_ROW_KEYS_METHODDEF
{NULL, NULL}
};

View File

@ -672,7 +672,7 @@ _PyLong_FromGid(gid_t gid)
}
int
_Py_Uid_Converter(PyObject *obj, void *p)
_Py_Uid_Converter(PyObject *obj, uid_t *p)
{
uid_t uid;
PyObject *index;
@ -759,7 +759,7 @@ _Py_Uid_Converter(PyObject *obj, void *p)
success:
Py_DECREF(index);
*(uid_t *)p = uid;
*p = uid;
return 1;
underflow:
@ -778,7 +778,7 @@ fail:
}
int
_Py_Gid_Converter(PyObject *obj, void *p)
_Py_Gid_Converter(PyObject *obj, gid_t *p)
{
gid_t gid;
PyObject *index;
@ -866,7 +866,7 @@ _Py_Gid_Converter(PyObject *obj, void *p)
success:
Py_DECREF(index);
*(gid_t *)p = gid;
*p = gid;
return 1;
underflow:

View File

@ -14,8 +14,8 @@ extern "C" {
#ifndef MS_WINDOWS
PyAPI_FUNC(PyObject *) _PyLong_FromUid(uid_t);
PyAPI_FUNC(PyObject *) _PyLong_FromGid(gid_t);
PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, void *);
PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, void *);
PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, uid_t *);
PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, gid_t *);
#endif /* MS_WINDOWS */
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \

View File

@ -51,7 +51,7 @@ extern char **completion_matches(char *, CPFunction *);
*
* This emulation library is not 100% API compatible with the "real" readline
* and cannot be detected at compile-time,
* hence we use a runtime check to detect if the Python readlinke module is
* hence we use a runtime check to detect if the Python readline module is
* linked to libedit.
*
* Currently there is one known API incompatibility: