Skip to content

Commit 6b55f5c

Browse files
authored
Clean up multiprocessing + shared_memory (#3351)
* Make multiprocessing stubs match implementation * Add multiprocessing.process.BaseProcess * Use BaseProcess in multiprocessing.context where applicable * Remove non-existing BaseContext.Process() * Derive DefaultContext from BaseContext * Fix BaseContext/DefaultContext.set_start_method() signatures * Re-export multiprocessing.context.Process from multiprocessing, instead of using a custom definition * Re-export multiprocessing.active_from from multiprocessing.process instead of using a custom definition * Add parent_process() (Python 3.8) * Complete BaseManager; add Server * Add multiprocessing.shared_memory et al
1 parent 0501e2b commit 6b55f5c

File tree

5 files changed

+125
-70
lines changed

5 files changed

+125
-70
lines changed

stdlib/3/multiprocessing/__init__.pyi

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
# Stubs for multiprocessing
22

3+
import sys
34
from typing import Any, Callable, Iterable, Mapping, Optional, List, Union, Sequence, Tuple, Type, overload
45

56
from ctypes import _CData
67
from logging import Logger
78
from multiprocessing import connection, pool, spawn, synchronize
89
from multiprocessing.context import (
10+
AuthenticationError as AuthenticationError,
911
BaseContext,
10-
ProcessError as ProcessError, BufferTooShort as BufferTooShort, TimeoutError as TimeoutError, AuthenticationError as AuthenticationError)
12+
BufferTooShort as BufferTooShort,
13+
Process as Process,
14+
ProcessError as ProcessError,
15+
TimeoutError as TimeoutError,
16+
)
1117
from multiprocessing.managers import SyncManager
12-
from multiprocessing.process import current_process as current_process
18+
from multiprocessing.process import active_children as active_children, current_process as current_process
1319
from multiprocessing.queues import Queue as Queue, SimpleQueue as SimpleQueue, JoinableQueue as JoinableQueue
1420
from multiprocessing.spawn import freeze_support as freeze_support
1521
from multiprocessing.spawn import set_executable as set_executable
1622

17-
import sys
23+
if sys.version_info >= (3, 8):
24+
from multiprocessing.process import parent_process as parent_process
1825

1926
# N.B. The functions below are generated at runtime by partially applying
2027
# multiprocessing.context.BaseContext's methods, so the two signatures should
@@ -39,31 +46,6 @@ def Pool(processes: Optional[int] = ...,
3946
initargs: Iterable[Any] = ...,
4047
maxtasksperchild: Optional[int] = ...) -> pool.Pool: ...
4148

42-
class Process():
43-
name: str
44-
daemon: bool
45-
pid: Optional[int]
46-
exitcode: Optional[int]
47-
authkey: bytes
48-
sentinel: int
49-
# TODO: set type of group to None
50-
def __init__(self,
51-
group: Any = ...,
52-
target: Optional[Callable[..., Any]] = ...,
53-
name: Optional[str] = ...,
54-
args: Iterable[Any] = ...,
55-
kwargs: Mapping[Any, Any] = ...,
56-
*,
57-
daemon: Optional[bool] = ...) -> None: ...
58-
def start(self) -> None: ...
59-
def run(self) -> None: ...
60-
def terminate(self) -> None: ...
61-
if sys.version_info >= (3, 7):
62-
def kill(self) -> None: ...
63-
def close(self) -> None: ...
64-
def is_alive(self) -> bool: ...
65-
def join(self, timeout: Optional[float] = ...) -> None: ...
66-
6749
class Array():
6850
value: Any = ...
6951

@@ -90,7 +72,6 @@ class Value():
9072
def release(self) -> bool: ...
9173

9274
# ----- multiprocessing function stubs -----
93-
def active_children() -> List[Process]: ...
9475
def allow_connection_pickling() -> None: ...
9576
def cpu_count() -> int: ...
9677
def get_logger() -> Logger: ...

stdlib/3/multiprocessing/context.pyi

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ from logging import Logger
44
import multiprocessing
55
from multiprocessing import synchronize
66
from multiprocessing import queues
7+
from multiprocessing.process import BaseProcess
78
import sys
89
from typing import Any, Callable, Iterable, Optional, List, Mapping, Sequence, Type, Union
910

@@ -27,9 +28,12 @@ class BaseContext(object):
2728
# multiprocessing.*, so the signatures should be identical (modulo self).
2829

2930
@staticmethod
30-
def current_process() -> multiprocessing.Process: ...
31+
def current_process() -> BaseProcess: ...
32+
if sys.version_info >= (3, 8):
33+
@staticmethod
34+
def parent_process() -> Optional[BaseProcess]: ...
3135
@staticmethod
32-
def active_children() -> List[multiprocessing.Process]: ...
36+
def active_children() -> List[BaseProcess]: ...
3337
def cpu_count(self) -> int: ...
3438
# TODO: change return to SyncManager once a stub exists in multiprocessing.managers
3539
def Manager(self) -> Any: ...
@@ -59,16 +63,6 @@ class BaseContext(object):
5963
initargs: Iterable[Any] = ...,
6064
maxtasksperchild: Optional[int] = ...
6165
) -> multiprocessing.pool.Pool: ...
62-
def Process(
63-
self,
64-
group: Any = ...,
65-
target: Optional[Callable[..., Any]] = ...,
66-
name: Optional[str] = ...,
67-
args: Iterable[Any] = ...,
68-
kwargs: Mapping[Any, Any] = ...,
69-
*,
70-
daemon: Optional[bool] = ...
71-
) -> multiprocessing.Process: ...
7266
# TODO: typecode_or_type param is a ctype with a base class of _SimpleCData or array.typecode Need to figure out
7367
# how to handle the ctype
7468
# TODO: change return to RawValue once a stub exists in multiprocessing.sharedctypes
@@ -104,46 +98,42 @@ class BaseContext(object):
10498
def set_forkserver_preload(self, module_names: List[str]) -> None: ...
10599
def get_context(self, method: Optional[str] = ...) -> BaseContext: ...
106100
def get_start_method(self, allow_none: bool = ...) -> str: ...
107-
def set_start_method(self, method: Optional[str] = ...) -> None: ...
101+
def set_start_method(self, method: Optional[str], force: bool = ...) -> None: ...
108102
@property
109103
def reducer(self) -> str: ...
110104
@reducer.setter
111105
def reducer(self, reduction: str) -> None: ...
112106
def _check_available(self) -> None: ...
113107

114-
class Process(object):
108+
class Process(BaseProcess):
115109
_start_method: Optional[str]
116110
@staticmethod
117-
# TODO: type should be BaseProcess once a stub in multiprocessing.process exists
118-
def _Popen(process_obj: Any) -> DefaultContext: ...
111+
def _Popen(process_obj: BaseProcess) -> DefaultContext: ...
119112

120-
class DefaultContext(object):
113+
class DefaultContext(BaseContext):
121114
Process: Type[multiprocessing.Process]
122115

123116
def __init__(self, context: BaseContext) -> None: ...
124117
def get_context(self, method: Optional[str] = ...) -> BaseContext: ...
125-
def set_start_method(self, method: str, force: bool = ...) -> None: ...
118+
def set_start_method(self, method: Optional[str], force: bool = ...) -> None: ...
126119
def get_start_method(self, allow_none: bool = ...) -> str: ...
127120
def get_all_start_methods(self) -> List[str]: ...
128121

129122
if sys.platform != 'win32':
130-
# TODO: type should be BaseProcess once a stub in multiprocessing.process exists
131-
class ForkProcess(Any):
123+
class ForkProcess(BaseProcess):
132124
_start_method: str
133125
@staticmethod
134-
def _Popen(process_obj: Any) -> Any: ...
126+
def _Popen(process_obj: BaseProcess) -> Any: ...
135127

136-
# TODO: type should be BaseProcess once a stub in multiprocessing.process exists
137-
class SpawnProcess(Any):
128+
class SpawnProcess(BaseProcess):
138129
_start_method: str
139130
@staticmethod
140-
def _Popen(process_obj: Any) -> SpawnProcess: ...
131+
def _Popen(process_obj: BaseProcess) -> SpawnProcess: ...
141132

142-
# TODO: type should be BaseProcess once a stub in multiprocessing.process exists
143-
class ForkServerProcess(Any):
133+
class ForkServerProcess(BaseProcess):
144134
_start_method: str
145135
@staticmethod
146-
def _Popen(process_obj: Any) -> Any: ...
136+
def _Popen(process_obj: BaseProcess) -> Any: ...
147137

148138
class ForkContext(BaseContext):
149139
_name: str
@@ -157,20 +147,16 @@ if sys.platform != 'win32':
157147
_name: str
158148
Process: Type[ForkServerProcess]
159149
else:
160-
# TODO: type should be BaseProcess once a stub in multiprocessing.process exists
161-
class SpawnProcess(Any):
150+
class SpawnProcess(BaseProcess):
162151
_start_method: str
163152
@staticmethod
164-
# TODO: type should be BaseProcess once a stub in multiprocessing.process exists
165-
def _Popen(process_obj: Process) -> Any: ...
153+
def _Popen(process_obj: BaseProcess) -> Any: ...
166154

167155
class SpawnContext(BaseContext):
168156
_name: str
169157
Process: Type[SpawnProcess]
170158

171159
def _force_start_method(method: str) -> None: ...
172-
# TODO: type should be BaseProcess once a stub in multiprocessing.process exists
173160
def get_spawning_popen() -> Optional[Any]: ...
174-
# TODO: type should be BaseProcess once a stub in multiprocessing.process exists
175161
def set_spawning_popen(popen: Any) -> None: ...
176162
def assert_spawning(obj: Any) -> None: ...

stdlib/3/multiprocessing/managers.pyi

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
# NOTE: These are incomplete!
44

55
import queue
6+
import sys
67
import threading
78
from typing import (
89
Any, Callable, ContextManager, Dict, Iterable, Generic, List, Mapping, Optional,
910
Sequence, Tuple, TypeVar, Union,
1011
)
12+
from .context import BaseContext
13+
14+
if sys.version_info >= (3, 8):
15+
from .shared_memory import ShareableList, SharedMemory, _SLT
1116

1217
_T = TypeVar('_T')
1318
_KT = TypeVar('_KT')
@@ -24,18 +29,32 @@ class ValueProxy(BaseProxy, Generic[_T]):
2429
def set(self, value: _T) -> None: ...
2530
value: _T
2631

32+
# Returned by BaseManager.get_server()
33+
class Server:
34+
address: Any
35+
def serve_forever(self) -> None: ...
36+
2737
class BaseManager(ContextManager[BaseManager]):
28-
address: Union[str, Tuple[str, int]]
38+
def __init__(
39+
self,
40+
address: Optional[Any] = ...,
41+
authkey: Optional[bytes] = ...,
42+
serializer: str = ...,
43+
ctx: Optional[BaseContext] = ...,
44+
) -> None: ...
45+
def get_server(self) -> Server: ...
2946
def connect(self) -> None: ...
47+
def start(self, initializer: Optional[Callable[..., Any]] = ..., initargs: Iterable[Any] = ...) -> None: ...
48+
def shutdown(self) -> None: ... # only available after start() was called
49+
def join(self, timeout: Optional[float] = ...) -> None: ... # undocumented
50+
@property
51+
def address(self) -> Any: ...
3052
@classmethod
3153
def register(cls, typeid: str, callable: Optional[Callable[..., Any]] = ...,
3254
proxytype: Any = ...,
3355
exposed: Optional[Sequence[str]] = ...,
3456
method_to_typeid: Optional[Mapping[str, str]] = ...,
3557
create_method: bool = ...) -> None: ...
36-
def shutdown(self) -> None: ...
37-
def start(self, initializer: Optional[Callable[..., Any]] = ...,
38-
initargs: Iterable[Any] = ...) -> None: ...
3958

4059
class SyncManager(BaseManager, ContextManager[SyncManager]):
4160
def BoundedSemaphore(self, value: Any = ...) -> threading.BoundedSemaphore: ...
@@ -52,3 +71,10 @@ class SyncManager(BaseManager, ContextManager[SyncManager]):
5271
def list(self, sequence: Sequence[_T] = ...) -> List[_T]: ...
5372

5473
class RemoteError(Exception): ...
74+
75+
if sys.version_info >= (3, 8):
76+
class SharedMemoryServer(Server): ...
77+
class SharedMemoryManager(BaseManager):
78+
def get_server(self) -> SharedMemoryServer: ...
79+
def SharedMemory(self, size: int) -> SharedMemory: ...
80+
def ShareableList(self, sequence: Optional[Iterable[_SLT]]) -> ShareableList[_SLT]: ...

stdlib/3/multiprocessing/process.pyi

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
1-
from typing import List
2-
from multiprocessing import Process
1+
import sys
2+
from typing import Any, Callable, List, Mapping, Optional, Tuple
33

4-
def current_process() -> Process: ...
5-
def active_children() -> List[Process]: ...
4+
class BaseProcess:
5+
name: str
6+
daemon: bool
7+
authkey: bytes
8+
def __init__(
9+
self,
10+
group: None = ...,
11+
target: Optional[Callable[..., Any]] = ...,
12+
name: Optional[str] = ...,
13+
args: Tuple[Any, ...] = ...,
14+
kwargs: Mapping[str, Any] = ...,
15+
*,
16+
daemon: Optional[bool] = ...,
17+
) -> None: ...
18+
def run(self) -> None: ...
19+
def start(self) -> None: ...
20+
def terminate(self) -> None: ...
21+
if sys.version_info >= (3, 7):
22+
def kill(self) -> None: ...
23+
def close(self) -> None: ...
24+
def join(self, timeout: Optional[float] = ...) -> None: ...
25+
def is_alive(self) -> bool: ...
26+
@property
27+
def exitcode(self) -> Optional[int]: ...
28+
@property
29+
def ident(self) -> Optional[int]: ...
30+
@property
31+
def pid(self) -> Optional[int]: ...
32+
@property
33+
def sentinel(self) -> int: ...
34+
35+
def current_process() -> BaseProcess: ...
36+
def active_children() -> List[BaseProcess]: ...
37+
if sys.version_info >= (3, 8):
38+
def parent_process() -> Optional[BaseProcess]: ...
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import sys
2+
from typing import Generic, Iterable, Optional, Tuple, TypeVar
3+
4+
_S = TypeVar("_S")
5+
_SLT = TypeVar("_SLT", int, float, bool, str, bytes, None)
6+
7+
if sys.version_info >= (3, 8):
8+
class SharedMemory:
9+
def __init__(self, name: Optional[str] = ..., create: bool = ..., size: int = ...) -> None: ...
10+
@property
11+
def buf(self) -> memoryview: ...
12+
@property
13+
def name(self) -> str: ...
14+
@property
15+
def size(self) -> int: ...
16+
def close(self) -> None: ...
17+
def unlink(self) -> None: ...
18+
19+
class ShareableList(Generic[_SLT]):
20+
shm: SharedMemory
21+
def __init__(self, sequence: Optional[Iterable[_SLT]] = ..., *, name: Optional[str] = ...) -> None: ...
22+
def __getitem__(self, position: int) -> _SLT: ...
23+
def __setitem__(self, position: int, value: _SLT) -> None: ...
24+
def __reduce__(self: _S) -> Tuple[_S, Tuple[_SLT, ...]]: ...
25+
def __len__(self) -> int: ...
26+
@property
27+
def format(self) -> str: ...
28+
def count(self, value: _SLT) -> int: ...
29+
def index(self, value: _SLT) -> int: ...

0 commit comments

Comments
 (0)