Skip to content

Commit 4529493

Browse files
committed
gh-102029: Sync __new__ sigs of _CRLock and _PyRLock in threading
1 parent b1b375e commit 4529493

File tree

6 files changed

+54
-5
lines changed

6 files changed

+54
-5
lines changed

Doc/whatsnew/3.12.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,12 @@ threading
332332
profiling functions in all running threads in addition to the calling one.
333333
(Contributed by Pablo Galindo in :gh:`93503`.)
334334

335+
* Passing any arguments to :func:`threading.RLock` is now restricted.
336+
Previously C version allowed any numbers of args and kwargs,
337+
but they were just ignored. Python version never allowed any arguments.
338+
Now, these two implementation match.
339+
(Contributed by Nikita Sobolev in :gh:`102029`.)
340+
335341
unicodedata
336342
-----------
337343

Lib/test/lock_tests.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ def use_lock(lock):
293293
use_lock(lock2)
294294

295295

296-
class RLockTests(BaseLockTests):
296+
class RLockAPITests(BaseLockTests):
297297
"""
298298
Tests for recursive locks.
299299
"""
@@ -360,6 +360,31 @@ def f():
360360
self.assertFalse(lock._is_owned())
361361

362362

363+
class RLockTests(RLockAPITests):
364+
def test_signature(self): # gh-102029
365+
# 0 args are fine:
366+
self.locktype()
367+
self.locktype(*(), **{})
368+
369+
# no other args are allowed:
370+
arg_types = [
371+
((1,), {}),
372+
((), {'a': 1}),
373+
((1, 2), {'a': 1}),
374+
]
375+
for args, kwargs in arg_types:
376+
with self.subTest(args=args, kwargs=kwargs):
377+
with self.assertRaises(TypeError):
378+
self.locktype(*args, **kwargs)
379+
380+
# Subtypes with custom `__init__` are allowed (but, not recommended):
381+
class CustomRLock(self.locktype):
382+
def __init__(self, a, *, b) -> None:
383+
super().__init__()
384+
385+
CustomRLock(1, b=2)
386+
387+
363388
class EventTests(BaseTestCase):
364389
"""
365390
Tests for Event objects.

Lib/test/test_threading.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1722,7 +1722,7 @@ class CRLockTests(lock_tests.RLockTests):
17221722
class EventTests(lock_tests.EventTests):
17231723
eventtype = staticmethod(threading.Event)
17241724

1725-
class ConditionAsRLockTests(lock_tests.RLockTests):
1725+
class ConditionAsRLockTests(lock_tests.RLockAPITests):
17261726
# Condition uses an RLock by default and exports its API.
17271727
locktype = staticmethod(threading.Condition)
17281728

Lib/threading.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def gettrace():
107107

108108
Lock = _allocate_lock
109109

110-
def RLock(*args, **kwargs):
110+
def RLock():
111111
"""Factory function that returns a new reentrant lock.
112112
113113
A reentrant lock must be released by the thread that acquired it. Once a
@@ -117,8 +117,8 @@ def RLock(*args, **kwargs):
117117
118118
"""
119119
if _CRLock is None:
120-
return _PyRLock(*args, **kwargs)
121-
return _CRLock(*args, **kwargs)
120+
return _PyRLock()
121+
return _CRLock()
122122

123123
class _RLock:
124124
"""This class implements reentrant lock objects.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Sync ``__new__`` signatures of ``threading._CRLock`` and
2+
``threading._PyRLock``. Now they both require 0 arguments.

Modules/_threadmodule.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,22 @@ For internal use by `threading.Condition`.");
505505
static PyObject *
506506
rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
507507
{
508+
// Can later be converted to AC:
509+
if (type->tp_init == PyBaseObject_Type.tp_init) {
510+
int rc = 0;
511+
if (args != NULL)
512+
rc = PyObject_IsTrue(args);
513+
if (rc == 0 && kwds != NULL)
514+
rc = PyObject_IsTrue(kwds);
515+
if (rc != 0) {
516+
if (rc > 0) {
517+
PyErr_SetString(PyExc_TypeError,
518+
"Initialization arguments are not supported");
519+
}
520+
return NULL;
521+
}
522+
}
523+
508524
rlockobject *self = (rlockobject *) type->tp_alloc(type, 0);
509525
if (self == NULL) {
510526
return NULL;

0 commit comments

Comments
 (0)