def _parseFetchPairs(self, fetchResponseList):
        """
        Given the result of parsing a single I{FETCH} response, construct a
        L{dict} mapping response keys to response values.

        @param fetchResponseList: The result of parsing a I{FETCH} response
            with L{parseNestedParens} and extracting just the response data
            (that is, just the part that comes after C{"FETCH"}).  The form
            of this input (and therefore the output of this method) is very
            disagreeable.  A valuable improvement would be to enumerate the
            possible keys (representing them as structured objects of some
            sort) rather than using strings and tuples of tuples of strings
            and so forth.  This would allow the keys to be documented more
            easily and would allow for a much simpler application-facing API
            (one not based on looking up somewhat hard to predict keys in a
            dict).  Since C{fetchResponseList} notionally represents a
            flattened sequence of pairs (identifying keys followed by their
            associated values), collapsing such complex elements of this
            list as C{["BODY", ["HEADER.FIELDS", ["SUBJECT"]]]} into a
            single object would also greatly simplify the implementation of
            this method.

        @return: A C{dict} of the response data represented by C{pairs}.  Keys
            in this dictionary are things like C{"RFC822.TEXT"}, C{"FLAGS"}, or
            C{("BODY", ("HEADER.FIELDS", ("SUBJECT",)))}.  Values are entirely
            dependent on the key with which they are associated, but retain the
            same structured as produced by L{parseNestedParens}.
        """

        # TODO: RFC 3501 Section 7.4.2, "FETCH Response", says for
        # BODY responses that "8-bit textual data is permitted if a
        # charset identifier is part of the body parameter
        # parenthesized list".  Every other component is 7-bit.  This
        # should parse out the charset identifier and use it to decode
        # 8-bit bodies.  Until then, on Python 2 it should continue to
        # return native (byte) strings, while on Python 3 it should
        # decode bytes to native strings via charmap, ensuring data
        # fidelity at the cost of mojibake.
        if _PY3:
            def nativeStringResponse(thing):
                if isinstance(thing, bytes):
                    return thing.decode('charmap')
                elif isinstance(thing, list):
                    return [nativeStringResponse(subthing)
                            for subthing in thing]
        else:
            def nativeStringResponse(thing):
                return thing

        values = {}
        unstructured = []

        responseParts = iter(fetchResponseList)
        while True:
            try:
                key = next(responseParts)
            except StopIteration:
                break

            try:
                value = next(responseParts)
            except StopIteration:
                raise IllegalServerResponse(
                    b"Not enough arguments", fetchResponseList)

            # The parsed forms of responses like:
            #
            # BODY[] VALUE
            # BODY[TEXT] VALUE
            # BODY[HEADER.FIELDS (SUBJECT)] VALUE
            # BODY[HEADER.FIELDS (SUBJECT)]<N.M> VALUE
            #
            # are:
            #
            # ["BODY", [], VALUE]
            # ["BODY", ["TEXT"], VALUE]
            # ["BODY", ["HEADER.FIELDS", ["SUBJECT"]], VALUE]
            # ["BODY", ["HEADER.FIELDS", ["SUBJECT"]], "<N.M>", VALUE]
            #
            # Additionally, BODY responses for multipart messages are
            # represented as:
            #
            #    ["BODY", VALUE]
            #
            # with list as the type of VALUE and the type of VALUE[0].
            #
            # See #6281 for ideas on how this might be improved.

            if key not in (b"BODY", b"BODY.PEEK"):
                # Only BODY (and by extension, BODY.PEEK) responses can have
                # body sections.
                hasSection = False
            elif not isinstance(value, list):
                # A BODY section is always represented as a list.  Any non-list
                # is not a BODY section.
                hasSection = False
            elif len(value) > 2:
                # The list representing a BODY section has at most two elements.
                hasSection = False
            elif value and isinstance(value[0], list):
                # A list containing a list represents the body structure of a
                # multipart message, instead.
                hasSection = False
            else:
                # Otherwise it must have a BODY section to examine.
                hasSection = True

            # If it has a BODY section, grab some extra elements and shuffle
            # around the shape of the key a little bit.

            key = nativeString(key)
            unstructured.append(key)

            if hasSection:
                if len(value) < 2:
                    value = [nativeString(v) for v in value]
                    unstructured.append(value)

                    key = (key, tuple(value))
                else:
                    valueHead = nativeString(value[0])
                    valueTail = [nativeString(v) for v in value[1]]
                    unstructured.append([valueHead, valueTail])

                    key = (key, (valueHead, tuple(valueTail)))
                try:
                    value = next(responseParts)
                except StopIteration:
                    raise IllegalServerResponse(
                        b"Not enough arguments", fetchResponseList)

                # Handle partial ranges
                if value.startswith(b'<') and value.endswith(b'>'):
                    try:
                        int(value[1:-1])
                    except ValueError:
                        # This isn't really a range, it's some content.
                        pass
                    else:
                        value = nativeString(value)
                        unstructured.append(value)
                        key = key + (value,)
                        try:
                            value = next(responseParts)
                        except StopIteration:
                            raise IllegalServerResponse(
                                b"Not enough arguments", fetchResponseList)

            value = nativeStringResponse(value)
            unstructured.append(value)
            values[key] = value

        return values, unstructured

        Given the result of parsing a single I{FETCH} response, construct a
        L{dict} mapping response keys to response values.

        @param fetchResponseList: The result of parsing a I{FETCH} response
            with L{parseNestedParens} and extracting just the response data
            (that is, just the part that comes after C{"FETCH"}).  The form
            of this input (and therefore the output of this method) is very
            disagreeable.  A valuable improvement would be to enumerate the
            possible keys (representing them as structured objects of some
            sort) rather than using strings and tuples of tuples of strings
            and so forth.  This would allow the keys to be documented more
            easily and would allow for a much simpler application-facing API
            (one not based on looking up somewhat hard to predict keys in a
            dict).  Since C{fetchResponseList} notionally represents a
            flattened sequence of pairs (identifying keys followed by their
            associated values), collapsing such complex elements of this
            list as C{["BODY", ["HEADER.FIELDS", ["SUBJECT"]]]} into a
            single object would also greatly simplify the implementation of
            this method.

        @return: A C{dict} of the response data represented by C{pairs}.  Keys
            in this dictionary are things like C{"RFC822.TEXT"}, C{"FLAGS"}, or
            C{("BODY", ("HEADER.FIELDS", ("SUBJECT",)))}.  Values are entirely
            dependent on the key with which they are associated, but retain the
            same structured as produced by L{parseNestedParens}.
        
stackoverflow/venv/lib/python3.6/site-packages/twisted/mail/imap4.py