grequests not having the attributes response.status_code

617 Views Asked by At

Can I get a tip for how to do an http request via a VOLTTRON agent using grequests? From what I know about VOLTTRON I think grequests are required for an asynchronous methods.

Small snip from my VOLTTRON agent code, line 140 on git gist:

    _log.info(f'*** [grequests INFO] *** -  onstart sucess!')
    self.core.schedule(cron('*/1 * * * *'), self.cron_function)


def cron_function(self):
    def simple_request(url):
        page = requests.get(url)
        return page

    _log.info(f'*** [grequests INFO] *** - starting CRON Processes')


    request = grequests.get(simple_request(self.url1))
    _log.info(f'*** [grequests INFO] *** - sending out {request}')

    response = grequests.send(request)

    _log.info(f'*** [grequests INFO] *** - response code {response.status_code}')
    _log.info(f'*** [grequests INFO] *** - response text {response.content}')

The traceback when I install the agent has to do with grequests not having the attributes response.status_code. Should I be wrapping the requests library with a grequests to make my script asynchronous? Sorry not a lot wisdom here but I only need to do one http request and I think I realize my agent code needs to asynchronous to accommodate what all else is happening on the VOLTTRON platform.

2021-05-02 10:28:10,875 (grequesteragent-0.1 39693) <stderr> ERROR: Traceback (most recent call last):
2021-05-02 10:28:10,875 (grequesteragent-0.1 39693) <stderr> ERROR:   File "src/gevent/greenlet.py", line 854, in gevent._gevent_cgreenlet.Greenlet.run
2021-05-02 10:28:10,875 (grequesteragent-0.1 39693) <stderr> ERROR:   File "/home/dan/Desktop/volttron/volttron/platform/vip/agent/core.py", line 455, in wrapper
2021-05-02 10:28:10,875 (grequesteragent-0.1 39693) <stderr> ERROR:     event.function(*event.args, **event.kwargs)
2021-05-02 10:28:10,876 (grequesteragent-0.1 39693) <stderr> ERROR:   File "/home/dan/.volttron/agents/5b1bc704-ff6e-4d3d-a186-d5ec6b348686/grequesteragent-0.1/grequester/agent.py", line 153, in cron_function
2021-05-02 10:28:10,877 (grequesteragent-0.1 39693) <stderr> ERROR:     _log.info(f'*** [grequests INFO] *** - response code {response.status_code}')
2021-05-02 10:28:10,877 (grequesteragent-0.1 39693) <stderr> ERROR: AttributeError: 'gevent._gevent_cgreenlet.Greenlet' object has no attribute 'status_code'
2021-05-02 10:28:10,877 (grequesteragent-0.1 39693) <stderr> ERROR: 2021-05-02T15:20:00Z <Greenlet at 0x7f44a146c9d0: wrapper> failed with AttributeError
2021-05-02 10:28:10,877 (grequesteragent-0.1 39693) <stderr> ERROR:
1

There are 1 best solutions below

0
On BEST ANSWER

Example code from the Ecobee driver that I've annotated:

def call_grequest(method_name, url, **kwargs):
    """
    Make grequest calls to remote api
    :param method_name: method type - put/get/delete
    :param url: http URL suffix
    :param kwargs: Additional arguments for http request
    :return: grequest response
    """
    try:
        # Get the correct grequests method for the HTTP request type
        fn = getattr(grequests, method_name)
        # use that method with the url and any args to send the request
        request = fn(url, **kwargs)
        # use map to pull out the response
        response = grequests.map([request])[0]
        if response and isinstance(response, list):
            response = response[0]
        # handle cases were we receive a non-200 response
        response.raise_for_status()
        return response
    # handle specific error cases by logging a message and re-raising so we can handle it elsewhere
    except (ConnectionError, NewConnectionError) as e:
        _log.error(f"Error connecting to {url} with args {kwargs}: {e}")
        raise e


def make_ecobee_request(request_type, url, **kwargs):
    """
    Wrapper around making arbitrary GET and POST requests to remote Ecobee API
    :return: Ecobee API response using provided request content
    """
    # Generate appropriate grequests object
    # HTTP request method
    if request_type.lower() in ["get", "post"]:
        # we use verify so we can work with SSL
        response = call_grequest(request_type.lower(), url, verify=requests.certs.where(), timeout=30, **kwargs)
    else:
        raise ValueError(f"Unsupported request type {request_type} for Ecobee driver.")
    # Send request and extract data from response
    headers = response.headers
    # parse JSON content
    if "json" in headers.get("Content-Type"):
        return response.json()
    else:
        # parse Text content
        content = response.content
        if isinstance(content, bytes):
            content = jsonapi.loads(response.decode("UTF-8"))
        return content