diff options
Diffstat (limited to 'linuxnamespaces/filedescriptor.py')
-rw-r--r-- | linuxnamespaces/filedescriptor.py | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/linuxnamespaces/filedescriptor.py b/linuxnamespaces/filedescriptor.py index e4eff9b..ee96a94 100644 --- a/linuxnamespaces/filedescriptor.py +++ b/linuxnamespaces/filedescriptor.py @@ -8,11 +8,33 @@ import os import typing +# pylint: disable=too-few-public-methods # It's that one method we describe. +@typing.runtime_checkable +class HasFileno(typing.Protocol): + """A typing protocol representing a file-like object and looking up the + underlying file descriptor. + """ + + def fileno(self) -> int: + """Return the underlying file descriptor.""" + + +FileDescriptorLike = int | HasFileno + + class FileDescriptor(int): """Type tag for integers that represent file descriptors. It also provides a few very generic file descriptor methods. """ + def __new__(cls, value: FileDescriptorLike) -> typing.Self: + """Construct a FileDescriptor from an int or HasFileno.""" + if isinstance(value, cls): + return value # No need to copy, it's immutable. + if not isinstance(value, int): + value = value.fileno() + return super(FileDescriptor, cls).__new__(cls, value) + def __enter__(self) -> "FileDescriptor": """When used as a context manager, close the file descriptor on scope exit. @@ -37,11 +59,18 @@ class FileDescriptor(int): return FileDescriptor(os.dup(self)) return FileDescriptor(fcntl.fcntl(self, fcntl.F_DUPFD_CLOEXEC, 0)) - def dup2(self, fd2: int, inheritable: bool = True) -> "FileDescriptor": + def dup2( + self, fd2: FileDescriptorLike, inheritable: bool = True + ) -> "FileDescriptor": """Duplicate the file to the given file descriptor number.""" - return FileDescriptor(os.dup2(self, fd2, inheritable)) + return FileDescriptor(os.dup2(self, FileDescriptor(fd2), inheritable)) - def fileno(self) -> int: + @classmethod + def pidfd_open(cls, pid: int, flags: int = 0) -> typing.Self: + """Convenience wrapper for os.pidfd_open.""" + return cls(os.pidfd_open(pid, flags)) + + def fileno(self) -> "FileDescriptor": """Return self such that it satisfies the HasFileno protocol.""" return self |