Coverage for python/lsst/resources/_resourceHandles/_baseResourceHandle.py: 64%
93 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-02 06:15 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-02 06:15 -0800
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 enum import Enum, auto
19from io import SEEK_SET
20from logging import Logger
21from typing import AnyStr, Callable, Generic, Iterable, Optional, Protocol, Type, TypeVar, Union
23S = TypeVar("S", bound="ResourceHandleProtocol")
24T = TypeVar("T", bound="BaseResourceHandle")
25U = TypeVar("U", str, bytes)
28class CloseStatus(Enum):
29 """Enumerated closed/open status of a file handle, implementation detail
30 that may be used by BaseResourceHandle children.
31 """
33 OPEN = auto()
34 CLOSING = auto()
35 CLOSED = auto()
38class ResourceHandleProtocol(Protocol, Generic[U]):
39 """Defines the interface protocol that is compatible with children of
40 `BaseResourceHandle`.
42 Any class that satisfies this protocol can be used in any context where a
43 `BaseResourceHandle` is expected.
44 """
46 @abstractproperty
47 def mode(self) -> str:
48 ...
50 @abstractmethod
51 def close(self) -> None:
52 ...
54 @abstractproperty
55 def closed(self) -> bool:
56 ...
58 @abstractmethod
59 def fileno(self) -> int:
60 ...
62 @abstractmethod
63 def flush(self) -> None:
64 ...
66 @abstractproperty
67 def isatty(self) -> Union[bool, Callable[[], bool]]:
68 ...
70 @abstractmethod
71 def readable(self) -> bool:
72 ...
74 @abstractmethod
75 def readline(self, size: int = -1) -> U:
76 ...
78 @abstractmethod
79 def readlines(self, hint: int = -1) -> Iterable[U]:
80 ...
82 @abstractmethod
83 def seek(self, offset: int, whence: int = SEEK_SET, /) -> int:
84 pass
86 @abstractmethod
87 def seekable(self) -> bool:
88 ...
90 @abstractmethod
91 def tell(self) -> int:
92 ...
94 @abstractmethod
95 def truncate(self, size: Optional[int] = None) -> int:
96 ...
98 @abstractmethod
99 def writable(self) -> bool:
100 ...
102 @abstractmethod
103 def writelines(self, lines: Iterable[U], /) -> None:
104 ...
106 @abstractmethod
107 def read(self, size: int = -1) -> U:
108 ...
110 @abstractmethod
111 def write(self, b: U, /) -> int:
112 ...
114 def __enter__(self: S) -> S:
115 ...
117 def __exit__(
118 self,
119 exc_type: Optional[Type[BaseException]],
120 exc_val: Optional[BaseException],
121 exc_tb: Optional[TracebackType],
122 /,
123 ) -> Optional[bool]:
124 ...
127class BaseResourceHandle(ABC, ResourceHandleProtocol[U]):
128 """Base class interface for the handle like interface of `ResourcePath`
129 subclasses.
131 Parameters
132 ----------
133 mode : `str`
134 Handle modes as described in the python `io` module
135 log : `~logging.Logger`
136 Logger to used when writing messages
137 newline : `str`
138 When doing multiline operations, break the stream on given character
139 Defaults to newline.
141 Notes
142 -----
143 Documentation on the methods of this class line should refer to the
144 corresponding methods in the `io` module.
145 """
147 _closed: CloseStatus
148 _mode: str
149 _log: Logger
150 _newline: U
152 def __init__(self, mode: str, log: Logger, *, newline: Optional[AnyStr] = None) -> None:
153 if newline is None:
154 if "b" in mode:
155 self._newline = b"\n" # type: ignore
156 else:
157 self._newline = "\n" # type: ignore
158 else:
159 self._newline = newline # type: ignore
160 self._mode = mode
161 self._log = log
163 @property
164 def mode(self) -> str:
165 return self._mode
167 def __enter__(self: T) -> T:
168 self._closed = CloseStatus.OPEN
169 return self
171 def __exit__(
172 self,
173 exc_type: Optional[Type[BaseException]],
174 exc_bal: Optional[BaseException],
175 exc_tb: Optional[TracebackType],
176 ) -> Optional[bool]:
177 self.close()
178 return None