<commit_before>"""Manage the marshaling and demarshaling of AMQP frames

demarshal will turn a raw AMQP byte stream into the appropriate AMQP objects
from the specification file.

marshal will take an object created from the specification file and turn it
into a raw byte stream.

"""
import logging
import struct

from pamqp import body
from pamqp import codec
from pamqp import exceptions
from pamqp import heartbeat
from pamqp import header
from pamqp import specification

DEMARSHALLING_FAILURE = 0, 0, None
FRAME_HEADER_SIZE = 7
FRAME_END_CHAR = chr(specification.FRAME_END)
LOGGER = logging.getLogger(__name__)


def demarshal(data_in):
    """Takes in binary data and maps builds the appropriate frame type,
    returning a frame object.

    :param str data_in: Raw byte stream data
    :rtype: tuple of  bytes consumed, channel, and a frame object
    :raises: specification.FrameError

    """
    # Look to see if it's a protocol header frame
    try:
        frame_value = _demarshal_protocol_header_frame(data_in)
        if frame_value:
            return 8, 0, frame_value
    except ValueError as error:
        raise exceptions.DemarshalingException(header.ProtocolHeader, error)

    # Decode the low level frame and break it into parts
    try:
        frame_type, channel_id, frame_size = _frame_parts(data_in)
        byte_count = FRAME_HEADER_SIZE + frame_size + 1

        if data_in[byte_count - 1] != FRAME_END_CHAR:
            raise exceptions.DemarshalingException('Unknown', 'Last byte error')
        frame_data = data_in[FRAME_HEADER_SIZE:byte_count - 1]
    except ValueError, error:
        raise exceptions.DemarshalingException('Unknown', error)

    # Decode a method frame
    if frame_type == specification.FRAME_METHOD:
        return byte_count, channel_id, _demarshal_method_frame(frame_data)

    # Decode a header frame
    elif frame_type == specification.FRAME_HEADER:
        return byte_count, channel_id, _demarshal_header_frame(frame_data)

    # Decode a body frame
    elif frame_type == specification.FRAME_BODY:
        return byte_count, channel_id, _demarshal_body_frame(frame_data)

    # Decode a heartbeat frame
    elif frame_type == specification.FRAME_HEARTBEAT:
        return byte_count, channel_id, heartbeat.Heartbeat()

    exceptions.DemarshalingException('Unknown',
                                     'Unknown frame type: %i' % frame_type)


def marshal(frame_value, channel_id):
    """Marshal a frame to be sent over the wire.

    :param pamqp.specification.Frame frame_value: The frame object to marshal
    :param int channel_id: The channel number to send the frame on
    :rtype: str
    :raises: ValueError
<commit_msg>Add more exceptions in frame demarshalling<commit_after>"""Manage the marshaling and demarshaling of AMQP frames

demarshal will turn a raw AMQP byte stream into the appropriate AMQP objects
from the specification file.

marshal will take an object created from the specification file and turn it
into a raw byte stream.

"""
import logging
import struct

from pamqp import body
from pamqp import codec
from pamqp import exceptions
from pamqp import heartbeat
from pamqp import header
from pamqp import specification

DEMARSHALLING_FAILURE = 0, 0, None
FRAME_HEADER_SIZE = 7
FRAME_END_CHAR = chr(specification.FRAME_END)
LOGGER = logging.getLogger(__name__)


def demarshal(data_in):
    """Takes in binary data and maps builds the appropriate frame type,
    returning a frame object.

    :param str data_in: Raw byte stream data
    :rtype: tuple of  bytes consumed, channel, and a frame object
    :raises: specification.FrameError

    """
    # Look to see if it's a protocol header frame
    try:
        frame_value = _demarshal_protocol_header_frame(data_in)
        if frame_value:
            return 8, 0, frame_value
    except ValueError as error:
        raise exceptions.DemarshalingException(header.ProtocolHeader, error)

    # Decode the low level frame and break it into parts
    try:
        frame_type, channel_id, frame_size = _frame_parts(data_in)
        if not frame_size:
            raise exceptions.DemarshalingException('Unknown', 'No frame size')

        byte_count = FRAME_HEADER_SIZE + frame_size + 1
        if byte_count > len(data_in):
            raise exceptions.DemarshalingException('Unknown',
                                                   'Not all data received')

        if data_in[byte_count - 1] != FRAME_END_CHAR:
            raise exceptions.DemarshalingException('Unknown', 'Last byte error')

        frame_data = data_in[FRAME_HEADER_SIZE:byte_count - 1]

    except ValueError as error:
        raise exceptions.DemarshalingException('Unknown', error)

    # Decode a method frame
    if frame_type == specification.FRAME_METHOD:
        return byte_count, channel_id, _demarshal_method_frame(frame_data)

    # Decode a header frame
    elif frame_type == specification.FRAME_HEADER:
        return byte_count, channel_id, _demarshal_header_frame(frame_data)

    # Decode a body frame
    elif frame_type == specification.FRAME_BODY:
        return byte_count, channel_id, _demarshal_body_frame(frame_data)

    # Decode a heartbeat frame
    elif frame_type == specification.FRAME_HEARTBEAT:
        return byte_count, channel_id, heartbeat.Heartbeat()

    exceptions.DemarshalingException('Unknown',
                                     'Unknown frame type: %i' % frame_type)


def marshal(frame_value, channel_id):
    """Marshal a frame to be sent over the wire.

    :param pamqp.specification.Frame frame_value: The frame object to marshal
    :param int channel_id: The channel number to send the frame on
    :rtype: str
    :raises: ValueError

{'fraction_non_alphanumeric': 0.05989492119089317, 'fraction_numerical': 0.0028021015761821367, 'mean_word_length': 3.3762452107279692, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5850335', 'n_tokens_mistral': 1659, 'n_tokens_neox': 1556, 'n_words': 551}