Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/a2wsgi/wsgi_typing.py: 18%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

28 statements  

1""" 

2https://peps.python.org/pep-3333/ 

3""" 

4from types import TracebackType 

5from typing import ( 

6 Any, 

7 Callable, 

8 Iterable, 

9 List, 

10 Optional, 

11 Protocol, 

12 Tuple, 

13 Type, 

14 TypedDict, 

15) 

16 

17CGIRequiredDefined = TypedDict( 

18 "CGIRequiredDefined", 

19 { 

20 # The HTTP request method, such as GET or POST. This cannot ever be an 

21 # empty string, and so is always required. 

22 "REQUEST_METHOD": str, 

23 # When HTTP_HOST is not set, these variables can be combined to determine 

24 # a default. 

25 # SERVER_NAME and SERVER_PORT are required strings and must never be empty. 

26 "SERVER_NAME": str, 

27 "SERVER_PORT": str, 

28 # The version of the protocol the client used to send the request. 

29 # Typically this will be something like "HTTP/1.0" or "HTTP/1.1" and 

30 # may be used by the application to determine how to treat any HTTP 

31 # request headers. (This variable should probably be called REQUEST_PROTOCOL, 

32 # since it denotes the protocol used in the request, and is not necessarily 

33 # the protocol that will be used in the server's response. However, for 

34 # compatibility with CGI we have to keep the existing name.) 

35 "SERVER_PROTOCOL": str, 

36 }, 

37) 

38 

39CGIOptionalDefined = TypedDict( 

40 "CGIOptionalDefined", 

41 { 

42 "REQUEST_URI": str, 

43 "REMOTE_ADDR": str, 

44 "REMOTE_PORT": str, 

45 # The initial portion of the request URL’s “path” that corresponds to the 

46 # application object, so that the application knows its virtual “location”. 

47 # This may be an empty string, if the application corresponds to the “root” 

48 # of the server. 

49 "SCRIPT_NAME": str, 

50 # The remainder of the request URL’s “path”, designating the virtual 

51 # “location” of the request’s target within the application. This may be an 

52 # empty string, if the request URL targets the application root and does 

53 # not have a trailing slash. 

54 "PATH_INFO": str, 

55 # The portion of the request URL that follows the “?”, if any. May be empty 

56 # or absent. 

57 "QUERY_STRING": str, 

58 # The contents of any Content-Type fields in the HTTP request. May be empty 

59 # or absent. 

60 "CONTENT_TYPE": str, 

61 # The contents of any Content-Length fields in the HTTP request. May be empty 

62 # or absent. 

63 "CONTENT_LENGTH": str, 

64 }, 

65 total=False, 

66) 

67 

68 

69class InputStream(Protocol): 

70 """ 

71 An input stream (file-like object) from which the HTTP request body bytes can be 

72 read. (The server or gateway may perform reads on-demand as requested by the 

73 application, or it may pre- read the client's request body and buffer it in-memory 

74 or on disk, or use any other technique for providing such an input stream, according 

75 to its preference.) 

76 """ 

77 

78 def read(self, size: int = -1, /) -> bytes: 

79 """ 

80 The server is not required to read past the client's specified Content-Length, 

81 and should simulate an end-of-file condition if the application attempts to read 

82 past that point. The application should not attempt to read more data than is 

83 specified by the CONTENT_LENGTH variable. 

84 A server should allow read() to be called without an argument, and return the 

85 remainder of the client's input stream. 

86 A server should return empty bytestrings from any attempt to read from an empty 

87 or exhausted input stream. 

88 """ 

89 raise NotImplementedError 

90 

91 def readline(self, limit: int = -1, /) -> bytes: 

92 """ 

93 Servers should support the optional "size" argument to readline(), but as in 

94 WSGI 1.0, they are allowed to omit support for it. 

95 (In WSGI 1.0, the size argument was not supported, on the grounds that it might 

96 have been complex to implement, and was not often used in practice... but then 

97 the cgi module started using it, and so practical servers had to start 

98 supporting it anyway!) 

99 """ 

100 raise NotImplementedError 

101 

102 def readlines(self, hint: int = -1, /) -> List[bytes]: 

103 """ 

104 Note that the hint argument to readlines() is optional for both caller and 

105 implementer. The application is free not to supply it, and the server or gateway 

106 is free to ignore it. 

107 """ 

108 raise NotImplementedError 

109 

110 

111class ErrorStream(Protocol): 

112 """ 

113 An output stream (file-like object) to which error output can be written, 

114 for the purpose of recording program or other errors in a standardized and 

115 possibly centralized location. This should be a "text mode" stream; 

116 i.e., applications should use "\n" as a line ending, and assume that it will 

117 be converted to the correct line ending by the server/gateway. 

118 (On platforms where the str type is unicode, the error stream should accept 

119 and log arbitrary unicode without raising an error; it is allowed, however, 

120 to substitute characters that cannot be rendered in the stream's encoding.) 

121 For many servers, wsgi.errors will be the server's main error log. Alternatively, 

122 this may be sys.stderr, or a log file of some sort. The server's documentation 

123 should include an explanation of how to configure this or where to find the 

124 recorded output. A server or gateway may supply different error streams to 

125 different applications, if this is desired. 

126 """ 

127 

128 def flush(self) -> None: 

129 """ 

130 Since the errors stream may not be rewound, servers and gateways are free to 

131 forward write operations immediately, without buffering. In this case, the 

132 flush() method may be a no-op. Portable applications, however, cannot assume 

133 that output is unbuffered or that flush() is a no-op. They must call flush() 

134 if they need to ensure that output has in fact been written. 

135 (For example, to minimize intermingling of data from multiple processes writing 

136 to the same error log.) 

137 """ 

138 raise NotImplementedError 

139 

140 def write(self, s: str, /) -> Any: 

141 raise NotImplementedError 

142 

143 def writelines(self, seq: List[str], /) -> Any: 

144 raise NotImplementedError 

145 

146 

147WSGIDefined = TypedDict( 

148 "WSGIDefined", 

149 { 

150 "wsgi.version": Tuple[int, int], # e.g. (1, 0) 

151 "wsgi.url_scheme": str, # e.g. "http" or "https" 

152 "wsgi.input": InputStream, 

153 "wsgi.errors": ErrorStream, 

154 # This value should evaluate true if the application object may be simultaneously 

155 # invoked by another thread in the same process, and should evaluate false otherwise. 

156 "wsgi.multithread": bool, 

157 # This value should evaluate true if an equivalent application object may be 

158 # simultaneously invoked by another process, and should evaluate false otherwise. 

159 "wsgi.multiprocess": bool, 

160 # This value should evaluate true if the server or gateway expects (but does 

161 # not guarantee!) that the application will only be invoked this one time during 

162 # the life of its containing process. Normally, this will only be true for a 

163 # gateway based on CGI (or something similar). 

164 "wsgi.run_once": bool, 

165 }, 

166) 

167 

168 

169class Environ(CGIRequiredDefined, CGIOptionalDefined, WSGIDefined): 

170 """ 

171 WSGI Environ 

172 """ 

173 

174 

175ExceptionInfo = Tuple[Type[BaseException], BaseException, Optional[TracebackType]] 

176 

177# https://peps.python.org/pep-3333/#the-write-callable 

178WriteCallable = Callable[[bytes], None] 

179 

180 

181class StartResponse(Protocol): 

182 def __call__( 

183 self, 

184 status: str, 

185 response_headers: List[Tuple[str, str]], 

186 exc_info: Optional[ExceptionInfo] = None, 

187 /, 

188 ) -> WriteCallable: 

189 raise NotImplementedError 

190 

191 

192IterableChunks = Iterable[bytes] 

193 

194WSGIApp = Callable[[Environ, StartResponse], IterableChunks]