def fetch_events(query):
    queue_id = query["queue_id"]
    dont_block = query["dont_block"]
    last_event_id = query["last_event_id"]
    user_profile_id = query["user_profile_id"]
    new_queue_data = query.get("new_queue_data")
    user_profile_email = query["user_profile_email"]
    client_type_name = query["client_type_name"]
    handler_id = query["handler_id"]

    try:
        was_connected = False
        orig_queue_id = queue_id
        extra_log_data = ""
        if queue_id is None:
            if dont_block:
                client = allocate_client_descriptor(new_queue_data)
                queue_id = client.event_queue.id
            else:
                raise JsonableError("Missing 'queue_id' argument")
        else:
            if last_event_id is None:
                raise JsonableError("Missing 'last_event_id' argument")
            client = get_client_descriptor(queue_id)
            if client is None:
                raise JsonableError("Bad event queue id: %s" % (queue_id,))
            if user_profile_id != client.user_profile_id:
                raise JsonableError("You are not authorized to get events from this queue")
            client.event_queue.prune(last_event_id)
            was_connected = client.finish_current_handler()

        if not client.event_queue.empty() or dont_block:
            response = dict(events=client.event_queue.contents(),
                            handler_id=handler_id)
            if orig_queue_id is None:
                response['queue_id'] = queue_id
            extra_log_data = "[%s/%s]" % (queue_id, len(response["events"]))
            if was_connected:
                extra_log_data += " [was connected]"
            return dict(type="response", response=response, extra_log_data=extra_log_data)

        # After this point, dont_block=False, the queue is empty, and we
        # have a pre-existing queue, so we wait for new events.
        if was_connected:
            logging.info("Disconnected handler for queue %s (%s/%s)" % (queue_id, user_profile_email,
                                                                        client_type_name))
    except JsonableError as e:
        if hasattr(e, 'to_json_error_msg') and callable(e.to_json_error_msg):
            return dict(type="error", handler_id=handler_id,
                        message=e.to_json_error_msg())
        raise e

    client.connect_handler(handler_id, client_type_name)
    return dict(type="async")

# The following functions are called from Django

# Workaround to support the Python-requests 1.0 transition of .json
# from a property to a function
dataset/ETHPy150Open zulip/zulip/zerver/lib/event_queue.py/fetch_events/original