Closed
Labels
user-experienceEnsuring that users have a good experience using the libraryEnsuring that users have a good experience using the library
Milestone
Description
Checklist
- The bug is reproducible against the latest release and/or
master. - There are no similar issues or pull requests to fix it yet.
Describe the bug
Merging of request-level auth unset does not take priority over Client level value.
To reproduce
Try to 'unset' the client set authorization values.
with httpx.Client(auth=('tom', 'mot123')) as client:
r = client.get('http://httpbin.org', auth=None)
assert 'Authorization' not in r.request.headers['Authorization']Expected behavior
The documentation for Merging of configuration states For all other parameters, the request-level value takes priority. and shows this example:
with httpx.Client(auth=('tom', 'mot123')) as client:
r = client.get('https://example.com', auth=('alice', 'ecila123'))
_, _, auth = r.request.headers['Authorization'].partition(' ')I would expect that by setting auth=None in the request level that the individual request would be sent without authorization.
Actual behavior
In reality, the authorization is not overridden. This is due to this line: https://github.com/encode/httpx/blob/master/httpx/_client.py#L258
Overriding the auth value via this method works:
with httpx.Client(auth=('tom', 'mot123')) as client:
r = client.get('http://httpbin.org', auth=Auth())
assert 'Authorization' not in r.request.headers['Authorization']Personally, I found passing in auth=None to be more intuitive than auth=Auth() to indicate that no authorization should be used.
Metadata
Metadata
Assignees
Labels
user-experienceEnsuring that users have a good experience using the libraryEnsuring that users have a good experience using the library
Activity
lovelydinosaur commentedon May 29, 2020
Right, so...
Presumably you'd get the same behaviour with
param,cookies,headers, orauth...All of these default to
Nonein the method signature, and python doesn't give us any way of determining when a user has passed an explicitauth=Nonevs. nothing being passed.We could change the method signature to use open-ended keyword arguments,
eg **kwargs, but that's far less descriptive, and then needs a bunch of extra checking.Alternately we could change them to some sentinel empty value, so eg
params = EMPTY, but that's a big awkward.I'd be interested to know if you get similar behaviour in, say, requests, or if they're working around this being a bit of an awkward pattern in a graceful way?
We may well just want to make sure we're documenting this well, since it's a usability gotcha, even if it's not buggy.
yeraydiazdiaz commentedon May 29, 2020
I was thinking on init we could set
self.authto theUNSETtype ifauth=None. Then at request time we can safely useNoneto signify "no auth"?lovelydinosaur commentedon May 29, 2020
Only if we changed the
.request()signature. Otherwise there's no way of determining the difference between theauth=Nonedefault, and an explicitauth=Nonepassed by the user.florimondmanca commentedon May 29, 2020
Looks like Requests behaves the same as we do for the specific case of
auth, i.e.request(auth=None)is treated as "use theauthvalue on the session".But honestly I'd consider it a usability bug too.
Eg we have
timeout=Nonemeaning "no timeout", so it'd be okay to assume thatauth=Noneshould mean "no auth".Do we see an issue with considering using the same
UNSETtrick as we did for timeouts here (and maybe on other parameters such asheaders,cookies,params)?florimondmanca commentedon May 29, 2020
I was going to suggest
.build_request()/.send()as a workaround, but as expected it won't work either — the "use client auth if request auth isNone" logic is made inside.send().cansarigol commentedon May 30, 2020
Can we use a decorator to evaluate signature data before set?