-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix bug with str(OAuthDependentTokenResponse) #644
Conversation
The stringifier inherited from OAuthTokenResponse assumes that `self.get(...)` is safe, but that's only true when the data is a `dict`, as it normally is. OAuthDependentTokenResponse has `self.data: list`. Therefore, this needs a check and special handling in the stringifier. Add a test case which fails without this addition, then make the `get()` call conditional on the type of the underlying data. Arguably this is a "bad" division of responsibilities (base class knows about its subclasses), but any alternative which solves this generically is more verbose or touches on core codepaths like the central `GlobusHTTPResponse.get` implementation.
if isinstance(self.data, dict): | ||
id_token_to_print = t.cast(t.Optional[str], self.get("id_token")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels boundary breaking to have this check self.data
but then retrieve a value by calling self.get(...)
Could we either
- If we're comfortable that sometimes data in
OAuthTokenResponse
won't be a dict, make.get
safe forOAuthTokenResponse
. Maybe override the get method likeclass OAuthTokenReponse(GlobusHTTPResponse): ... def __getitem__(self, key: t.Union[str, int, slice])) -> t.Any: if not isinstance(self.data, dict): return None return super().__getitem__(key) ...
- Or check the same thing we're querying from:
- Move
self.get(...)
toself.data.get(...)
so that we're querying the same object we just verified, not relying on the fact that the internals of__getitem__
do that - I guess error handling would be the way to handle the "not-a-dict" option from the response interface level
try: id_token_to_print = t.cast(t.Optional[str], self.get("id_token")) except ValueError: id_token_to_print = None
- Move
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for identify this -- I didn't love it either but didn't have better ideas at the time. Why don't we go with redefining get
on this one class to handle non-dict data? I'll put together a version of that later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened this up in order to make the change today, and I realized that there's very little reason for GlobusHTTPResponse.get
not to handle list
data nicely.
I've gone ahead and added a commit which moves the check to the base class' get
method, and removes this check here entirely. It also adds an appropriate changelog item.
It's a pretty significant change in where the fix is applied, and it's breadth of potential impact and utility. But I have started to think that it's the best way to fix this problem.
`GlobusHTTPResponse.get` checks if the data is `None` for special behavior, but this check can easily be extended to the case in which `data` is a list. This makes `get()` safer to use when data may be a dict or list, as it won't try to user `list.get` and encounter an AttributeError. Add a changelog fragment to this effect. The result is also that the changes to `OAuthTokenResponse` to handle the `OauthDependentTokenResponse` are no longer necessary and are reverted here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
The stringifier inherited from OAuthTokenResponse assumes that
self.get(...)
is safe, but that's only true when the data is adict
, as it normally is.OAuthDependentTokenResponse has
self.data: list
. Therefore, this needs a check and special handling in the stringifier.Add a test case which fails without this addition, then make the
get()
call conditional on the type of the underlying data.Arguably this is a "bad" division of responsibilities (base class knows about its subclasses), but any alternative which solves this generically is more verbose or touches on core codepaths like the central
GlobusHTTPResponse.get
implementation.