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

76 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-16 02:51 -0700

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: ... 48 ↛ exitline 48 didn't return from function 'mode', because

49 

50 @abstractmethod 

51 def close(self) -> None: ... 51 ↛ exitline 51 didn't return from function 'close', because

52 

53 @abstractproperty 

54 def closed(self) -> bool: ... 54 ↛ exitline 54 didn't return from function 'closed', because

55 

56 @abstractmethod 

57 def fileno(self) -> int: ... 57 ↛ exitline 57 didn't return from function 'fileno', because

58 

59 @abstractmethod 

60 def flush(self) -> None: ... 60 ↛ exitline 60 didn't return from function 'flush', because

61 

62 @abstractproperty 

63 def isatty(self) -> bool | Callable[[], bool]: ... 63 ↛ exitline 63 didn't return from function 'isatty', because

64 

65 @abstractmethod 

66 def readable(self) -> bool: ... 66 ↛ exitline 66 didn't return from function 'readable', because

67 

68 @abstractmethod 

69 def readline(self, size: int = -1) -> U: ... 69 ↛ exitline 69 didn't return from function 'readline', because

70 

71 @abstractmethod 

72 def readlines(self, hint: int = -1) -> Iterable[U]: ... 72 ↛ exitline 72 didn't return from function 'readlines', because

73 

74 @abstractmethod 

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

76 pass 

77 

78 @abstractmethod 

79 def seekable(self) -> bool: ... 79 ↛ exitline 79 didn't return from function 'seekable', because

80 

81 @abstractmethod 

82 def tell(self) -> int: ... 82 ↛ exitline 82 didn't return from function 'tell', because

83 

84 @abstractmethod 

85 def truncate(self, size: int | None = None) -> int: ... 85 ↛ exitline 85 didn't return from function 'truncate', because

86 

87 @abstractmethod 

88 def writable(self) -> bool: ... 88 ↛ exitline 88 didn't return from function 'writable', because

89 

90 @abstractmethod 

91 def writelines(self, lines: Iterable[U], /) -> None: ... 91 ↛ exitline 91 didn't return from function 'writelines', because

92 

93 @abstractmethod 

94 def read(self, size: int = -1) -> U: ... 94 ↛ exitline 94 didn't return from function 'read', because

95 

96 @abstractmethod 

97 def write(self, b: U, /) -> int: ... 97 ↛ exitline 97 didn't return from function 'write', because

98 

99 def __enter__(self: S) -> S: ... 99 ↛ exitline 99 didn't jump to line 99, because

100 

101 def __exit__( 101 ↛ exitline 101 didn't jump to the function exit

102 self, 

103 exc_type: type[BaseException] | None, 

104 exc_val: BaseException | None, 

105 exc_tb: TracebackType | None, 

106 /, 

107 ) -> bool | None: ... 

108 

109 

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

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

112 `~lsst.resources.ResourcePath` subclasses. 

113 

114 Parameters 

115 ---------- 

116 mode : `str` 

117 Handle modes as described in the python `io` module. 

118 log : `~logging.Logger` 

119 Logger to used when writing messages. 

120 newline : `str` 

121 When doing multiline operations, break the stream on given character 

122 Defaults to newline. 

123 

124 Notes 

125 ----- 

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

127 corresponding methods in the `io` module. 

128 """ 

129 

130 _closed: CloseStatus 

131 _mode: str 

132 _log: Logger 

133 _newline: U 

134 

135 def __init__(self, mode: str, log: Logger, *, newline: AnyStr | None = None) -> None: 

136 if newline is None: 

137 if "b" in mode: 

138 self._newline = b"\n" # type: ignore 

139 else: 

140 self._newline = "\n" # type: ignore 

141 else: 

142 self._newline = newline # type: ignore 

143 self._mode = mode 

144 self._log = log 

145 

146 @property 

147 def mode(self) -> str: 

148 return self._mode 

149 

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

151 self._closed = CloseStatus.OPEN 

152 return self 

153 

154 def __exit__( 

155 self, 

156 exc_type: type[BaseException] | None, 

157 exc_bal: BaseException | None, 

158 exc_tb: TracebackType | None, 

159 ) -> bool | None: 

160 self.close() 

161 return None