1010import time
1111from collections .abc import Iterator
1212from email .header import Header
13- from functools import cached_property
1413from http .client import responses
1514from http .cookies import SimpleCookie
1615from typing import IO , Any
@@ -86,10 +85,13 @@ def _convert_to_charset(
8685 def __delitem__ (self , key : str ) -> None :
8786 self .pop (key )
8887
89- def __setitem__ (self , key : str , value : str | bytes ) -> None :
88+ def __setitem__ (self , key : str , value : str | bytes | None ) -> None :
9089 key = self ._convert_to_charset (key , "ascii" )
91- value = self ._convert_to_charset (value , "latin-1" , mime_encode = True )
92- self ._store [key .lower ()] = (key , value )
90+ if value is None :
91+ self ._store [key .lower ()] = (key , None )
92+ else :
93+ value = self ._convert_to_charset (value , "latin-1" , mime_encode = True )
94+ self ._store [key .lower ()] = (key , value )
9395
9496 def pop (self , key : str , default : Any = None ) -> Any :
9597 return self ._store .pop (key .lower (), default )
@@ -182,17 +184,6 @@ def charset(self) -> str:
182184 def charset (self , value : str ) -> None :
183185 self ._charset = value
184186
185- def serialize_headers (self ) -> bytes :
186- """HTTP headers as a bytestring."""
187- return b"\r \n " .join (
188- [
189- key .encode ("ascii" ) + b": " + value .encode ("latin-1" )
190- for key , value in self .headers .items ()
191- ]
192- )
193-
194- __bytes__ = serialize_headers
195-
196187 @property
197188 def _content_type_for_repr (self ) -> str :
198189 return (
@@ -315,9 +306,6 @@ def make_bytes(self, value: str | bytes) -> bytes:
315306 # Handle non-string types.
316307 return str (value ).encode (self .charset )
317308
318- # These methods partially implement the file-like object interface.
319- # See https://docs.python.org/library/io.html#io.IOBase
320-
321309 # The WSGI server must call this method upon completion of the request.
322310 # See http://blog.dscpl.com.au/2012/10/obligations-for-calling-close-on.html
323311 def close (self ) -> None :
@@ -331,32 +319,6 @@ def close(self) -> None:
331319 self .closed = True
332320 signals .request_finished .send (sender = self ._handler_class )
333321
334- def write (self , content : bytes ) -> None :
335- raise OSError (f"This { self .__class__ .__name__ } instance is not writable" )
336-
337- def flush (self ) -> None :
338- pass
339-
340- def tell (self ) -> int :
341- raise OSError (
342- f"This { self .__class__ .__name__ } instance cannot tell its position"
343- )
344-
345- # These methods partially implement a stream-like object interface.
346- # See https://docs.python.org/library/io.html#io.IOBase
347-
348- def readable (self ) -> bool :
349- return False
350-
351- def seekable (self ) -> bool :
352- return False
353-
354- def writable (self ) -> bool :
355- return False
356-
357- def writelines (self , lines : list [bytes | str ]) -> None :
358- raise OSError (f"This { self .__class__ .__name__ } instance is not writable" )
359-
360322
361323class Response (ResponseBase ):
362324 """
@@ -366,42 +328,19 @@ class Response(ResponseBase):
366328 """
367329
368330 streaming = False
369- non_picklable_attrs = frozenset (
370- [
371- "resolver_match" ,
372- # Non-picklable attributes added by test clients.
373- "client" ,
374- "context" ,
375- "json" ,
376- "templates" ,
377- ]
378- )
379331
380332 def __init__ (self , content : bytes | str | Iterator [bytes ] = b"" , ** kwargs : Any ):
381333 super ().__init__ (** kwargs )
382334 # Content is a bytestring. See the `content` property methods.
383335 self .content = content
384336
385- def __getstate__ (self ) -> dict [str , Any ]:
386- obj_dict = self .__dict__ .copy ()
387- for attr in self .non_picklable_attrs :
388- if attr in obj_dict :
389- del obj_dict [attr ]
390- return obj_dict
391-
392337 def __repr__ (self ) -> str :
393338 return "<%(cls)s status_code=%(status_code)d%(content_type)s>" % { # noqa: UP031
394339 "cls" : self .__class__ .__name__ ,
395340 "status_code" : self .status_code ,
396341 "content_type" : self ._content_type_for_repr ,
397342 }
398343
399- def serialize (self ) -> bytes :
400- """Full HTTP message, including headers, as a bytestring."""
401- return self .serialize_headers () + b"\r \n \r \n " + self .content
402-
403- __bytes__ = serialize
404-
405344 @property
406345 def content (self ) -> bytes :
407346 return b"" .join (self ._container )
@@ -420,32 +359,11 @@ def content(self, value: bytes | str | Iterator[bytes]) -> None:
420359 pass
421360 else :
422361 content = self .make_bytes (value )
423- # Create a list of properly encoded bytestrings to support write().
424362 self ._container = [content ]
425363
426- @cached_property
427- def text (self ) -> str :
428- return self .content .decode (self .charset or "utf-8" )
429-
430364 def __iter__ (self ) -> Iterator [bytes ]:
431365 return iter (self ._container )
432366
433- def write (self , content : bytes | str ) -> None :
434- self ._container .append (self .make_bytes (content ))
435-
436- def tell (self ) -> int :
437- return len (self .content )
438-
439- def getvalue (self ) -> bytes :
440- return self .content
441-
442- def writable (self ) -> bool :
443- return True
444-
445- def writelines (self , lines : list [bytes | str ]) -> None :
446- for line in lines :
447- self .write (line )
448-
449367
450368class StreamingResponse (ResponseBase ):
451369 """
@@ -495,9 +413,6 @@ def _set_streaming_content(self, value: Iterator[bytes | str]) -> None:
495413 def __iter__ (self ) -> Iterator [bytes ]:
496414 return iter (self .streaming_content )
497415
498- def getvalue (self ) -> bytes :
499- return b"" .join (self .streaming_content )
500-
501416
502417class FileResponse (StreamingResponse ):
503418 """
0 commit comments