Skip to content

Commit 75158fb

Browse files
committed
[multiprocessing] Fix return types of Value and Array
The stubs did not match what CPython returns: - With `lock=False`, `Value` and `Array` return the raw ctypes object. `BaseContext.Value` claimed `Synchronized[_CT]` instead of `_CT`, and both `Array` stubs returned something other than `ctypes.Array[_CT]`. - `sharedctypes.Value` returned `SynchronizedBase` for simple C types and typecode strings, hiding the `value` attribute that the runtime `Synchronized` wrapper provides. - `BaseContext.Value` returned `Synchronized[_CT]` for other ctypes such as structures. These are wrapped in a `SynchronizedBase` subclass that has no `value` attribute. Make both modules match the runtime and each other. Fixes #10319
1 parent 5d9cd84 commit 75158fb

3 files changed

Lines changed: 32 additions & 10 deletions

File tree

‎stdlib/@tests/test_cases/multiprocessing/check_ctypes.py‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
from __future__ import annotations
22

3-
from ctypes import c_char, c_float, c_int
4-
from multiprocessing import Array, Value
5-
from multiprocessing.sharedctypes import Synchronized, SynchronizedArray, SynchronizedString
3+
import ctypes
4+
from ctypes import Structure, c_char, c_float, c_int
5+
from multiprocessing import Array, Value, sharedctypes
6+
from multiprocessing.sharedctypes import Synchronized, SynchronizedArray, SynchronizedBase, SynchronizedString
7+
from typing import Any
68
from typing_extensions import assert_type
79

10+
11+
class Point(Structure):
12+
_fields_ = [("x", c_int), ("y", c_int)]
13+
14+
815
string = Array(c_char, 12)
916
assert_type(string, SynchronizedString)
1017
assert_type(string.value, bytes)
@@ -17,3 +24,14 @@
1724
field = Value(c_float, 0.0)
1825
assert_type(field, Synchronized[float])
1926
field.value = 1.2
27+
28+
assert_type(Value("i", 0), Synchronized[Any])
29+
assert_type(Value(c_int, 0, lock=False), c_int)
30+
assert_type(Value(Point), SynchronizedBase[Point])
31+
assert_type(Array(c_int, 3, lock=False), ctypes.Array[c_int])
32+
33+
assert_type(sharedctypes.Value(c_int, 0), Synchronized[int])
34+
assert_type(sharedctypes.Value("i", 0), Synchronized[Any])
35+
assert_type(sharedctypes.Value(c_int, 0, lock=False), c_int)
36+
assert_type(sharedctypes.Value(Point), SynchronizedBase[Point])
37+
assert_type(sharedctypes.Array(c_int, 3, lock=False), ctypes.Array[c_int])

‎stdlib/multiprocessing/context.pyi‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ from multiprocessing import popen_fork, popen_forkserver, popen_spawn_posix, pop
88
from multiprocessing.managers import SyncManager
99
from multiprocessing.pool import Pool as _Pool
1010
from multiprocessing.process import BaseProcess
11-
from multiprocessing.sharedctypes import Synchronized, SynchronizedArray, SynchronizedString
11+
from multiprocessing.sharedctypes import Synchronized, SynchronizedArray, SynchronizedBase, SynchronizedString
1212
from typing import Any, ClassVar, Literal, TypeAlias, TypeVar, overload
1313

1414
if sys.platform != "win32":
@@ -90,18 +90,18 @@ class BaseContext:
9090
self, typecode_or_type: type[_SimpleCData[_T]], *args: Any, lock: Literal[True] | _LockLike = True
9191
) -> Synchronized[_T]: ...
9292
@overload
93-
def Value(self, typecode_or_type: type[_CT], *args: Any, lock: Literal[False]) -> Synchronized[_CT]: ...
93+
def Value(self, typecode_or_type: type[_CT], *args: Any, lock: Literal[False]) -> _CT: ...
9494
@overload
95-
def Value(self, typecode_or_type: type[_CT], *args: Any, lock: Literal[True] | _LockLike = True) -> Synchronized[_CT]: ...
95+
def Value(self, typecode_or_type: type[_CT], *args: Any, lock: Literal[True] | _LockLike = True) -> SynchronizedBase[_CT]: ...
9696
@overload
9797
def Value(self, typecode_or_type: str, *args: Any, lock: Literal[True] | _LockLike = True) -> Synchronized[Any]: ...
9898
@overload
9999
def Value(self, typecode_or_type: str | type[_CData], *args: Any, lock: bool | _LockLike = True) -> Any: ...
100100

101101
@overload
102102
def Array(
103-
self, typecode_or_type: type[_SimpleCData[_T]], size_or_initializer: int | Sequence[Any], *, lock: Literal[False]
104-
) -> SynchronizedArray[_T]: ...
103+
self, typecode_or_type: type[_CT], size_or_initializer: int | Sequence[Any], *, lock: Literal[False]
104+
) -> ctypes.Array[_CT]: ...
105105
@overload
106106
def Array(
107107
self, typecode_or_type: type[c_char], size_or_initializer: int | Sequence[Any], *, lock: Literal[True] | _LockLike = True

‎stdlib/multiprocessing/sharedctypes.pyi‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ def RawArray(typecode_or_type: str, size_or_initializer: int | Sequence[Any]) ->
2525
@overload
2626
def Value(typecode_or_type: type[_CT], *args: Any, lock: Literal[False], ctx: BaseContext | None = None) -> _CT: ...
2727
@overload
28+
def Value(
29+
typecode_or_type: type[_SimpleCData[_T]], *args: Any, lock: Literal[True] | _LockLike = True, ctx: BaseContext | None = None
30+
) -> Synchronized[_T]: ...
31+
@overload
2832
def Value(
2933
typecode_or_type: type[_CT], *args: Any, lock: Literal[True] | _LockLike = True, ctx: BaseContext | None = None
3034
) -> SynchronizedBase[_CT]: ...
3135
@overload
3236
def Value(
3337
typecode_or_type: str, *args: Any, lock: Literal[True] | _LockLike = True, ctx: BaseContext | None = None
34-
) -> SynchronizedBase[Any]: ...
38+
) -> Synchronized[Any]: ...
3539
@overload
3640
def Value(
3741
typecode_or_type: str | type[_CData], *args: Any, lock: bool | _LockLike = True, ctx: BaseContext | None = None
@@ -40,7 +44,7 @@ def Value(
4044
@overload
4145
def Array(
4246
typecode_or_type: type[_CT], size_or_initializer: int | Sequence[Any], *, lock: Literal[False], ctx: BaseContext | None = None
43-
) -> _CT: ...
47+
) -> ctypes.Array[_CT]: ...
4448
@overload
4549
def Array(
4650
typecode_or_type: type[c_char],

0 commit comments

Comments
 (0)