Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/asyncio/protocols.py: 65%

40 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1"""Abstract Protocol base classes.""" 

2 

3__all__ = ( 

4 'BaseProtocol', 'Protocol', 'DatagramProtocol', 

5 'SubprocessProtocol', 'BufferedProtocol', 

6) 

7 

8 

9class BaseProtocol: 

10 """Common base class for protocol interfaces. 

11 

12 Usually user implements protocols that derived from BaseProtocol 

13 like Protocol or ProcessProtocol. 

14 

15 The only case when BaseProtocol should be implemented directly is 

16 write-only transport like write pipe 

17 """ 

18 

19 __slots__ = () 

20 

21 def connection_made(self, transport): 

22 """Called when a connection is made. 

23 

24 The argument is the transport representing the pipe connection. 

25 To receive data, wait for data_received() calls. 

26 When the connection is closed, connection_lost() is called. 

27 """ 

28 

29 def connection_lost(self, exc): 

30 """Called when the connection is lost or closed. 

31 

32 The argument is an exception object or None (the latter 

33 meaning a regular EOF is received or the connection was 

34 aborted or closed). 

35 """ 

36 

37 def pause_writing(self): 

38 """Called when the transport's buffer goes over the high-water mark. 

39 

40 Pause and resume calls are paired -- pause_writing() is called 

41 once when the buffer goes strictly over the high-water mark 

42 (even if subsequent writes increases the buffer size even 

43 more), and eventually resume_writing() is called once when the 

44 buffer size reaches the low-water mark. 

45 

46 Note that if the buffer size equals the high-water mark, 

47 pause_writing() is not called -- it must go strictly over. 

48 Conversely, resume_writing() is called when the buffer size is 

49 equal or lower than the low-water mark. These end conditions 

50 are important to ensure that things go as expected when either 

51 mark is zero. 

52 

53 NOTE: This is the only Protocol callback that is not called 

54 through EventLoop.call_soon() -- if it were, it would have no 

55 effect when it's most needed (when the app keeps writing 

56 without yielding until pause_writing() is called). 

57 """ 

58 

59 def resume_writing(self): 

60 """Called when the transport's buffer drains below the low-water mark. 

61 

62 See pause_writing() for details. 

63 """ 

64 

65 

66class Protocol(BaseProtocol): 

67 """Interface for stream protocol. 

68 

69 The user should implement this interface. They can inherit from 

70 this class but don't need to. The implementations here do 

71 nothing (they don't raise exceptions). 

72 

73 When the user wants to requests a transport, they pass a protocol 

74 factory to a utility function (e.g., EventLoop.create_connection()). 

75 

76 When the connection is made successfully, connection_made() is 

77 called with a suitable transport object. Then data_received() 

78 will be called 0 or more times with data (bytes) received from the 

79 transport; finally, connection_lost() will be called exactly once 

80 with either an exception object or None as an argument. 

81 

82 State machine of calls: 

83 

84 start -> CM [-> DR*] [-> ER?] -> CL -> end 

85 

86 * CM: connection_made() 

87 * DR: data_received() 

88 * ER: eof_received() 

89 * CL: connection_lost() 

90 """ 

91 

92 __slots__ = () 

93 

94 def data_received(self, data): 

95 """Called when some data is received. 

96 

97 The argument is a bytes object. 

98 """ 

99 

100 def eof_received(self): 

101 """Called when the other end calls write_eof() or equivalent. 

102 

103 If this returns a false value (including None), the transport 

104 will close itself. If it returns a true value, closing the 

105 transport is up to the protocol. 

106 """ 

107 

108 

109class BufferedProtocol(BaseProtocol): 

110 """Interface for stream protocol with manual buffer control. 

111 

112 Important: this has been added to asyncio in Python 3.7 

113 *on a provisional basis*! Consider it as an experimental API that 

114 might be changed or removed in Python 3.8. 

115 

116 Event methods, such as `create_server` and `create_connection`, 

117 accept factories that return protocols that implement this interface. 

118 

119 The idea of BufferedProtocol is that it allows to manually allocate 

120 and control the receive buffer. Event loops can then use the buffer 

121 provided by the protocol to avoid unnecessary data copies. This 

122 can result in noticeable performance improvement for protocols that 

123 receive big amounts of data. Sophisticated protocols can allocate 

124 the buffer only once at creation time. 

125 

126 State machine of calls: 

127 

128 start -> CM [-> GB [-> BU?]]* [-> ER?] -> CL -> end 

129 

130 * CM: connection_made() 

131 * GB: get_buffer() 

132 * BU: buffer_updated() 

133 * ER: eof_received() 

134 * CL: connection_lost() 

135 """ 

136 

137 __slots__ = () 

138 

139 def get_buffer(self, sizehint): 

140 """Called to allocate a new receive buffer. 

141 

142 *sizehint* is a recommended minimal size for the returned 

143 buffer. When set to -1, the buffer size can be arbitrary. 

144 

145 Must return an object that implements the 

146 :ref:`buffer protocol <bufferobjects>`. 

147 It is an error to return a zero-sized buffer. 

148 """ 

149 

150 def buffer_updated(self, nbytes): 

151 """Called when the buffer was updated with the received data. 

152 

153 *nbytes* is the total number of bytes that were written to 

154 the buffer. 

155 """ 

156 

157 def eof_received(self): 

158 """Called when the other end calls write_eof() or equivalent. 

159 

160 If this returns a false value (including None), the transport 

161 will close itself. If it returns a true value, closing the 

162 transport is up to the protocol. 

163 """ 

164 

165 

166class DatagramProtocol(BaseProtocol): 

167 """Interface for datagram protocol.""" 

168 

169 __slots__ = () 

170 

171 def datagram_received(self, data, addr): 

172 """Called when some datagram is received.""" 

173 

174 def error_received(self, exc): 

175 """Called when a send or receive operation raises an OSError. 

176 

177 (Other than BlockingIOError or InterruptedError.) 

178 """ 

179 

180 

181class SubprocessProtocol(BaseProtocol): 

182 """Interface for protocol for subprocess calls.""" 

183 

184 __slots__ = () 

185 

186 def pipe_data_received(self, fd, data): 

187 """Called when the subprocess writes data into stdout/stderr pipe. 

188 

189 fd is int file descriptor. 

190 data is bytes object. 

191 """ 

192 

193 def pipe_connection_lost(self, fd, exc): 

194 """Called when a file descriptor associated with the child process is 

195 closed. 

196 

197 fd is the int file descriptor that was closed. 

198 """ 

199 

200 def process_exited(self): 

201 """Called when subprocess has exited.""" 

202 

203 

204def _feed_data_to_buffered_proto(proto, data): 

205 data_len = len(data) 

206 while data_len: 

207 buf = proto.get_buffer(data_len) 

208 buf_len = len(buf) 

209 if not buf_len: 

210 raise RuntimeError('get_buffer() returned an empty buffer') 

211 

212 if buf_len >= data_len: 

213 buf[:data_len] = data 

214 proto.buffer_updated(data_len) 

215 return 

216 else: 

217 buf[:buf_len] = data[:buf_len] 

218 proto.buffer_updated(buf_len) 

219 data = data[buf_len:] 

220 data_len = len(data)