Coverage for python/lsst/resources/_resourceHandles/_baseResourceHandle.py: 74%

94 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-25 09:29 +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 

12 

13from types import TracebackType 

14 

15__all__ = ("BaseResourceHandle", "CloseStatus", "ResourceHandleProtocol") 

16 

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 

23 

24S = TypeVar("S", bound="ResourceHandleProtocol") 

25T = TypeVar("T", bound="BaseResourceHandle") 

26U = TypeVar("U", str, bytes) 

27 

28 

29class CloseStatus(Enum): 

30 """Enumerated closed/open status of a file handle, implementation detail 

31 that may be used by BaseResourceHandle children. 

32 """ 

33 

34 OPEN = auto() 

35 CLOSING = auto() 

36 CLOSED = auto() 

37 

38 

39class ResourceHandleProtocol(Protocol, Generic[U]): 

40 """Defines the interface protocol that is compatible with children of 

41 `.BaseResourceHandle`. 

42 

43 Any class that satisfies this protocol can be used in any context where a 

44 `.BaseResourceHandle` is expected. 

45 """ 

46 

47 @abstractproperty 

48 def mode(self) -> str: 

49 ... 

50 

51 @abstractmethod 

52 def close(self) -> None: 

53 ... 

54 

55 @abstractproperty 

56 def closed(self) -> bool: 

57 ... 

58 

59 @abstractmethod 

60 def fileno(self) -> int: 

61 ... 

62 

63 @abstractmethod 

64 def flush(self) -> None: 

65 ... 

66 

67 @abstractproperty 

68 def isatty(self) -> bool | Callable[[], bool]: 

69 ... 

70 

71 @abstractmethod 

72 def readable(self) -> bool: 

73 ... 

74 

75 @abstractmethod 

76 def readline(self, size: int = -1) -> U: 

77 ... 

78 

79 @abstractmethod 

80 def readlines(self, hint: int = -1) -> Iterable[U]: 

81 ... 

82 

83 @abstractmethod 

84 def seek(self, offset: int, whence: int = SEEK_SET, /) -> int: 

85 pass 

86 

87 @abstractmethod 

88 def seekable(self) -> bool: 

89 ... 

90 

91 @abstractmethod 

92 def tell(self) -> int: 

93 ... 

94 

95 @abstractmethod 

96 def truncate(self, size: int | None = None) -> int: 

97 ... 

98 

99 @abstractmethod 

100 def writable(self) -> bool: 

101 ... 

102 

103 @abstractmethod 

104 def writelines(self, lines: Iterable[U], /) -> None: 

105 ... 

106 

107 @abstractmethod 

108 def read(self, size: int = -1) -> U: 

109 ... 

110 

111 @abstractmethod 

112 def write(self, b: U, /) -> int: 

113 ... 

114 

115 def __enter__(self: S) -> S: 

116 ... 

117 

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 ... 

126 

127 

128class BaseResourceHandle(ABC, ResourceHandleProtocol[U]): 

129 """Base class interface for the handle like interface of 

130 `~lsst.resources.ResourcePath` subclasses. 

131 

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. 

141 

142 Notes 

143 ----- 

144 Documentation on the methods of this class line should refer to the 

145 corresponding methods in the `io` module. 

146 """ 

147 

148 _closed: CloseStatus 

149 _mode: str 

150 _log: Logger 

151 _newline: U 

152 

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 

163 

164 @property 

165 def mode(self) -> str: 

166 return self._mode 

167 

168 def __enter__(self: T) -> T: 

169 self._closed = CloseStatus.OPEN 

170 return self 

171 

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