sseclient icon indicating copy to clipboard operation
sseclient copied to clipboard

Document issue: requests usage example has a bug

Open awarecan opened this issue 6 years ago • 4 comments

python 3.6 requests 2.18.4 sseclient-py 1.7

When using requests library, should use response.iter_content() as event source

response = requests.get(url, stream=True, allow_redirects=False, headers={'Accept': 'text/event-stream'})
client = sseclient.SSEClient(response.iter_content())

awarecan avatar May 04 '18 22:05 awarecan

bump. Would like to see the sseclient work with iter_content or httpx

reidmeyer avatar Oct 10 '22 14:10 reidmeyer

I'm not sure I understand why this is necessary. Internally, sseclient iterates over the event source with a simple loop (https://github.com/mpetazzoni/sseclient/blob/master/sseclient/init.py#L48):

for chunk in self._event_source:
  # ...

This will in turn get an iterator from the requests.Response object by calling its __iter__ method (https://github.com/psf/requests/blob/main/requests/models.py#L751-L753), which calls iter_content() already:

def __iter__(self):
    """Allows you to use a response as an iterator."""
    return self.iter_content(128)

mpetazzoni avatar Oct 28 '22 23:10 mpetazzoni

For me, I bumped this because sseclient is throwing an error when i try to plug in my Response object from my async_asgi_testclient. The Response object is from the http requests library.

Code like this:

        resp = await async_client.get("/streaming-egress/v1/trouble_tickets/", stream=True, headers=headers)
        client = sseclient.SSEClient(resp)
        for event in client.events():
            print(event)

this code throws an error

            client = sseclient.SSEClient(resp)
>           for event in client.events():

tests/test_api/test_basic_functionality.py:68: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.venv/lib/python3.10/site-packages/sseclient/__init__.py:58: in events
    for chunk in self._read():
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sseclient.SSEClient object at 0x1079c4940>

    def _read(self):
        """Read the incoming event source stream and yield event chunks.
    
        Unfortunately it is possible for some servers to decide to break an
        event into multiple HTTP chunks in the response. It is thus necessary
        to correctly stitch together consecutive response chunks and find the
        SSE delimiter (empty new line) to yield full, correct event chunks."""
        data = b''
>       for chunk in self._event_source:
E       TypeError: iter() returned non-iterator of type 'async_generator'

.venv/lib/python3.10/site-packages/sseclient/__init__.py:48: TypeError

I am able to get streaming data out of the response using:

        async for line in resp.iter_content(1000):

which is why I bumped this issue about iter_content, thinking a level down it might work.

reidmeyer avatar Oct 29 '22 08:10 reidmeyer