Compare commits
11 Commits
c56988b88f
...
2edfc86f69
Author | SHA1 | Date |
---|---|---|
Andre Delfino | 2edfc86f69 | |
Erlend Egeberg Aasland | 84d79cfda9 | |
Jakub Kulík | 0159e5efee | |
Hai Shi | dd39123970 | |
Michael Wayne Goodman | 84402eb110 | |
Jero Bado | a4258e8cd7 | |
Senthil Kumaran | 030a713183 | |
Ross | c1af128f5a | |
Zackery Spytz | 40c2c83899 | |
Serhiy Storchaka | 1df56bc059 | |
Serhiy Storchaka | 156b7f7052 |
|
@ -665,14 +665,14 @@ The ``errors`` module has the following attributes:
|
||||||
|
|
||||||
.. data:: codes
|
.. data:: codes
|
||||||
|
|
||||||
A dictionary mapping numeric error codes to their string descriptions.
|
A dictionary mapping string descriptions to their error codes.
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
|
||||||
.. data:: messages
|
.. data:: messages
|
||||||
|
|
||||||
A dictionary mapping string descriptions to their error codes.
|
A dictionary mapping numeric error codes to their string descriptions.
|
||||||
|
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,8 @@ Examining Symbol Tables
|
||||||
|
|
||||||
Return ``True`` if the symbol is annotated.
|
Return ``True`` if the symbol is annotated.
|
||||||
|
|
||||||
|
.. versionadded:: 3.6
|
||||||
|
|
||||||
.. method:: is_free()
|
.. method:: is_free()
|
||||||
|
|
||||||
Return ``True`` if the symbol is referenced in its block, but not assigned
|
Return ``True`` if the symbol is referenced in its block, but not assigned
|
||||||
|
|
|
@ -27,8 +27,7 @@ import functools
|
||||||
|
|
||||||
py_functools = import_helper.import_fresh_module('functools',
|
py_functools = import_helper.import_fresh_module('functools',
|
||||||
blocked=['_functools'])
|
blocked=['_functools'])
|
||||||
c_functools = import_helper.import_fresh_module('functools',
|
c_functools = import_helper.import_fresh_module('functools')
|
||||||
fresh=['_functools'])
|
|
||||||
|
|
||||||
decimal = import_helper.import_fresh_module('decimal', fresh=['_decimal'])
|
decimal = import_helper.import_fresh_module('decimal', fresh=['_decimal'])
|
||||||
|
|
||||||
|
|
|
@ -449,7 +449,7 @@ class TclTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertEqual(result, str(i))
|
self.assertEqual(result, str(i))
|
||||||
self.assertIsInstance(result, str)
|
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))
|
self.assertRaises(TclError, tcl.call, 'expr', str(2**1000))
|
||||||
|
|
||||||
def test_passing_values(self):
|
def test_passing_values(self):
|
||||||
|
|
|
@ -1851,9 +1851,17 @@ class MiscTests(unittest.TestCase):
|
||||||
('ftp', 'joe', 'password', 'proxy.example.com')),
|
('ftp', 'joe', 'password', 'proxy.example.com')),
|
||||||
# Test for no trailing '/' case
|
# Test for no trailing '/' case
|
||||||
('http://joe:password@proxy.example.com',
|
('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:
|
for tc, expected in parse_proxy_test_cases:
|
||||||
self.assertEqual(_parse_proxy(tc), expected)
|
self.assertEqual(_parse_proxy(tc), expected)
|
||||||
|
|
||||||
|
|
|
@ -516,15 +516,11 @@ class Variable:
|
||||||
self._tk.call("trace", "vinfo", self._name))]
|
self._tk.call("trace", "vinfo", self._name))]
|
||||||
|
|
||||||
def __eq__(self, other):
|
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):
|
if not isinstance(other, Variable):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
return self.__class__.__name__ == other.__class__.__name__ \
|
return (self._name == other._name
|
||||||
and self._name == other._name
|
and self.__class__.__name__ == other.__class__.__name__
|
||||||
|
and self._tk == other._tk)
|
||||||
|
|
||||||
|
|
||||||
class StringVar(Variable):
|
class StringVar(Variable):
|
||||||
|
|
|
@ -107,7 +107,7 @@ class Font:
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if not isinstance(other, Font):
|
if not isinstance(other, Font):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
return self.name == other.name
|
return self.name == other.name and self._tk == other._tk
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.cget(key)
|
return self.cget(key)
|
||||||
|
|
|
@ -63,15 +63,22 @@ class FontTest(AbstractTkTest, unittest.TestCase):
|
||||||
self.assertEqual(self.font.name, fontname)
|
self.assertEqual(self.font.name, fontname)
|
||||||
self.assertEqual(str(self.font), 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)
|
font1 = font.Font(root=self.root, name=fontname, exists=True)
|
||||||
font2 = font.Font(root=self.root, name=fontname, exists=True)
|
font2 = font.Font(root=self.root, name=fontname, exists=True)
|
||||||
self.assertIsNot(font1, font2)
|
self.assertIsNot(font1, font2)
|
||||||
self.assertEqual(font1, font2)
|
self.assertEqual(font1, font2)
|
||||||
self.assertNotEqual(font1, font1.copy())
|
self.assertNotEqual(font1, font1.copy())
|
||||||
|
|
||||||
self.assertNotEqual(font1, 0)
|
self.assertNotEqual(font1, 0)
|
||||||
self.assertEqual(font1, ALWAYS_EQ)
|
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):
|
def test_measure(self):
|
||||||
self.assertIsInstance(self.font.measure('abc'), int)
|
self.assertIsInstance(self.font.measure('abc'), int)
|
||||||
|
|
||||||
|
|
|
@ -58,22 +58,32 @@ class TestVariable(TestBase):
|
||||||
del v2
|
del v2
|
||||||
self.assertFalse(self.info_exists("name"))
|
self.assertFalse(self.info_exists("name"))
|
||||||
|
|
||||||
def test___eq__(self):
|
def test_equality(self):
|
||||||
# values doesn't matter, only class and name are checked
|
# values doesn't matter, only class and name are checked
|
||||||
v1 = Variable(self.root, name="abc")
|
v1 = Variable(self.root, name="abc")
|
||||||
v2 = Variable(self.root, name="abc")
|
v2 = Variable(self.root, name="abc")
|
||||||
self.assertIsNot(v1, v2)
|
self.assertIsNot(v1, v2)
|
||||||
self.assertEqual(v1, v2)
|
self.assertEqual(v1, v2)
|
||||||
|
|
||||||
v3 = StringVar(self.root, name="abc")
|
v3 = Variable(self.root, name="cba")
|
||||||
self.assertNotEqual(v1, v3)
|
self.assertNotEqual(v1, v3)
|
||||||
|
|
||||||
|
v4 = StringVar(self.root, name="abc")
|
||||||
|
self.assertEqual(str(v1), str(v4))
|
||||||
|
self.assertNotEqual(v1, v4)
|
||||||
|
|
||||||
V = type('Variable', (), {})
|
V = type('Variable', (), {})
|
||||||
self.assertNotEqual(v1, V())
|
self.assertNotEqual(v1, V())
|
||||||
|
|
||||||
self.assertNotEqual(v1, object())
|
self.assertNotEqual(v1, object())
|
||||||
self.assertEqual(v1, ALWAYS_EQ)
|
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):
|
def test_invalid_name(self):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
Variable(self.root, name=123)
|
Variable(self.root, name=123)
|
||||||
|
|
|
@ -1249,7 +1249,7 @@ def _no_init(self, *args, **kwargs):
|
||||||
raise TypeError('Protocols cannot be instantiated')
|
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.
|
"""Allow instance and class checks for special stdlib modules.
|
||||||
|
|
||||||
The abc and functools modules indiscriminately call isinstance() and
|
The abc and functools modules indiscriminately call isinstance() and
|
||||||
|
@ -1338,12 +1338,12 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
|
||||||
|
|
||||||
# First, perform various sanity checks.
|
# First, perform various sanity checks.
|
||||||
if not getattr(cls, '_is_runtime_protocol', False):
|
if not getattr(cls, '_is_runtime_protocol', False):
|
||||||
if _allow_reckless_class_cheks():
|
if _allow_reckless_class_checks():
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
raise TypeError("Instance and class checks can only be used with"
|
raise TypeError("Instance and class checks can only be used with"
|
||||||
" @runtime_checkable protocols")
|
" @runtime_checkable protocols")
|
||||||
if not _is_callable_members_only(cls):
|
if not _is_callable_members_only(cls):
|
||||||
if _allow_reckless_class_cheks():
|
if _allow_reckless_class_checks():
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
raise TypeError("Protocols with non-method members"
|
raise TypeError("Protocols with non-method members"
|
||||||
" don't support issubclass()")
|
" don't support issubclass()")
|
||||||
|
|
|
@ -773,7 +773,11 @@ def _parse_proxy(proxy):
|
||||||
raise ValueError("proxy URL with no authority: %r" % proxy)
|
raise ValueError("proxy URL with no authority: %r" % proxy)
|
||||||
# We have an authority, so for RFC 3986-compliant URLs (by ss 3.
|
# We have an authority, so for RFC 3986-compliant URLs (by ss 3.
|
||||||
# and 3.3.), path is empty or starts with '/'
|
# and 3.3.), path is empty or starts with '/'
|
||||||
end = r_scheme.find("/", 2)
|
if '@' in r_scheme:
|
||||||
|
host_separator = r_scheme.find('@')
|
||||||
|
end = r_scheme.find("/", host_separator)
|
||||||
|
else:
|
||||||
|
end = r_scheme.find("/", 2)
|
||||||
if end == -1:
|
if end == -1:
|
||||||
end = None
|
end = None
|
||||||
authority = r_scheme[2:end]
|
authority = r_scheme[2:end]
|
||||||
|
|
|
@ -1784,7 +1784,7 @@ instead of an OrderedDict.
|
||||||
.. nonce: Q0ktFC
|
.. nonce: Q0ktFC
|
||||||
.. section: Library
|
.. 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
|
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
|
handle were ever to cause an exception, the others will now be closed
|
||||||
instead of leaked. (patch by Giampaolo Rodola)
|
instead of leaked. (patch by Giampaolo Rodola)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Convert functools module to use :c:func:`PyType_FromModuleAndSpec`.
|
|
@ -0,0 +1,2 @@
|
||||||
|
:mod:`subprocess` *extra_groups* is now correctly passed into setgroups()
|
||||||
|
system call.
|
|
@ -0,0 +1 @@
|
||||||
|
Allow / character in username, password fields on _PROXY envars.
|
|
@ -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.
|
|
@ -24,9 +24,37 @@ typedef struct {
|
||||||
vectorcallfunc vectorcall;
|
vectorcallfunc vectorcall;
|
||||||
} partialobject;
|
} 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 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 *
|
static PyObject *
|
||||||
partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
|
@ -42,7 +70,11 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
|
|
||||||
pargs = pkw = NULL;
|
pargs = pkw = NULL;
|
||||||
func = PyTuple_GET_ITEM(args, 0);
|
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;
|
partialobject *part = (partialobject *)func;
|
||||||
if (part->dict == NULL) {
|
if (part->dict == NULL) {
|
||||||
pargs = part->args;
|
pargs = part->args;
|
||||||
|
@ -117,6 +149,7 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
static void
|
static void
|
||||||
partial_dealloc(partialobject *pto)
|
partial_dealloc(partialobject *pto)
|
||||||
{
|
{
|
||||||
|
PyTypeObject *tp = Py_TYPE(pto);
|
||||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||||
PyObject_GC_UnTrack(pto);
|
PyObject_GC_UnTrack(pto);
|
||||||
if (pto->weakreflist != NULL)
|
if (pto->weakreflist != NULL)
|
||||||
|
@ -125,7 +158,8 @@ partial_dealloc(partialobject *pto)
|
||||||
Py_XDECREF(pto->args);
|
Py_XDECREF(pto->args);
|
||||||
Py_XDECREF(pto->kw);
|
Py_XDECREF(pto->kw);
|
||||||
Py_XDECREF(pto->dict);
|
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"},
|
"tuple of arguments to future partial calls"},
|
||||||
{"keywords", T_OBJECT, OFF(kw), READONLY,
|
{"keywords", T_OBJECT, OFF(kw), READONLY,
|
||||||
"dictionary of keyword arguments to future partial calls"},
|
"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 */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -420,49 +460,28 @@ static PyMethodDef partial_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyTypeObject partial_type = {
|
static PyType_Slot partial_type_slots[] = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
{Py_tp_dealloc, partial_dealloc},
|
||||||
"functools.partial", /* tp_name */
|
{Py_tp_repr, partial_repr},
|
||||||
sizeof(partialobject), /* tp_basicsize */
|
{Py_tp_call, partial_call},
|
||||||
0, /* tp_itemsize */
|
{Py_tp_getattro, PyObject_GenericGetAttr},
|
||||||
/* methods */
|
{Py_tp_setattro, PyObject_GenericSetAttr},
|
||||||
(destructor)partial_dealloc, /* tp_dealloc */
|
{Py_tp_doc, (void *)partial_doc},
|
||||||
offsetof(partialobject, vectorcall),/* tp_vectorcall_offset */
|
{Py_tp_traverse, partial_traverse},
|
||||||
0, /* tp_getattr */
|
{Py_tp_methods, partial_methods},
|
||||||
0, /* tp_setattr */
|
{Py_tp_members, partial_memberlist},
|
||||||
0, /* tp_as_async */
|
{Py_tp_getset, partial_getsetlist},
|
||||||
(reprfunc)partial_repr, /* tp_repr */
|
{Py_tp_new, partial_new},
|
||||||
0, /* tp_as_number */
|
{Py_tp_free, PyObject_GC_Del},
|
||||||
0, /* tp_as_sequence */
|
{0, 0}
|
||||||
0, /* tp_as_mapping */
|
};
|
||||||
0, /* tp_hash */
|
|
||||||
(ternaryfunc)partial_call, /* tp_call */
|
static PyType_Spec partial_type_spec = {
|
||||||
0, /* tp_str */
|
.name = "functools.partial",
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
.basicsize = sizeof(partialobject),
|
||||||
PyObject_GenericSetAttr, /* tp_setattro */
|
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||||
0, /* tp_as_buffer */
|
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
.slots = partial_type_slots
|
||||||
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 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -474,12 +493,21 @@ typedef struct {
|
||||||
PyObject *object;
|
PyObject *object;
|
||||||
} keyobject;
|
} keyobject;
|
||||||
|
|
||||||
|
static int
|
||||||
|
keyobject_clear(keyobject *ko)
|
||||||
|
{
|
||||||
|
Py_CLEAR(ko->cmp);
|
||||||
|
Py_CLEAR(ko->object);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
keyobject_dealloc(keyobject *ko)
|
keyobject_dealloc(keyobject *ko)
|
||||||
{
|
{
|
||||||
Py_DECREF(ko->cmp);
|
PyTypeObject *tp = Py_TYPE(ko);
|
||||||
Py_XDECREF(ko->object);
|
keyobject_clear(ko);
|
||||||
PyObject_Free(ko);
|
PyObject_Free(ko);
|
||||||
|
Py_DECREF(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -490,15 +518,6 @@ keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
|
||||||
return 0;
|
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[] = {
|
static PyMemberDef keyobject_members[] = {
|
||||||
{"obj", T_OBJECT,
|
{"obj", T_OBJECT,
|
||||||
offsetof(keyobject, object), 0,
|
offsetof(keyobject, object), 0,
|
||||||
|
@ -512,38 +531,22 @@ keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
keyobject_richcompare(PyObject *ko, PyObject *other, int op);
|
keyobject_richcompare(PyObject *ko, PyObject *other, int op);
|
||||||
|
|
||||||
static PyTypeObject keyobject_type = {
|
static PyType_Slot keyobject_type_slots[] = {
|
||||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
{Py_tp_dealloc, keyobject_dealloc},
|
||||||
"functools.KeyWrapper", /* tp_name */
|
{Py_tp_call, keyobject_call},
|
||||||
sizeof(keyobject), /* tp_basicsize */
|
{Py_tp_getattro, PyObject_GenericGetAttr},
|
||||||
0, /* tp_itemsize */
|
{Py_tp_traverse, keyobject_traverse},
|
||||||
/* methods */
|
{Py_tp_clear, keyobject_clear},
|
||||||
(destructor)keyobject_dealloc, /* tp_dealloc */
|
{Py_tp_richcompare, keyobject_richcompare},
|
||||||
0, /* tp_vectorcall_offset */
|
{Py_tp_members, keyobject_members},
|
||||||
0, /* tp_getattr */
|
{0, 0}
|
||||||
0, /* tp_setattr */
|
};
|
||||||
0, /* tp_as_async */
|
|
||||||
0, /* tp_repr */
|
static PyType_Spec keyobject_type_spec = {
|
||||||
0, /* tp_as_number */
|
.name = "functools.KeyWrapper",
|
||||||
0, /* tp_as_sequence */
|
.basicsize = sizeof(keyobject),
|
||||||
0, /* tp_as_mapping */
|
.flags = Py_TPFLAGS_DEFAULT,
|
||||||
0, /* tp_hash */
|
.slots = keyobject_type_slots
|
||||||
(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 PyObject *
|
static PyObject *
|
||||||
|
@ -555,9 +558,11 @@ keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
|
||||||
return NULL;
|
return NULL;
|
||||||
result = PyObject_New(keyobject, &keyobject_type);
|
|
||||||
if (!result)
|
result = PyObject_New(keyobject, Py_TYPE(ko));
|
||||||
|
if (result == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
Py_INCREF(ko->cmp);
|
Py_INCREF(ko->cmp);
|
||||||
result->cmp = ko->cmp;
|
result->cmp = ko->cmp;
|
||||||
Py_INCREF(object);
|
Py_INCREF(object);
|
||||||
|
@ -575,7 +580,7 @@ keyobject_richcompare(PyObject *ko, PyObject *other, int op)
|
||||||
PyObject *answer;
|
PyObject *answer;
|
||||||
PyObject* stack[2];
|
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");
|
PyErr_Format(PyExc_TypeError, "other argument must be K instance");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -609,10 +614,13 @@ functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
PyObject *cmp;
|
PyObject *cmp;
|
||||||
static char *kwargs[] = {"mycmp", NULL};
|
static char *kwargs[] = {"mycmp", NULL};
|
||||||
keyobject *object;
|
keyobject *object;
|
||||||
|
_functools_state *state;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
|
||||||
return NULL;
|
return NULL;
|
||||||
object = PyObject_New(keyobject, &keyobject_type);
|
|
||||||
|
state = get_functools_state(self);
|
||||||
|
object = PyObject_New(keyobject, state->keyobject_type);
|
||||||
if (!object)
|
if (!object)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_INCREF(cmp);
|
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_list_elem;
|
||||||
struct lru_cache_object;
|
struct lru_cache_object;
|
||||||
|
|
||||||
|
@ -746,33 +750,23 @@ typedef struct lru_list_elem {
|
||||||
static void
|
static void
|
||||||
lru_list_elem_dealloc(lru_list_elem *link)
|
lru_list_elem_dealloc(lru_list_elem *link)
|
||||||
{
|
{
|
||||||
|
PyTypeObject *tp = Py_TYPE(link);
|
||||||
Py_XDECREF(link->key);
|
Py_XDECREF(link->key);
|
||||||
Py_XDECREF(link->result);
|
Py_XDECREF(link->result);
|
||||||
PyObject_Free(link);
|
PyObject_Free(link);
|
||||||
|
Py_DECREF(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyTypeObject lru_list_elem_type = {
|
static PyType_Slot lru_list_elem_type_slots[] = {
|
||||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
{Py_tp_dealloc, lru_list_elem_dealloc},
|
||||||
"functools._lru_list_elem", /* tp_name */
|
{0, 0}
|
||||||
sizeof(lru_list_elem), /* tp_basicsize */
|
};
|
||||||
0, /* tp_itemsize */
|
|
||||||
/* methods */
|
static PyType_Spec lru_list_elem_type_spec = {
|
||||||
(destructor)lru_list_elem_dealloc, /* tp_dealloc */
|
.name = "functools._lru_list_elem",
|
||||||
0, /* tp_vectorcall_offset */
|
.basicsize = sizeof(lru_list_elem),
|
||||||
0, /* tp_getattr */
|
.flags = Py_TPFLAGS_DEFAULT,
|
||||||
0, /* tp_setattr */
|
.slots = lru_list_elem_type_slots
|
||||||
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 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -792,10 +786,9 @@ typedef struct lru_cache_object {
|
||||||
PyObject *weakreflist;
|
PyObject *weakreflist;
|
||||||
} lru_cache_object;
|
} lru_cache_object;
|
||||||
|
|
||||||
static PyTypeObject lru_cache_type;
|
|
||||||
|
|
||||||
static PyObject *
|
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;
|
PyObject *key, *keyword, *value;
|
||||||
Py_ssize_t key_size, pos, key_pos, kwds_size;
|
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);
|
PyTuple_SET_ITEM(key, key_pos++, item);
|
||||||
}
|
}
|
||||||
if (kwds_size) {
|
if (kwds_size) {
|
||||||
Py_INCREF(kwd_mark);
|
Py_INCREF(state->kwd_mark);
|
||||||
PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
|
PyTuple_SET_ITEM(key, key_pos++, state->kwd_mark);
|
||||||
for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
|
for (pos = 0; PyDict_Next(kwds, &pos, &keyword, &value);) {
|
||||||
Py_INCREF(keyword);
|
Py_INCREF(keyword);
|
||||||
PyTuple_SET_ITEM(key, key_pos++, 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;
|
PyObject *result;
|
||||||
Py_hash_t hash;
|
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)
|
if (!key)
|
||||||
return NULL;
|
return NULL;
|
||||||
hash = PyObject_Hash(key);
|
hash = PyObject_Hash(key);
|
||||||
|
@ -979,8 +977,13 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
|
||||||
lru_list_elem *link;
|
lru_list_elem *link;
|
||||||
PyObject *key, *result, *testresult;
|
PyObject *key, *result, *testresult;
|
||||||
Py_hash_t hash;
|
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)
|
if (!key)
|
||||||
return NULL;
|
return NULL;
|
||||||
hash = PyObject_Hash(key);
|
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 */
|
/* Cache is not full, so put the result in a new link */
|
||||||
link = (lru_list_elem *)PyObject_New(lru_list_elem,
|
link = (lru_list_elem *)PyObject_New(lru_list_elem,
|
||||||
&lru_list_elem_type);
|
state->lru_list_elem_type);
|
||||||
if (link == NULL) {
|
if (link == NULL) {
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
Py_DECREF(result);
|
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
|
static void
|
||||||
lru_cache_dealloc(lru_cache_object *obj)
|
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 */
|
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||||
PyObject_GC_UnTrack(obj);
|
PyObject_GC_UnTrack(obj);
|
||||||
if (obj->weakreflist != NULL)
|
if (obj->weakreflist != NULL) {
|
||||||
PyObject_ClearWeakRefs((PyObject*)obj);
|
PyObject_ClearWeakRefs((PyObject*)obj);
|
||||||
|
}
|
||||||
|
|
||||||
list = lru_cache_unlink_list(obj);
|
lru_cache_tp_clear(obj);
|
||||||
Py_XDECREF(obj->cache);
|
tp->tp_free(obj);
|
||||||
Py_XDECREF(obj->func);
|
Py_DECREF(tp);
|
||||||
Py_XDECREF(obj->cache_info_type);
|
|
||||||
Py_XDECREF(obj->dict);
|
|
||||||
lru_cache_clear_list(list);
|
|
||||||
Py_TYPE(obj)->tp_free(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1323,18 +1335,6 @@ lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
|
||||||
return 0;
|
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,
|
PyDoc_STRVAR(lru_cache_doc,
|
||||||
"Create a cached callable that wraps another function.\n\
|
"Create a cached callable that wraps another function.\n\
|
||||||
|
@ -1366,51 +1366,37 @@ static PyGetSetDef lru_cache_getsetlist[] = {
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyTypeObject lru_cache_type = {
|
static PyMemberDef lru_cache_memberlist[] = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
{"__dictoffset__", T_PYSSIZET,
|
||||||
"functools._lru_cache_wrapper", /* tp_name */
|
offsetof(lru_cache_object, dict), READONLY},
|
||||||
sizeof(lru_cache_object), /* tp_basicsize */
|
{"__weaklistoffset__", T_PYSSIZET,
|
||||||
0, /* tp_itemsize */
|
offsetof(lru_cache_object, weakreflist), READONLY},
|
||||||
/* methods */
|
{NULL} /* Sentinel */
|
||||||
(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 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 ********************************************************/
|
/* module level code ********************************************************/
|
||||||
|
|
||||||
PyDoc_STRVAR(_functools_doc,
|
PyDoc_STRVAR(_functools_doc,
|
||||||
|
@ -1423,38 +1409,83 @@ static PyMethodDef _functools_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{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
|
static int
|
||||||
_functools_exec(PyObject *module)
|
_functools_exec(PyObject *module)
|
||||||
{
|
{
|
||||||
PyTypeObject *typelist[] = {
|
_functools_state *state = get_functools_state(module);
|
||||||
&partial_type,
|
state->kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
|
||||||
&lru_cache_type
|
if (state->kwd_mark == NULL) {
|
||||||
};
|
return -1;
|
||||||
|
|
||||||
if (!kwd_mark) {
|
|
||||||
kwd_mark = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type);
|
|
||||||
if (!kwd_mark) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) {
|
state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
|
||||||
if (PyModule_AddType(module, typelist[i]) < 0) {
|
&partial_type_spec, NULL);
|
||||||
return -1;
|
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;
|
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[] = {
|
static struct PyModuleDef_Slot _functools_slots[] = {
|
||||||
{Py_mod_exec, _functools_exec},
|
{Py_mod_exec, _functools_exec},
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
|
@ -1462,14 +1493,14 @@ static struct PyModuleDef_Slot _functools_slots[] = {
|
||||||
|
|
||||||
static struct PyModuleDef _functools_module = {
|
static struct PyModuleDef _functools_module = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"_functools",
|
.m_name = "_functools",
|
||||||
_functools_doc,
|
.m_doc = _functools_doc,
|
||||||
0,
|
.m_size = sizeof(_functools_state),
|
||||||
_functools_methods,
|
.m_methods = _functools_methods,
|
||||||
_functools_slots,
|
.m_slots = _functools_slots,
|
||||||
NULL,
|
.m_traverse = _functools_traverse,
|
||||||
NULL,
|
.m_clear = _functools_clear,
|
||||||
_functools_free,
|
.m_free = _functools_free,
|
||||||
};
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
|
|
|
@ -900,7 +900,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
|
||||||
if (groups_list != Py_None) {
|
if (groups_list != Py_None) {
|
||||||
#ifdef HAVE_SETGROUPS
|
#ifdef HAVE_SETGROUPS
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
unsigned long gid;
|
gid_t gid;
|
||||||
|
|
||||||
if (!PyList_Check(groups_list)) {
|
if (!PyList_Check(groups_list)) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
@ -934,10 +934,6 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
|
||||||
Py_DECREF(elem);
|
Py_DECREF(elem);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else {
|
} 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)) {
|
if (!_Py_Gid_Converter(elem, &gid)) {
|
||||||
Py_DECREF(elem);
|
Py_DECREF(elem);
|
||||||
PyErr_SetString(PyExc_ValueError, "invalid group id");
|
PyErr_SetString(PyExc_ValueError, "invalid group id");
|
||||||
|
|
|
@ -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]*/
|
|
@ -23,6 +23,13 @@
|
||||||
|
|
||||||
#include "row.h"
|
#include "row.h"
|
||||||
#include "cursor.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)
|
void pysqlite_row_dealloc(pysqlite_Row* self)
|
||||||
{
|
{
|
||||||
|
@ -35,30 +42,25 @@ void pysqlite_row_dealloc(pysqlite_Row* self)
|
||||||
Py_DECREF(tp);
|
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 *
|
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;
|
pysqlite_Row *self;
|
||||||
PyObject* data;
|
|
||||||
pysqlite_Cursor* cursor;
|
|
||||||
|
|
||||||
assert(type != NULL && type->tp_alloc != NULL);
|
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);
|
self = (pysqlite_Row *) type->tp_alloc(type, 0);
|
||||||
if (self == NULL)
|
if (self == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -153,7 +155,15 @@ pysqlite_row_length(pysqlite_Row* self)
|
||||||
return PyTuple_GET_SIZE(self->data);
|
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;
|
PyObject* list;
|
||||||
Py_ssize_t nitems, i;
|
Py_ssize_t nitems, i;
|
||||||
|
@ -204,8 +214,7 @@ static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other,
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef row_methods[] = {
|
static PyMethodDef row_methods[] = {
|
||||||
{"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
|
PYSQLITE_ROW_KEYS_METHODDEF
|
||||||
PyDoc_STR("Returns the keys of the row.")},
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -672,7 +672,7 @@ _PyLong_FromGid(gid_t gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_Py_Uid_Converter(PyObject *obj, void *p)
|
_Py_Uid_Converter(PyObject *obj, uid_t *p)
|
||||||
{
|
{
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
PyObject *index;
|
PyObject *index;
|
||||||
|
@ -759,7 +759,7 @@ _Py_Uid_Converter(PyObject *obj, void *p)
|
||||||
|
|
||||||
success:
|
success:
|
||||||
Py_DECREF(index);
|
Py_DECREF(index);
|
||||||
*(uid_t *)p = uid;
|
*p = uid;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
underflow:
|
underflow:
|
||||||
|
@ -778,7 +778,7 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_Py_Gid_Converter(PyObject *obj, void *p)
|
_Py_Gid_Converter(PyObject *obj, gid_t *p)
|
||||||
{
|
{
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
PyObject *index;
|
PyObject *index;
|
||||||
|
@ -866,7 +866,7 @@ _Py_Gid_Converter(PyObject *obj, void *p)
|
||||||
|
|
||||||
success:
|
success:
|
||||||
Py_DECREF(index);
|
Py_DECREF(index);
|
||||||
*(gid_t *)p = gid;
|
*p = gid;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
underflow:
|
underflow:
|
||||||
|
|
|
@ -14,8 +14,8 @@ extern "C" {
|
||||||
#ifndef MS_WINDOWS
|
#ifndef MS_WINDOWS
|
||||||
PyAPI_FUNC(PyObject *) _PyLong_FromUid(uid_t);
|
PyAPI_FUNC(PyObject *) _PyLong_FromUid(uid_t);
|
||||||
PyAPI_FUNC(PyObject *) _PyLong_FromGid(gid_t);
|
PyAPI_FUNC(PyObject *) _PyLong_FromGid(gid_t);
|
||||||
PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, void *);
|
PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, uid_t *);
|
||||||
PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, void *);
|
PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, gid_t *);
|
||||||
#endif /* MS_WINDOWS */
|
#endif /* MS_WINDOWS */
|
||||||
|
|
||||||
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \
|
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \
|
||||||
|
|
|
@ -51,7 +51,7 @@ extern char **completion_matches(char *, CPFunction *);
|
||||||
*
|
*
|
||||||
* This emulation library is not 100% API compatible with the "real" readline
|
* This emulation library is not 100% API compatible with the "real" readline
|
||||||
* and cannot be detected at compile-time,
|
* 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.
|
* linked to libedit.
|
||||||
*
|
*
|
||||||
* Currently there is one known API incompatibility:
|
* Currently there is one known API incompatibility:
|
||||||
|
|
Loading…
Reference in New Issue