Closed francisjervis closed 7 years ago
I looked into this further and this appears to be a result of the /users/me endpoint in Parse Server adding additional attributes. The crash appeared to happen when parse-rest tried to set the className attribute. See https://github.com/ParsePlatform/parse-server/issues/3348
Hey @francisjervis - thanks for investigating.
I doubt they will fix this upstream, since (1) this is not an official library, and (2) libraries shouldn't break when keys are appended (as opposed to missing). So I think the fault here is in this library.
I will take a look at this in the next couple of days. In the meantime, please comment here and/or submit a PR if you are able to fix the issue. It should be pretty straight forward.
Otherwise, a hacky would be to avoid the /users/me endpoint and just query the _User
table directly. But that's obviously not optimal. :)
@milesrichardson Thanks for getting back to me; I agree, though given that parse-server is not supposed to break existing code, one could argue they should fix it too ;)
I am going to hazard a guess at this being a failure in the convert_from_parse method in datatypes.py where the className key-value pair is outside the expected inputs. As noted in the parse-server issue, the new keys are
"__type": "Object", "className": "_User","
I'm not 100% sure I understand how the lib handles converting responses to objects, so I can't offer much here - however I have tried retrieving users using a query, which does work as expected. Unfortunately I need to retrieve the current_user based on a session token passed from the browser cookie store, so I can't actually use that as a workaround (I think). If this is because the user object from a query doesn't have the extra keys, I'd be more inclined to see this as parse-server's issue (not that that necessarily means they will fix it, as you say).
Yes, the issue is 99% chance in the convert_from_parse
method. Feel free to play with it and see if you can get something to work (or even put a hacky conditional in there like "if User object
") and submit a PR and I can make sure it doesn't break anything.
Re: the workaround, you can query the _Session
class by the session token and use the select_related('user')
method (equivalent to .include
in the JS sdk) to also select the _User
object that the _Session
object points to in its user
field.
With a quick glance, I think the issue is probably in this line:
https://github.com/milesrichardson/ParsePy/blob/master/parse_rest/datatypes.py#L44
I will try to take a look at this later tonight. Let me know if you get a fix in the meantime.
OK - my hacky conditional idea was to not try to convert className but I suspect that would break things? I've run a version with
def _init_attrs(self, args):
print args
for key, value in six.iteritems(args):
print key
setattr(self, key, ParseType.convert_from_parse(key, value))
print key, value
and the crash is definitely happening after the iteration gets to key className.
I'll give that a try, thanks for the suggestion!
Or perhaps https://github.com/milesrichardson/ParsePy/blob/master/parse_rest/datatypes.py#L106 given where it seems to crash?
That code is only for deserializing nested pointer objects. But the section below it might be relevant.
Have to head out now -- I'll take a look in a few hours. good luck
Some more logs - thanks, I will keep hacking ;)
File "/Users/francis/Library/Python/2.7/lib/python/site-packages/parse_rest/user.py", line 97, in current_user
return cls(**User.GET(user_url))
File "/Users/francis/Library/Python/2.7/lib/python/site-packages/parse_rest/datatypes.py", line 431, in __init__
self._init_attrs(kw)
File "/Users/francis/Library/Python/2.7/lib/python/site-packages/parse_rest/datatypes.py", line 444, in _init_attrs
setattr(self, key, ParseType.convert_from_parse(key, value))
AttributeError: can't set attribute
@francisjervis This should be fixed now. You can install from master like pip install git+https://github.com/milesrichardson/ParsePy
Since I included a link to this issue in a comment at the location of the fix in the code, I'm putting the solution in this comment.
The problem was that setattr(self, key, ParseType.convert_from_parse(key, value))
was trying to set the attribute className
on class ParseResource
, but className
conflicts with the existing ParseResource
property:
@property
def className(self):
return self.__class__.__name__
The offending code:
for key, value in six.iteritems(args):
setattr(self, key, ParseType.convert_from_parse(key, value))
As far as I can see there were two solutions:
1) Hard code an exception (no pun intended...) for the className
attribute:
for key, value in six.iteritems(args):
if key == 'className':
continue
setattr(self, key, ParseType.convert_from_parse(key, value))
2) Skip any AttributeError
for key, value in six.iteritems(args):
try:
setattr(self, key, ParseType.convert_from_parse(key, value))
except AttributeError:
continue
I chose solution 2 because it's more "future proof" in the case that there are any other attributes that conflict with existing properties of the ParseResource
object.
As an aside, the reason this happened only with User
objects is that User
is derived from ParseResource
, which has the conflicting className
property, but all other objects are derived from Object
, which does not have the conflicting className
property.
Confirming this is working on my end, thanks for such a quick fix!
EDIT FOR FUTURE: see https://github.com/milesrichardson/ParsePy/issues/155#issuecomment-271482650 for solution
Using Parse Server, I am encountering a crash at line 442 in datatypes.py
setattr(self, key, ParseType.convert_from_parse(key, value))
when retrieving the currently logged in user. The user object appears to be being loaded correctly, looking at both the server logs and the error page from my (Django) app.This only happens using the self-hosted server, not the Parse service.