note env stdout will in fact be stderr with download ignore broken pipes unless traceback write the output stream try writing bytes so we use the buffer interface buf outfile buffer except attributeerror buf outfile for chunk in stream buf writechunk if flush outfile flush def writestreamwithcolorswin stream basestream outfile textio flush bool color b x1b encoding outfile encoding for chunk in stream if color in chunk outfile writechunk decodeencoding else outfile buffer writechunk if flush outfile flush def writerawdata env environment data any processingoptions optionalprocessingoptions none headers optionalhttpheadersdict none streamkwargs optionaldictstr any none msg requests preparedrequest msg isbodyuploadchunk true msg body data msg headers headers or httpheadersdict msgoutputoptions outputoptions frommessagemsg bodytrue headersfalse return writemessage requestsmessagemsg envenv outputoptionsmsgoutputoptions processingoptionsprocessingoptions or processingoptions extrastreamkwargsstreamkwargs def buildoutputstreamformessage env environment requestsmessage requestsmessage outputoptions outputoptions processingoptions processingoptions extrastreamkwargs optionaldictstr any none messagetype requestsmessagekind request httprequest requestsmessagekind response httpresponse outputoptions kind streamclass streamkwargs getstreamtypeandkwargs envenv processingoptionsprocessingoptions messagetypemessagetype headersrequestsmessage headers if extrastreamkwargs streamkwargs updateextrastreamkwargs yield from streamclass msgmessagetyperequestsmessage outputoptionsoutputoptions streamkwargs if env stdoutisatty and outputoptions body and not outputoptions meta and not getattrrequestsmessage isbodyuploadchunk false ensure a blank line after the response body for terminal output only yield messageseparatorbytes def getstreamtypeandkwargs env environment processingoptions processingoptions messagetype typehttpmessage headers httpheadersdict tupletype basestream dict isstream processingoptions stream prettifygroups processingoptions getprettifyenv if not isstream and messagetype is httpresponse if this is a response then check the headers for determining autostreaming rawcontenttypeheader headers get contenttype none if rawcontenttypeheader contenttypeheader parsecontenttypeheaderrawcontenttypeheader isstream contenttypeheader texteventstream if not env stdoutisatty and not prettifygroups streamclass rawstream streamkwargs chunksize rawstream chunksizebyline if isstream else rawstream chunksize else streamclass encodedstream streamkwargs env env if messagetype is httpresponse streamkwargs update mimeoverwrite processingoptions responsemime encodingoverwrite processingoptions responsecharset if prettifygroups streamclass prettystream if isstream else bufferedprettystream streamkwargs update conversion conversion formatting formatting envenv groupsprettifygroups colorschemeprocessingoptions style explicitjsonprocessingoptions json formatoptionsprocessingoptions formatoptions return streamclass streamkwargs note env stdout will in fact be stderr with download ignore broken pipes unless traceback write the output stream writing bytes so we use the buffer interface like write but colorized chunks are written as text directly to outfile to ensure it gets processed by colorama applies only to windows and colorized terminal output ensure a blank line after the response body for terminal output only pick the right stream type and kwargs for it based on env and args if this is a response then check the headers for determining auto streaming
import errno
import requests
from typing import Any, Dict, IO, Optional, TextIO, Tuple, Type, Union

from ..cli.dicts import HTTPHeadersDict
from ..context import Environment
from ..models import (
    HTTPRequest,
    HTTPResponse,
    HTTPMessage,
    RequestsMessage,
    RequestsMessageKind,
    OutputOptions,
)
from .models import ProcessingOptions
from .processing import Conversion, Formatting
from .streams import (
    BaseStream, BufferedPrettyStream, EncodedStream, PrettyStream, RawStream,
)
from ..utils import parse_content_type_header


MESSAGE_SEPARATOR = '\n\n'
MESSAGE_SEPARATOR_BYTES = MESSAGE_SEPARATOR.encode()


def write_message(
    requests_message: RequestsMessage,
    env: Environment,
    output_options: OutputOptions,
    processing_options: ProcessingOptions,
    extra_stream_kwargs: Optional[Dict[str, Any]] = None
):
    if not output_options.any():
        return
    write_stream_kwargs = {
        'stream': build_output_stream_for_message(
            env=env,
            requests_message=requests_message,
            output_options=output_options,
            processing_options=processing_options,
            extra_stream_kwargs=extra_stream_kwargs
        ),
        
        'outfile': env.stdout,
        'flush': env.stdout_isatty or processing_options.stream
    }
    try:
        if env.is_windows and 'colors' in processing_options.get_prettify(env):
            write_stream_with_colors_win(**write_stream_kwargs)
        else:
            write_stream(**write_stream_kwargs)
    except OSError as e:
        if processing_options.show_traceback and e.errno == errno.EPIPE:
            
            env.stderr.write('\n')
        else:
            raise


def write_stream(
    stream: BaseStream,
    outfile: Union[IO, TextIO],
    flush: bool
):
    
    try:
        
        buf = outfile.buffer
    except AttributeError:
        buf = outfile

    for chunk in stream:
        buf.write(chunk)
        if flush:
            outfile.flush()


def write_stream_with_colors_win(
    stream: 'BaseStream',
    outfile: TextIO,
    flush: bool
):
    
    color = b'\x1b['
    encoding = outfile.encoding
    for chunk in stream:
        if color in chunk:
            outfile.write(chunk.decode(encoding))
        else:
            outfile.buffer.write(chunk)
        if flush:
            outfile.flush()


def write_raw_data(
    env: Environment,
    data: Any,
    *,
    processing_options: Optional[ProcessingOptions] = None,
    headers: Optional[HTTPHeadersDict] = None,
    stream_kwargs: Optional[Dict[str, Any]] = None
):
    msg = requests.PreparedRequest()
    msg.is_body_upload_chunk = True
    msg.body = data
    msg.headers = headers or HTTPHeadersDict()
    msg_output_options = OutputOptions.from_message(msg, body=True, headers=False)
    return write_message(
        requests_message=msg,
        env=env,
        output_options=msg_output_options,
        processing_options=processing_options or ProcessingOptions(),
        extra_stream_kwargs=stream_kwargs
    )


def build_output_stream_for_message(
    env: Environment,
    requests_message: RequestsMessage,
    output_options: OutputOptions,
    processing_options: ProcessingOptions,
    extra_stream_kwargs: Optional[Dict[str, Any]] = None
):
    message_type = {
        RequestsMessageKind.REQUEST: HTTPRequest,
        RequestsMessageKind.RESPONSE: HTTPResponse,
    }[output_options.kind]
    stream_class, stream_kwargs = get_stream_type_and_kwargs(
        env=env,
        processing_options=processing_options,
        message_type=message_type,
        headers=requests_message.headers
    )
    if extra_stream_kwargs:
        stream_kwargs.update(extra_stream_kwargs)
    yield from stream_class(
        msg=message_type(requests_message),
        output_options=output_options,
        **stream_kwargs,
    )
    if (env.stdout_isatty and output_options.body and not output_options.meta
            and not getattr(requests_message, 'is_body_upload_chunk', False)):
        
        
        yield MESSAGE_SEPARATOR_BYTES


def get_stream_type_and_kwargs(
    env: Environment,
    processing_options: ProcessingOptions,
    message_type: Type[HTTPMessage],
    headers: HTTPHeadersDict,
) -> Tuple[Type['BaseStream'], dict]:
    
    is_stream = processing_options.stream
    prettify_groups = processing_options.get_prettify(env)
    if not is_stream and message_type is HTTPResponse:
        
        
        raw_content_type_header = headers.get('Content-Type', None)
        if raw_content_type_header:
            content_type_header, _ = parse_content_type_header(raw_content_type_header)
            is_stream = (content_type_header == 'text/event-stream')

    if not env.stdout_isatty and not prettify_groups:
        stream_class = RawStream
        stream_kwargs = {
            'chunk_size': (
                RawStream.CHUNK_SIZE_BY_LINE
                if is_stream
                else RawStream.CHUNK_SIZE
            )
        }
    else:
        stream_class = EncodedStream
        stream_kwargs = {
            'env': env,
        }
        if message_type is HTTPResponse:
            stream_kwargs.update({
                'mime_overwrite': processing_options.response_mime,
                'encoding_overwrite': processing_options.response_charset,
            })
        if prettify_groups:
            stream_class = PrettyStream if is_stream else BufferedPrettyStream
            stream_kwargs.update({
                'conversion': Conversion(),
                'formatting': Formatting(
                    env=env,
                    groups=prettify_groups,
                    color_scheme=processing_options.style,
                    explicit_json=processing_options.json,
                    format_options=processing_options.format_options,
                )
            })

    return stream_class, stream_kwargs