Repository: praw-dev/praw

Issue:
Can't unpickle Comment objects (maximum recursion depth exceeded)
Here's the stack trace:

``` pytb
>>> import pickle
>>> import praw
>>> r = praw.Reddit('test')
>>> comment = r.get_info(thing_id='t1_cs6woop')
>>> pickled = pickle.dumps(comment)
>>> pickle.loads(pickled)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python2.7/pickle.py", line 1382, in loads
    return Unpickler(file).load()
  File "/usr/lib/python2.7/pickle.py", line 858, in load
    dispatch[key](self)
  File "/usr/lib/python2.7/pickle.py", line 1215, in load_build
    setstate = getattr(inst, "__setstate__", None)
  File "/home/___/.virtualenvs/___/local/lib/python2.7/site-packages/praw/objects.py", line 82, in __getattr__
    if not self.has_fetched:
  File "/home/___/.virtualenvs/___/local/lib/python2.7/site-packages/praw/objects.py", line 82, in __getattr__
    if not self.has_fetched:
  File "/home/___/.virtualenvs/___/local/lib/python2.7/site-packages/praw/objects.py", line 82, in __getattr__
    if not self.has_fetched:
  ...
RuntimeError: maximum recursion depth exceeded
```



Discussion:
Working on a patch


Resolving patch:
diff --git a/praw/objects.py b/praw/objects.py
--- a/praw/objects.py
+++ b/praw/objects.py
@@ -75,7 +75,7 @@ def __eq__(self, other):
 
     def __getattr__(self, attr):
         """Return the value of the `attr` attribute."""
-        if not self.has_fetched:
+        if attr != '__setstate__' and not self.has_fetched:
             self.has_fetched = self._populate(None, True)
             return getattr(self, attr)
         raise AttributeError('\'%s\' has no attribute \'%s\'' % (type(self),


Test patch:
diff --git a/tests/cassettes/test_unpickle_comment.json b/tests/cassettes/test_unpickle_comment.json
new file mode 100644
--- /dev/null
+++ b/tests/cassettes/test_unpickle_comment.json
@@ -0,0 +1 @@
+{"recorded_with": "betamax/0.4.2", "http_interactions": [{"recorded_at": "2015-06-15T13:50:36", "response": {"status": {"code": 200, "message": "OK"}, "headers": {"transfer-encoding": ["chunked"], "cache-control": ["private, no-cache", "no-cache"], "server": ["cloudflare-nginx"], "set-cookie": ["__cfduid=d28895e21c18fe156bbe302205f9b22ac1434376236; expires=Tue, 14-Jun-16 13:50:36 GMT; path=/; domain=.reddit.com; HttpOnly", "secure_session=; Domain=reddit.com; Max-Age=-1434376237; Path=/; expires=Thu, 01-Jan-1970 00:00:01 GMT; HttpOnly", "reddit_session=7302867%2C2015-06-15T06%3A50%3A37%2Cc0e114b1f45a1bc763984b34c83d31df49a92fed; Domain=reddit.com; Path=/; HttpOnly"], "x-moose": ["majestic"], "x-xss-protection": ["1; mode=block"], "connection": ["keep-alive"], "content-encoding": ["gzip"], "pragma": ["no-cache"], "x-ua-compatible": ["IE=edge"], "x-frame-options": ["SAMEORIGIN"], "cf-ray": ["1f6ebeb510a504a3-CDG"], "date": ["Mon, 15 Jun 2015 13:50:37 GMT"], "content-type": ["application/json; charset=UTF-8"], "x-content-type-options": ["nosniff"]}, "body": {"encoding": "UTF-8", "base64_string": "H4sIAAAAAAAAAxzLTWrDMBBA4auIWSug0c+MpXNkV0oZWaM6TRMV26GL4LuXdPs+3hO+tnGHYp6g6zrWDYp5e7cGmuzyn++q7WPZ958Xdfne1Bq4jbbItkAxcPt8CD+uv3zBPElGVidEnZPXWmtLVSmRsnOkVTwqR7AG5jGuF339HJyfiK13mE6OTpjOjkpyJbCdnSLGij0mwTozhTzFGuI8hRaw9Zgl+64NjuP4AwAA//8DABH3aj7KAAAA"}, "url": "https://api.reddit.com/api/login/.json"}, "request": {"headers": {"Accept-Encoding": ["gzip, deflate"], "Connection": ["keep-alive"], "Accept": ["*/*"], "Content-Length": ["45"], "User-Agent": ["PRAW_test_suite PRAW/3.0a1 Python/2.7.8 Linux-3.16.0-37-generic-x86_64-with-Ubuntu-14.10-utopic"], "Content-Type": ["application/x-www-form-urlencoded"]}, "body": {"encoding": "utf-8", "string": "passwd=1111&api_type=json&user=PyAPITestUser2"}, "uri": "https://api.reddit.com/api/login/.json", "method": "POST"}}, {"recorded_at": "2015-06-15T13:50:37", "response": {"status": {"code": 200, "message": "OK"}, "headers": {"x-ratelimit-remaining": ["299"], "content-type": ["application/json; charset=UTF-8"], "cache-control": ["private, no-cache", "no-cache"], "content-length": ["2574"], "server": ["cloudflare-nginx"], "x-content-type-options": ["nosniff"], "x-moose": ["majestic"], "x-ratelimit-used": ["1"], "x-frame-options": ["SAMEORIGIN"], "x-sup-id": ["http://www.reddit.com/sup.json#e4356386a7"], "x-xss-protection": ["1; mode=block"], "connection": ["keep-alive"], "content-encoding": ["gzip"], "pragma": ["no-cache"], "x-ua-compatible": ["IE=edge"], "x-reddit-tracking": ["https://pixel.redditmedia.com/pixel/of_destiny.png?v=HcLLGdCwZSCTj%2BYMBgG8Ln0%2FKHA5a%2FIoJVNJ%2Fv%2FXrv6TSUaosRpQ67%2Fyfcg6Z7i5Diz8FZevtuCHzUmagS6TUQ7G47Go4bcv"], "cf-ray": ["1f6ebeb9f0cd04a3-CDG"], "date": ["Mon, 15 Jun 2015 13:50:37 GMT"], "x-ratelimit-reset": ["563"], "vary": ["accept-encoding"]}, "body": {"encoding": "UTF-8", "base64_string": "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"}, "url": "https://api.reddit.com/user/PyAPITestUser2/comments.json?sort=new&t=all"}, "request": {"headers": {"Connection": ["keep-alive"], "User-Agent": ["PRAW_test_suite PRAW/3.0a1 Python/2.7.8 Linux-3.16.0-37-generic-x86_64-with-Ubuntu-14.10-utopic"], "Accept": ["*/*"], "Accept-Encoding": ["gzip, deflate"], "Cookie": ["reddit_session=7302867%2C2015-06-15T06%3A50%3A37%2Cc0e114b1f45a1bc763984b34c83d31df49a92fed; __cfduid=d28895e21c18fe156bbe302205f9b22ac1434376236"]}, "body": {"encoding": "utf-8", "string": ""}, "uri": "https://api.reddit.com/user/PyAPITestUser2/comments.json?sort=new&t=all", "method": "GET"}}, {"recorded_at": "2015-06-15T13:50:38", "response": {"status": {"code": 200, "message": "OK"}, "headers": {"x-ratelimit-remaining": ["298"], "transfer-encoding": ["chunked"], "cache-control": ["private, no-cache", "no-cache"], "x-moose": ["majestic"], "server": ["cloudflare-nginx"], "x-ratelimit-used": ["2"], "x-frame-options": ["SAMEORIGIN"], "x-xss-protection": ["1; mode=block"], "connection": ["keep-alive"], "content-encoding": ["gzip"], "pragma": ["no-cache"], "x-ua-compatible": ["IE=edge"], "x-reddit-tracking": ["https://pixel.redditmedia.com/pixel/of_destiny.png?v=6qsn21tVL7go5HvVpotLbf0tnpT2hujgxe4105fEz7G1t0%2BHh25pl%2FSGghZNuAZaGB%2FJKaxz67I%3D"], "cf-ray": ["1f6ebebe912c04a3-CDG"], "date": ["Mon, 15 Jun 2015 13:50:38 GMT"], "x-ratelimit-reset": ["562"], "content-type": ["application/json; charset=UTF-8"], "x-content-type-options": ["nosniff"]}, "body": {"encoding": "UTF-8", "base64_string": "H4sIAAAAAAAAA1yRwW7DIBBEfwVxtqrYxgn2rcfecmjPaANLvYqBCnCUNsq/V6AkjXodzQ5vhgs/kjd8Yjx3vGHcQAY+sQufISkHtPCJWVgSNox7cFic++/X/ds7pvyRMNYrSspGwhp0d+uIkLEobSfFth02cnjZNIzPZFDZGJyK4RByerr5DItROqIxVPVid8HMkOby8LYVLq1j+Nl1BzNYsYGulwjCgu7sCOM49LtejhalMJ0WW7krcDcQtWb9gGnFHabUDOZ/1YX8UR0hujJG25WU4Bz6/BDHhvFwwqhaySeW41rOKKlS4SmIavyfozbE8xdFyBQ8n5hfl+UGcsJIltAovOHcY+sHCU1nW9f2h3BWOqw+l42u118AAAD//wMAKxRkF8UBAAA="}, "url": "https://api.reddit.com/user/PyAPITestUser2/about/.json"}, "request": {"headers": {"Connection": ["keep-alive"], "User-Agent": ["PRAW_test_suite PRAW/3.0a1 Python/2.7.8 Linux-3.16.0-37-generic-x86_64-with-Ubuntu-14.10-utopic"], "Accept": ["*/*"], "Accept-Encoding": ["gzip, deflate"], "Cookie": ["reddit_session=7302867%2C2015-06-15T06%3A50%3A37%2Cc0e114b1f45a1bc763984b34c83d31df49a92fed; __cfduid=d28895e21c18fe156bbe302205f9b22ac1434376236"]}, "body": {"encoding": "utf-8", "string": ""}, "uri": "https://api.reddit.com/user/PyAPITestUser2/about/.json", "method": "GET"}}, {"recorded_at": "2015-06-15T13:50:38", "response": {"status": {"code": 200, "message": "OK"}, "headers": {"x-ratelimit-remaining": ["297"], "content-type": ["application/json; charset=UTF-8"], "cache-control": ["private, no-cache", "no-cache"], "content-length": ["682"], "server": ["cloudflare-nginx"], "x-content-type-options": ["nosniff"], "x-moose": ["majestic"], "x-ratelimit-used": ["3"], "x-frame-options": ["SAMEORIGIN"], "x-xss-protection": ["1; mode=block"], "connection": ["keep-alive"], "content-encoding": ["gzip"], "pragma": ["no-cache"], "x-ua-compatible": ["IE=edge"], "x-reddit-tracking": ["https://pixel.redditmedia.com/pixel/of_destiny.png?v=AqxVkrSRF3bN55ymSSdkwfD%2FLdA4QMcYwodHHwNYU4Pccch5s1XTILSk9LACd6ER3FcO3MQmUDmhY5Rn5rzZjrp3D2F%2F%2BvsO"], "cf-ray": ["1f6ebec1714204a3-CDG"], "date": ["Mon, 15 Jun 2015 13:50:38 GMT"], "x-ratelimit-reset": ["562"], "vary": ["accept-encoding"]}, "body": {"encoding": "UTF-8", "base64_string": "H4sIAC7YflUC/61UyU7cQBD9FccHTsx4XwaUAyIimgOLICdC1OqlPNOZ9kJ3e2BA/Hu6G5sxHJCQcrHsqvKrV/Wq6tnf8Ib5R56vM//Q8xnW2Hw9+wQ3DUjE65V1WpfqSc010vCo0VrXwtibXgjj6ZWNVMj9Y8EqLBQYB3fIsc7a3CKMcbRttOSk1600fi17GzuBHzMyrjqBd6jBNVibBMZMCO64CVPahqwBsz3NtdbdURCQuV73NVHz1x9qYBzPaVsH0c/0PF5dIX41u87l7cU5e7g0hPqL5RKj/vIpOl1GJ7ebEHV0/rdbOQ6gqOSd5m0zVu0fCH38bTbzbk7R5dmZN5sdrPSxNTK+9ajASn2/82t254/2zr782CN5BS3ytHpI6D0UjEZZXpQQVqQK0yIvUhpnxYLQjMa0giTJwoyFFiZwOHeNeze5RviRy8VAxfLWXAvXtGvXA+/kaun9Mk3z0oeUb7aPOfRJRXLDglR5SnHF4qLMU8DVgkAZFSRMynBB8pDFFo62QuBOAWIgQAMzGtY1NFpN1O56IjhFk47Z/NOyxT3Uuo8SuSuyKCxTVuRltFiYSqO8jG3hizJb4CysGKQljUqXu92CjMpPE/1Hab7O8avScDP/SPEnK8+wQc402bVhrEcRh6hPOvv1gZqstODNBglMYLLTmNK2N/oiTDXfWhLRvvNa4qridCLJQHio6ncShoeeefx5TWJ5EpB2WOJ4n9edkg95x13XGXq7G1QC1u6wREkcZ1lYFNncJPB76UQPZPDhNASuiZwBwmw6ogMS6rUl/wFtOHnvlRlvVt2a+vC7i+Vcyqi0hhoQNJgIR3JwDxuCFG0lIEem5o1lY5OZFgyc9a5zFb/29k0Wpexcj07c7KYXdN/TsbiXl38Stiz/ywUAAA=="}, "url": "https://api.reddit.com/r/reddit_api_test/about/.json"}, "request": {"headers": {"Connection": ["keep-alive"], "User-Agent": ["PRAW_test_suite PRAW/3.0a1 Python/2.7.8 Linux-3.16.0-37-generic-x86_64-with-Ubuntu-14.10-utopic"], "Accept": ["*/*"], "Accept-Encoding": ["gzip, deflate"], "Cookie": ["reddit_session=7302867%2C2015-06-15T06%3A50%3A37%2Cc0e114b1f45a1bc763984b34c83d31df49a92fed; __cfduid=d28895e21c18fe156bbe302205f9b22ac1434376236"]}, "body": {"encoding": "utf-8", "string": ""}, "uri": "https://api.reddit.com/r/reddit_api_test/about/.json", "method": "GET"}}]}
\ No newline at end of file
diff --git a/tests/test_comments.py b/tests/test_comments.py
--- a/tests/test_comments.py
+++ b/tests/test_comments.py
@@ -1,6 +1,7 @@
 """Tests for Comment class."""
 
 from __future__ import print_function, unicode_literals
+import pickle
 from praw import helpers
 from praw.objects import Comment, MoreComments
 from .helper import PRAWTest, betamax
@@ -97,6 +98,15 @@ def test_user_comment_replies_are_none(self):
                              lambda item: isinstance(item, Comment))
         self.assertEqual(comment._replies, None)
 
+    @betamax
+    def test_unpickle_comment(self):
+        item = next(self.r.user.get_comments())
+        pkl = pickle.dumps(item)
+        try:
+            pickle.loads(pkl)
+        except RuntimeError:
+            self.fail("unpickling shouldn't throw a RuntimeError exception")
+
 
 class MoreCommentsTest(PRAWTest):
     def betamax_init(self):