halcy / Mastodon.py

Python wrapper for the Mastodon ( https://github.com/mastodon/mastodon/ ) API.
MIT License
867 stars 150 forks source link

Streaming not working #348

Open franasal opened 12 months ago

franasal commented 12 months ago

when calling the mastodon.stream_user(handle_mention) function as per this tutorial

the following error prompts:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[51], line 14
     11         print(status.content.lower())
     13 # Start streaming for mentions
---> 14 mastodon.stream_user(handle_mention)

File ~/PycharmProjects/generic_scibot/venv/lib64/python3.9/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)
    230 if not kwsyntax:
    231     args, kw = fix(args, kw, sig)
--> 232 return caller(func, *(extras + args), **kw)

File ~/PycharmProjects/generic_scibot/venv/lib64/python3.9/site-packages/mastodon/utility.py:49, in api_version.<locals>.api_min_version_decorator.<locals>.wrapper(function, self, *args, **kwargs)
     47     elif major == self.mastodon_major and minor == self.mastodon_minor and patch > self.mastodon_patch:
     48         raise MastodonVersionError(f"Version check failed (Need version {version}, patch is {self.mastodon_patch})")
---> 49 return function(self, *args, **kwargs)

File ~/PycharmProjects/generic_scibot/venv/lib64/python3.9/site-packages/mastodon/streaming_endpoints.py:21, in Mastodon.stream_user(self, listener, run_async, timeout, reconnect_async, reconnect_async_wait_sec)
     15 @api_version("1.1.0", "1.4.2", _DICT_VERSION_STATUS)
     16 def stream_user(self, listener, run_async=False, timeout=_DEFAULT_STREAM_TIMEOUT, reconnect_async=False, reconnect_async_wait_sec=_DEFAULT_STREAM_RECONNECT_WAIT_SEC):
     17     """
     18     Streams events that are relevant to the authorized user, i.e. home
     19     timeline and notifications.
     20     """
---> 21     return self.__stream('/api/v1/streaming/user', listener, run_async=run_async, timeout=timeout, reconnect_async=reconnect_async, reconnect_async_wait_sec=reconnect_async_wait_sec)

File ~/PycharmProjects/generic_scibot/venv/lib64/python3.9/site-packages/mastodon/internals.py:540, in Mastodon.__stream(self, endpoint, listener, params, run_async, timeout, reconnect_async, reconnect_async_wait_sec)
    538 connection = connect_func()
    539 with closing(connection) as r:
--> 540     listener.handle_stream(r)

AttributeError: 'function' object has no attribute 'handle_stream'
halcy commented 12 months ago

I'm kind of confused by this - the tutorial you linked seems to just be... wrong, and I don't think that would have worked in any past version either.

What you want to do instead is something like (just from memory, didn't test, might not be 100% correct):

from mastodon.streaming import CallbackStreamListener

# ... setup ...

def handle_mention(notification):
    if notification.type == "mention":
        print(notification.status)

listener = CallbackStreamListener(notification_handler = handle_mention)
mastodon.stream_user(listener)

You might also want to look at run_async and reconnect_async if you want the stream to just run forever and reconnect if it loses connection.

You can find a full example of how to use the streaming API here: https://github.com/halcy/MastodonpyExamples/blob/bba210623a31d2f148ec4560669d22786e8102e3/01_latency_observatory/latencies.py

franasal commented 12 months ago

thanks for the feedback and the example, closing as it's not an actual Issue ( :

halcy commented 12 months ago

Did you get it working? If so, could you tell me if the snippet above was correct? I should probably ask the author of that tutorial to fix it

franasal commented 12 months ago

hmm not really. Sorry, I should have made a proper test before closing it. I modified your code as follows using public stream:

from mastodon.streaming import CallbackStreamListener

# ... setup ...

hashtag="vegan"

def handle_mention(status):
    if hashtag in status.content.lower():
        print(status.content)
    else:
        print(status.content)

listener = CallbackStreamListener(notification_handler = handle_mention)
mastodon.stream_public(listener)

but it doesn't catch any use of the hashtag, nor in the else statement gives any output. It should be printing every toot in real time, right? i also tried with stream_hashtag using the tag parameter but with the same result

halcy commented 12 months ago

For hashtags, you would want the on_update handler, so you'd want to modify that CallbackStreamListener line like so:

listener = CallbackStreamListener(update_handler = handle_mention)

That should make your code work and print all the statuses. You can have a look at the docs: https://mastodonpy.readthedocs.io/en/stable/10_streaming.html

but maybe that API just is a bit confusing, especially now that there are quite a few events, instead of just like, three, a few versions back. I wonder if we could add some simpler way where all events just go to one function.