1from __future__ import annotations
2
3from abc import abstractmethod
4from signal import Signals
5
6from ._resources import AsyncResource
7from ._streams import ByteReceiveStream, ByteSendStream
8
9
10class Process(AsyncResource):
11 """An asynchronous version of :class:`subprocess.Popen`."""
12
13 @abstractmethod
14 async def wait(self) -> int:
15 """
16 Wait until the process exits.
17
18 :return: the exit code of the process
19 """
20
21 @abstractmethod
22 def terminate(self) -> None:
23 """
24 Terminates the process, gracefully if possible.
25
26 On Windows, this calls ``TerminateProcess()``.
27 On POSIX systems, this sends ``SIGTERM`` to the process.
28
29 .. seealso:: :meth:`subprocess.Popen.terminate`
30 """
31
32 @abstractmethod
33 def kill(self) -> None:
34 """
35 Kills the process.
36
37 On Windows, this calls ``TerminateProcess()``.
38 On POSIX systems, this sends ``SIGKILL`` to the process.
39
40 .. seealso:: :meth:`subprocess.Popen.kill`
41 """
42
43 @abstractmethod
44 def send_signal(self, signal: Signals) -> None:
45 """
46 Send a signal to the subprocess.
47
48 .. seealso:: :meth:`subprocess.Popen.send_signal`
49
50 :param signal: the signal number (e.g. :data:`signal.SIGHUP`)
51 """
52
53 @property
54 @abstractmethod
55 def pid(self) -> int:
56 """The process ID of the process."""
57
58 @property
59 @abstractmethod
60 def returncode(self) -> int | None:
61 """
62 The return code of the process. If the process has not yet terminated, this will
63 be ``None``.
64 """
65
66 @property
67 @abstractmethod
68 def stdin(self) -> ByteSendStream | None:
69 """The stream for the standard input of the process."""
70
71 @property
72 @abstractmethod
73 def stdout(self) -> ByteReceiveStream | None:
74 """The stream for the standard output of the process."""
75
76 @property
77 @abstractmethod
78 def stderr(self) -> ByteReceiveStream | None:
79 """The stream for the standard error output of the process."""