Coverage for python/lsst/resources/_resourceHandles/_baseResourceHandle.py: 74%
94 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-30 11:34 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-30 11:34 +0000
1# This file is part of lsst-resources.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# Use of this source code is governed by a 3-clause BSD-style
10# license that can be found in the LICENSE file.
11from __future__ import annotations
13from types import TracebackType
15__all__ = ("BaseResourceHandle", "CloseStatus", "ResourceHandleProtocol")
17from abc import ABC, abstractmethod, abstractproperty
18from collections.abc import Callable, Iterable
19from enum import Enum, auto
20from io import SEEK_SET
21from logging import Logger
22from typing import AnyStr, Generic, Protocol, TypeVar
24S = TypeVar("S", bound="ResourceHandleProtocol")
25T = TypeVar("T", bound="BaseResourceHandle")
26U = TypeVar("U", str, bytes)
29class CloseStatus(Enum):
30 """Enumerated closed/open status of a file handle, implementation detail
31 that may be used by BaseResourceHandle children.
32 """
34 OPEN = auto()
35 CLOSING = auto()
36 CLOSED = auto()
39class ResourceHandleProtocol(Protocol, Generic[U]):
40 """Defines the interface protocol that is compatible with children of
41 `.BaseResourceHandle`.
43 Any class that satisfies this protocol can be used in any context where a
44 `.BaseResourceHandle` is expected.
45 """
47 @abstractproperty
48 def mode(self) -> str:
49 ...
51 @abstractmethod
52 def close(self) -> None:
53 ...
55 @abstractproperty
56 def closed(self) -> bool:
57 ...
59 @abstractmethod
60 def fileno(self) -> int:
61 ...
63 @abstractmethod
64 def flush(self) -> None:
65 ...
67 @abstractproperty
68 def isatty(self) -> bool | Callable[[], bool]:
69 ...
71 @abstractmethod
72 def readable(self) -> bool:
73 ...
75 @abstractmethod
76 def readline(self, size: int = -1) -> U:
77 ...
79 @abstractmethod
80 def readlines(self, hint: int = -1) -> Iterable[U]:
81 ...
83 @abstractmethod
84 def seek(self, offset: int, whence: int = SEEK_SET, /) -> int:
85 pass
87 @abstractmethod
88 def seekable(self) -> bool:
89 ...
91 @abstractmethod
92 def tell(self) -> int:
93 ...
95 @abstractmethod
96 def truncate(self, size: int | None = None) -> int:
97 ...
99 @abstractmethod
100 def writable(self) -> bool:
101 ...
103 @abstractmethod
104 def writelines(self, lines: Iterable[U], /) -> None:
105 ...
107 @abstractmethod
108 def read(self, size: int = -1) -> U:
109 ...
111 @abstractmethod
112 def write(self, b: U, /) -> int:
113 ...
115 def __enter__(self: S) -> S:
116 ...
118 def __exit__(
119 self,
120 exc_type: type[BaseException] | None,
121 exc_val: BaseException | None,
122 exc_tb: TracebackType | None,
123 /,
124 ) -> bool | None:
125 ...
128class BaseResourceHandle(ABC, ResourceHandleProtocol[U]):
129 """Base class interface for the handle like interface of
130 `~lsst.resources.ResourcePath` subclasses.
132 Parameters
133 ----------
134 mode : `str`
135 Handle modes as described in the python `io` module
136 log : `~logging.Logger`
137 Logger to used when writing messages
138 newline : `str`
139 When doing multiline operations, break the stream on given character
140 Defaults to newline.
142 Notes
143 -----
144 Documentation on the methods of this class line should refer to the
145 corresponding methods in the `io` module.
146 """
148 _closed: CloseStatus
149 _mode: str
150 _log: Logger
151 _newline: U
153 def __init__(self, mode: str, log: Logger, *, newline: AnyStr | None = None) -> None:
154 if newline is None:
155 if "b" in mode:
156 self._newline = b"\n" # type: ignore
157 else:
158 self._newline = "\n" # type: ignore
159 else:
160 self._newline = newline # type: ignore
161 self._mode = mode
162 self._log = log
164 @property
165 def mode(self) -> str:
166 return self._mode
168 def __enter__(self: T) -> T:
169 self._closed = CloseStatus.OPEN
170 return self
172 def __exit__(
173 self,
174 exc_type: type[BaseException] | None,
175 exc_bal: BaseException | None,
176 exc_tb: TracebackType | None,
177 ) -> bool | None:
178 self.close()
179 return None