'Publish to the channel with the given exchange, routing key, and
body. Unlike the legacy `BlockingChannel.basic_publish`, this method
provides more information about failures via exceptions.
For more information on basic_publish and what the parameters do, see:
http://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.publish
NOTE: mandatory and immediate may be enabled even without delivery
confirmation, but in the absence of delivery confirmation the
synchronous implementation has no way to know how long to wait for
the Basic.Return.
:param exchange: The exchange to publish to
:type exchange: str or unicode
:param routing_key: The routing key to bind on
:type routing_key: str or unicode
:param body: The message body; empty string if no body
:type body: str or unicode
:param pika.spec.BasicProperties properties: message properties
:param bool mandatory: The mandatory flag
:param bool immediate: The immediate flag
:raises UnroutableError: raised when a message published in
publisher-acknowledgments mode (see
`BlockingChannel.confirm_delivery`) is returned via `Basic.Return`
followed by `Basic.Ack`.
:raises NackError: raised when a message published in
publisher-acknowledgements mode is Nack\'ed by the broker. See
`BlockingChannel.confirm_delivery`.'

def publish(self, exchange, routing_key, body, properties=None, mandatory=False, immediate=False):

    if self._delivery_confirmation:
        with self._message_confirmation_result:
            self._impl.basic_publish(exchange=exchange, routing_key=routing_key, body=body, properties=properties, mandatory=mandatory, immediate=immediate)
            self._flush_output(self._message_confirmation_result.is_ready)
            conf_method = self._message_confirmation_result.value.method_frame.method
            if isinstance(conf_method, pika.spec.Basic.Nack):
                LOGGER.warn("Message    was    Nack'ed    by    broker:    nack=%r;    channel=%s;    exchange=%s;    routing_key=%s;    mandatory=%r;    immediate=%r", conf_method, self.channel_number, exchange, routing_key, mandatory, immediate)
                if (self._puback_return is not None):
                    returned_messages = [self._puback_return]
                    self._puback_return = None
                else:
                    returned_messages = []
                raise exceptions.NackError(returned_messages)
            else:
                assert isinstance(conf_method, pika.spec.Basic.Ack), conf_method
                if (self._puback_return is not None):
                    messages = [self._puback_return]
                    self._puback_return = None
                    raise exceptions.UnroutableError(messages)
    else:
        self._impl.basic_publish(exchange=exchange, routing_key=routing_key, body=body, properties=properties, mandatory=mandatory, immediate=immediate)
        self._flush_output()
