Search code examples
python-3.xpraw

"Type error: unhashable type: 'list'" in Praw bot


Running the following code for a Reddit bot gives the error message listed below the code, can anyone help me resolve this error? I've tried several things and cant find the answer on Google. Thanks in advance. D_035

#Bot

import praw
import time
import re
import os

r = praw.Reddit(user_agent = "Bot")
r.login()
cache = []



def run_bot():
    subreddit = r.get_subreddit("broap")
    comments = subreddit.get_comments(limit=25)
    for comment in comments:
        comment_text = comment.body.lower()
        author = comment.author
        url = comment.link_id
        msg = "User {} has tagged you in a post!".format(author)
        words = filter( lambda x:x.startswith('//'), comment_text.split())
        user = words[2:]  
        if comment.id not in cache and words:
            r.user.send_message(user ,msg)
            cache.add(comment.id)




while True:
    run_bot()
    time.sleep(5)

Error message it gives after running:

raceback (most recent call last):
  File "Test.py", line 32, in <module>
    run_bot()
  File "Test.py", line 25, in run_bot
    r.user.send_message(user ,msg)
  File "/usr/local/lib/python2.7/dist-packages/praw/decorators.py", line 60, in wrapped
    return function(self.reddit_session, self, *args, **kwargs)
  File "<decorator-gen-144>", line 2, in send_message
  File "/usr/local/lib/python2.7/dist-packages/praw/decorators.py", line 271, in wrap
    return function(*args, **kwargs)
  File "<decorator-gen-143>", line 2, in send_message
  File "/usr/local/lib/python2.7/dist-packages/praw/decorators.py", line 177, in require_captcha
    return function(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/praw/__init__.py", line 2555, in send_message
    retry_on_error=False)
  File "<decorator-gen-8>", line 2, in request_json
  File "/usr/local/lib/python2.7/dist-packages/praw/decorators.py", line 116, in raise_api_exceptions
    return_value = function(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/praw/__init__.py", line 620, in request_json
    retry_on_error=retry_on_error)
  File "/usr/local/lib/python2.7/dist-packages/praw/__init__.py", line 451, in _request
    response = handle_redirect()
  File "/usr/local/lib/python2.7/dist-packages/praw/__init__.py", line 432, in handle_redirect
    verify=self.http.validate_certs, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/praw/handlers.py", line 137, in wrapped
    if _cache_key in cls.cache:
TypeError: unhashable type: 'list'

Solution

  • r.user.send_message() doesn't expect a list as first argument. From the documentation, it looks like it expects a string (something like a user name).

    The way you build user:

        words = filter( lambda x:x.startswith('//'), comment_text.split())
        user = words[2:]
    

    makes it a list (filter returns an iterable, and then [2:] returns a "portion" of this iterable; the 'source' being a list (output of split()), it returns a list), hence the error.

    In order to correct your function, you have to change the way you build user. Don't know how to help you more since I don't know what exactly you want to do.

    EDIT: Now you told a little bit more, I would to it this way:

    def run_bot():
        subreddit = r.get_subreddit("broap")
        comments = subreddit.get_comments(limit=25)
        for comment in comments:
            comment_text = comment.body.lower()
            author = comment.author
            url = comment.link_id
            words = filter( lambda x:x.startswith('//'), comment_text.split())
            users_list = [ w[2:] for w in words ]
            for u in users_list:
                if comment.id not in cache and words:
                    r.user.send_message(u, 
            "User {a} has tagged you in a post!".format(a=author))
                    cache.append(comment.id)
    

    This should deal with any //username found in the comment. (How are you sure the username does exist? Isn't it a problem? (for instance if I write "A dummy comment just to try //invalid_username", what happens?))

    Something else: this is unrelated to your question directly, but this line:

        if comment.id not in cache and words:
    

    may not do what you want (will be True only if comment.id is not in cache AND if words is not an empty list, it won't check if comment.id belongs to words).