Repository: pennersr/django-allauth

Issue:
TypeError: <function save at 0x7f9b4eab48c0> is not JSON serializable
I'm trying to write Slack provider plugin but just can't get to log in. I'm constantly seeing the error below. Oddly, I was able to login twice out of 20-30 attempts I made and I didn't really make any changes to the code.

This is also happening if I try to login using bundled LinkedIn oAuth2 provider. I've no clue what is going on. The same code and requirements work on my staging server just fine. I also reset my database to make sure it's is not corrupt data but that didn't fix it either.

No user, social account or social token is created. I can share the preliminary code I wrote for slack provider but I doubt that has got anything to do with it since it happens with the linkedin provider also.

I tried version 0.15, 0.20 and master. Same thing.

Any pointers?

``` python
Environment:

Request Method: GET
Request URL: http://localhost:8000/accounts/slack/login/callback/?code=xxxxxxxxxx&state=xxxxxxx

Django Version: 1.7.7
Python Version: 2.7.3


Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  111.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/allauth/socialaccount/providers/oauth2/views.py" in view
  55.             return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/allauth/socialaccount/providers/oauth2/views.py" in dispatch
  125.             return complete_social_login(request, login)
File "/usr/local/lib/python2.7/dist-packages/allauth/socialaccount/helpers.py" in complete_social_login
  145.         return _complete_social_login(request, sociallogin)
File "/usr/local/lib/python2.7/dist-packages/allauth/socialaccount/helpers.py" in _complete_social_login
  161.         ret = _process_signup(request, sociallogin)
File "/usr/local/lib/python2.7/dist-packages/allauth/socialaccount/helpers.py" in _process_signup
  27.         request.session['socialaccount_sociallogin'] = sociallogin.serialize()
File "/usr/local/lib/python2.7/dist-packages/allauth/socialaccount/models.py" in serialize
  187.                    user=serialize_instance(self.user),
File "/usr/local/lib/python2.7/dist-packages/allauth/utils.py" in serialize_instance
  162.     return json.loads(json.dumps(ret, cls=DjangoJSONEncoder))
File "/usr/lib/python2.7/json/__init__.py" in dumps
  238.         **kw).encode(obj)
File "/usr/lib/python2.7/json/encoder.py" in encode
  201.         chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python2.7/json/encoder.py" in iterencode
  264.         return _iterencode(o, 0)
File "/usr/local/lib/python2.7/dist-packages/django/core/serializers/json.py" in default
  109.             return super(DjangoJSONEncoder, self).default(o)
File "/usr/lib/python2.7/json/encoder.py" in default
  178.         raise TypeError(repr(o) + " is not JSON serializable")

Exception Type: TypeError at /accounts/slack/login/callback/
Exception Value: <function save at 0x7f0ac718c8c0> is not JSON serializable

```



Discussion:
I wonder if clearing cookies/sessions would do any good? Do you have custom User model and if so can you make sure you can serialize (json) a User instance?

I can't serialize the user objects like in allauth.

``` python
In [22]: json.loads(json.dumps(user, cls=DjangoJSONEncoder))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/home/vetted/src/<ipython-input-22-4f97bbabb8ce> in <module>()
----> 1 json.loads(json.dumps(u, cls=DjangoJSONEncoder))

/usr/lib/python2.7/json/__init__.pyc in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, encoding, default, **kw)
    236         check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    237         separators=separators, encoding=encoding, default=default,
--> 238         **kw).encode(obj)
    239 
    240 

/usr/lib/python2.7/json/encoder.pyc in encode(self, o)
    199         # exceptions aren't as detailed.  The list call should be roughly

    200         # equivalent to the PySequence_Fast that ''.join() would do.

--> 201         chunks = self.iterencode(o, _one_shot=True)
    202         if not isinstance(chunks, (list, tuple)):
    203             chunks = list(chunks)

/usr/lib/python2.7/json/encoder.pyc in iterencode(self, o, _one_shot)
    262                 self.key_separator, self.item_separator, self.sort_keys,
    263                 self.skipkeys, _one_shot)
--> 264         return _iterencode(o, 0)
    265 
    266 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,

/usr/local/lib/python2.7/dist-packages/django/core/serializers/json.pyc in default(self, o)
    107             return str(o)
    108         else:
--> 109             return super(DjangoJSONEncoder, self).default(o)
    110 
    111 # Older, deprecated class name (for backwards compatibility purposes).


/usr/lib/python2.7/json/encoder.pyc in default(self, o)
    176 
    177         """
--> 178         raise TypeError(repr(o) + " is not JSON serializable")
    179 
    180     def encode(self, o):

TypeError: <User: John> is not JSON serializable
```

but I can serialize like this,

``` python
In [26]: serializers.serialize('json', [u])
Out[26]: u'[{"fields": {"reviews_count": 0, "last_name": "Doe", "is_staffable": true, "avg_score": null, "email": "john@exampe.com", "meta": "\\"{\\\\\\"last_updated_availability\\\\\\": \\\\\\"2015-02-19 15:54:51\\\\\\"}\\"", "user_permissions": [], "date_joined": null, "first_name": "John", "headline": "", "is_superuser": false, "last_login": null, "location": 106, "next_available": null, "username": "john", "bio": "", "vendor": null, "resume": "", "is_active": true, "phone": null, "groups": [2], "skill_level": null, , "categories": [57], "pending_setup_steps": null, "kind": 1, "is_deleted": false, "roles": [28], "first_login": null, "linkedin_profile_url": "", "summary": "", "is_staff": false}, "model": "users.user", "pk": 33}]'
```

I'm digging deeper into what is causing the issue.

This was mysteriously working for a few days but just resurfaced again. 


Resolving patch:
diff --git a/allauth/utils.py b/allauth/utils.py
--- a/allauth/utils.py
+++ b/allauth/utils.py
@@ -180,7 +180,7 @@ def serialize_instance(instance):
     """
     ret = dict([(k, v)
                 for k, v in instance.__dict__.items()
-                if not k.startswith('_')])
+                if not (k.startswith('_') or callable(v))])
     return json.loads(json.dumps(ret, cls=DjangoJSONEncoder))
 
 


Test patch:
diff --git a/allauth/tests.py b/allauth/tests.py
--- a/allauth/tests.py
+++ b/allauth/tests.py
@@ -85,12 +85,20 @@ class SomeModel(models.Model):
             dt = models.DateTimeField()
             t = models.TimeField()
             d = models.DateField()
+            
+        def method(self):
+            pass
+
         instance = SomeModel(dt=datetime.now(),
                              d=date.today(),
                              t=datetime.now().time())
+        # make sure serializer doesn't fail if a method is attached to the instance
+        instance.method = method
         instance.nonfield = 'hello'
         data = utils.serialize_instance(instance)
         instance2 = utils.deserialize_instance(SomeModel, data)
+        self.assertEqual(getattr(instance, 'method', None), method)
+        self.assertEqual(getattr(instance2, 'method', None), None)
         self.assertEqual(instance.nonfield, instance2.nonfield)
         self.assertEqual(instance.d, instance2.d)
         self.assertEqual(instance.dt.date(), instance2.dt.date())