Skip to content

Commit f0e9f6e

Browse files
committed
modules: add typing
All code changes should not impact current users. Force Sphinx to use the docstrings from the actual extension modules, otherwise it would only parse the new stub files.
1 parent b8fee31 commit f0e9f6e

File tree

12 files changed

+489
-81
lines changed

12 files changed

+489
-81
lines changed

docs/conf.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
# documentation root, use os.path.abspath to make it absolute, like shown here.
2121
#sys.path.insert(0, os.path.abspath('.'))
2222

23+
# Ignore stub files when generating documentation for extension modules.
24+
os.environ['SPHINX_AUTODOC_IGNORE_NATIVE_MODULE_TYPE_STUBS'] = '1'
25+
2326
# -- General configuration -----------------------------------------------------
2427

2528
# If your documentation needs a minimal Sphinx version, state it here.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ build = [
4343
"meson>=1.8.2",
4444
"twine>=4.0.2",
4545
]
46+
typing = ["mypy"]
4647

4748
[build-system]
4849
requires = ["meson-python"]

src/systemd/_daemon.pyi

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import socket
2+
from typing import Final, SupportsIndex
3+
4+
from typing_extensions import Unpack
5+
from _typeshed import StrOrBytesPath, SupportsLenAndGetItem
6+
7+
__version__: Final[str]
8+
9+
LISTEN_FDS_START: Final[int]
10+
11+
def booted() -> bool: ...
12+
def notify(status: str,
13+
unset_environment: bool = False,
14+
pid: SupportsIndex = 0,
15+
fds: SupportsLenAndGetItem[SupportsIndex] = []) -> bool: ...
16+
def _listen_fds(unset_environment: bool = True) -> int: ...
17+
def _listen_fds_with_names(unset_environment: bool = True) -> tuple[int, Unpack[tuple[str, ...]]]: ...
18+
def _is_fifo(fd: SupportsIndex, path: StrOrBytesPath | None = None, /) -> bool: ...
19+
def _is_mq(fd: SupportsIndex, path: StrOrBytesPath | None = None, /) -> bool: ...
20+
def _is_socket(fd: SupportsIndex,
21+
family: SupportsIndex = socket.AF_UNSPEC,
22+
type: SupportsIndex = 0,
23+
listening: SupportsIndex = -1,
24+
/) -> bool: ...
25+
def _is_socket_inet(fd: SupportsIndex,
26+
family: SupportsIndex = socket.AF_UNSPEC,
27+
type: SupportsIndex = 0,
28+
listening: SupportsIndex = -1,
29+
port: SupportsIndex = 0,
30+
/) -> bool: ...
31+
def _is_socket_sockaddr(fd: SupportsIndex,
32+
address: str,
33+
type: SupportsIndex = 0,
34+
flowinfo: SupportsIndex = 0,
35+
listening: SupportsIndex = -1,
36+
/) -> bool: ...
37+
def _is_socket_unix(fd: SupportsIndex,
38+
type: SupportsIndex = 0,
39+
listening: SupportsIndex = -1,
40+
path: StrOrBytesPath | None = None,
41+
/) -> bool: ...

src/systemd/_journal.pyi

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from typing import Final, SupportsIndex
2+
3+
__version__: Final[str]
4+
5+
def sendv(*args: str | bytes) -> None: ...
6+
def stream_fd(identifier: str,
7+
priority: SupportsIndex,
8+
level_prefix: SupportsIndex) -> int: ...

src/systemd/_reader.pyi

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import datetime
2+
import enum
3+
from types import TracebackType
4+
from typing import Any, Final, SupportsIndex, TypeVar, final, overload
5+
import uuid
6+
7+
from typing_extensions import Self
8+
from _typeshed import structseq, SupportsLenAndGetItem, StrOrBytesPath
9+
10+
_Timestamp = TypeVar("_Timestamp", int, datetime.timedelta)
11+
_Bootid = TypeVar("_Bootid", bytes, uuid.UUID)
12+
13+
__version__: Final[str]
14+
15+
class OpenFlag(enum.IntFlag):
16+
LOCAL_ONLY = ...
17+
RUNTIME_ONLY = ...
18+
SYSTEM = ...
19+
CURRENT_USER = ...
20+
OS_ROOT = ...
21+
ALL_NAMESPACES = ...
22+
INCLUDE_DEFAULT_NAMESPACE = ...
23+
TAKE_DIRECTORY_FD = ...
24+
ASSUME_IMMUTABLE = ...
25+
SYSTEM_ONLY = ...
26+
27+
LOCAL_ONLY = OpenFlag.LOCAL_ONLY
28+
RUNTIME_ONLY = OpenFlag.RUNTIME_ONLY
29+
SYSTEM = OpenFlag.SYSTEM
30+
CURRENT_USER = OpenFlag.CURRENT_USER
31+
OS_ROOT = OpenFlag.OS_ROOT
32+
ALL_NAMESPACES = OpenFlag.ALL_NAMESPACES
33+
INCLUDE_DEFAULT_NAMESPACE = OpenFlag.INCLUDE_DEFAULT_NAMESPACE
34+
TAKE_DIRECTORY_FD = OpenFlag.TAKE_DIRECTORY_FD
35+
ASSUME_IMMUTABLE = OpenFlag.ASSUME_IMMUTABLE
36+
SYSTEM_ONLY = OpenFlag.SYSTEM_ONLY
37+
38+
class WakeupEventType(enum.IntEnum):
39+
NOP = ...
40+
APPEND = ...
41+
INVALIDATE = ...
42+
43+
NOP = WakeupEventType.NOP
44+
APPEND = WakeupEventType.APPEND
45+
INVALIDATE = WakeupEventType.INVALIDATE
46+
47+
def _get_catalog(id: str, /) -> str: ...
48+
49+
class _Reader:
50+
@overload
51+
def __init__(self,
52+
flags: SupportsIndex = LOCAL_ONLY,
53+
*,
54+
files: SupportsLenAndGetItem[StrOrBytesPath | SupportsIndex]) -> None: ...
55+
@overload
56+
def __init__(self,
57+
flags: SupportsIndex = LOCAL_ONLY,
58+
*,
59+
namespace: StrOrBytesPath) -> None: ...
60+
@overload
61+
def __init__(self,
62+
flags: SupportsIndex = LOCAL_ONLY,
63+
path: StrOrBytesPath | SupportsIndex | None = None,
64+
files: None = None,
65+
namespace: None = None) -> None: ...
66+
def fileno(self) -> int: ...
67+
def reliable_fd(self) -> bool: ...
68+
def get_events(self) -> int: ...
69+
def get_timeout(self) -> int | None: ...
70+
def get_timeout_ms(self) -> int: ...
71+
def close(self) -> None: ...
72+
def get_usage(self) -> int: ...
73+
def __enter__(self) -> Self: ...
74+
def __exit__(self,
75+
exc_type: type[BaseException] | None,
76+
exc_value: BaseException | None,
77+
traceback: TracebackType | None,
78+
/) -> None: ...
79+
def _next(self, skip: SupportsIndex = 1, /) -> bool: ...
80+
def _previous(self, skip: SupportsIndex = 1, /) -> bool: ...
81+
def _get(self, field: str, /) -> bytes: ...
82+
def _get_all(self) -> dict[str, bytes | list[bytes]]: ...
83+
def _get_realtime(self) -> int: ...
84+
def _get_monotonic(self) -> Monotonic[int, bytes]: ...
85+
def add_match(self, match: str | bytes, /) -> None: ...
86+
def add_disjunction(self) -> None: ...
87+
def add_conjunction(self) -> None: ...
88+
def flush_matches(self) -> None: ...
89+
def seek_head(self) -> None: ...
90+
def seek_tail(self) -> None: ...
91+
def seek_realtime(self, timestamp: SupportsIndex, /) -> None: ...
92+
def seek_monotonic(self,
93+
timestamp: SupportsIndex,
94+
bootid: str | None = None,
95+
/) -> None: ...
96+
def _get_start(self) -> int: ...
97+
def _get_end(self) -> int: ...
98+
def process(self) -> WakeupEventType: ...
99+
def wait(self, timeout: SupportsIndex = -1, /) -> WakeupEventType: ...
100+
def seek_cursor(self, cursor: str, /) -> None: ...
101+
def _get_cursor(self) -> str: ...
102+
def test_cursor(self, cursor: str, /) -> bool: ...
103+
def query_unique(self, query: str, /) -> set[bytes]: ...
104+
def enumerate_fields(self) -> set[str]: ...
105+
def has_runtime_files(self) -> bool: ...
106+
def has_persistent_files(self) -> bool: ...
107+
def get_catalog(self) -> str: ...
108+
@property
109+
def data_threshold(self) -> int: ...
110+
@data_threshold.setter
111+
def data_threshold(self, value: int) -> None: ...
112+
@property
113+
def closed(self) -> bool: ...
114+
115+
@final
116+
class Monotonic(structseq[Any], tuple[_Timestamp, _Bootid]):
117+
@property
118+
def timestamp(self) -> _Timestamp: ...
119+
@property
120+
def bootid(self) -> _Bootid: ...

src/systemd/daemon.py

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# SPDX-License-Identifier: LGPL-2.1-or-later
2+
from __future__ import annotations
23

34
from socket import AF_UNSPEC as _AF_UNSPEC
5+
import socket as _socket
6+
import typing as _typing
47

58
from ._daemon import (__version__,
69
booted,
@@ -15,25 +18,39 @@
1518
_is_mq,
1619
LISTEN_FDS_START)
1720

18-
def _convert_fileobj(fileobj):
19-
try:
20-
return fileobj.fileno()
21-
except AttributeError:
21+
if _typing.TYPE_CHECKING:
22+
from _typeshed import FileDescriptorLike, StrOrBytesPath
23+
24+
def _convert_fileobj(fileobj: FileDescriptorLike) -> int:
25+
if isinstance(fileobj, int):
2226
return fileobj
27+
return fileobj.fileno()
2328

24-
def is_fifo(fileobj, path=None):
29+
def is_fifo(fileobj: FileDescriptorLike,
30+
path: StrOrBytesPath | None = None) -> bool:
2531
fd = _convert_fileobj(fileobj)
2632
return _is_fifo(fd, path)
2733

28-
def is_socket(fileobj, family=_AF_UNSPEC, type=0, listening=-1):
34+
def is_socket(fileobj: FileDescriptorLike,
35+
family: _socket.AddressFamily = _AF_UNSPEC,
36+
type: _socket.SocketKind | None = None,
37+
listening: int = -1) -> bool:
2938
fd = _convert_fileobj(fileobj)
30-
return _is_socket(fd, family, type, listening)
39+
return _is_socket(fd, family, type or 0, listening)
3140

32-
def is_socket_inet(fileobj, family=_AF_UNSPEC, type=0, listening=-1, port=0):
41+
def is_socket_inet(fileobj: FileDescriptorLike,
42+
family: _socket.AddressFamily = _AF_UNSPEC,
43+
type: _socket.SocketKind | None = None,
44+
listening: int = -1,
45+
port: int = 0) -> bool:
3346
fd = _convert_fileobj(fileobj)
34-
return _is_socket_inet(fd, family, type, listening, port)
47+
return _is_socket_inet(fd, family, type or 0, listening, port)
3548

36-
def is_socket_sockaddr(fileobj, address, type=0, flowinfo=0, listening=-1):
49+
def is_socket_sockaddr(fileobj: FileDescriptorLike,
50+
address: str,
51+
type: _socket.SocketKind | None = None,
52+
flowinfo: int = 0,
53+
listening: int = -1) -> bool:
3754
"""Check socket type, address and/or port, flowinfo, listening state.
3855
3956
Wraps sd_is_socket_inet_sockaddr(3).
@@ -45,17 +62,20 @@ def is_socket_sockaddr(fileobj, address, type=0, flowinfo=0, listening=-1):
4562
Constants for `family` are defined in the socket module.
4663
"""
4764
fd = _convert_fileobj(fileobj)
48-
return _is_socket_sockaddr(fd, address, type, flowinfo, listening)
65+
return _is_socket_sockaddr(fd, address, type or 0, flowinfo, listening)
4966

50-
def is_socket_unix(fileobj, type=0, listening=-1, path=None):
67+
def is_socket_unix(fileobj: FileDescriptorLike,
68+
type: _socket.SocketKind | None = None,
69+
listening: int = -1,
70+
path: StrOrBytesPath | None = None) -> bool:
5171
fd = _convert_fileobj(fileobj)
52-
return _is_socket_unix(fd, type, listening, path)
72+
return _is_socket_unix(fd, type or 0, listening, path)
5373

54-
def is_mq(fileobj, path=None):
74+
def is_mq(fileobj: FileDescriptorLike, path: StrOrBytesPath | None = None) -> bool:
5575
fd = _convert_fileobj(fileobj)
5676
return _is_mq(fd, path)
5777

58-
def listen_fds(unset_environment=True):
78+
def listen_fds(unset_environment: bool = True) -> list[int]:
5979
"""Return a list of socket activated descriptors
6080
6181
Example::
@@ -73,7 +93,7 @@ def listen_fds(unset_environment=True):
7393
num = _listen_fds(unset_environment)
7494
return list(range(LISTEN_FDS_START, LISTEN_FDS_START + num))
7595

76-
def listen_fds_with_names(unset_environment=True):
96+
def listen_fds_with_names(unset_environment: bool = True) -> dict[int, str]:
7797
"""Return a dictionary of socket activated descriptors as {fd: name}
7898
7999
Example::
@@ -88,8 +108,5 @@ def listen_fds_with_names(unset_environment=True):
88108
Execing python3 (...)
89109
[3]
90110
"""
91-
composite = _listen_fds_with_names(unset_environment)
92-
retval = {}
93-
for i in range(0, composite[0]):
94-
retval[i+LISTEN_FDS_START] = composite[1+i]
95-
return retval
111+
_, *names = _listen_fds_with_names(unset_environment)
112+
return {i: name for i, name in enumerate(names, LISTEN_FDS_START)}

0 commit comments

Comments
 (0)