Add equality functions for authentication handlers

A use case for this is mocking.

If you have a function that wrap a call like `requests.post('http://my_url', auth=HTTPBasicAuth(user, password))` and mock requests.post in your tests, calling `assert_called_once_with('http://my_url', auth=HTTPBasicAuth(user, password))` will fail.

Implementing equality functions solves this use case.


Was there already a bug or discussion of this? I didn't notice it if there was.

I'm pretty sure there's no other practical use of this which makes me very conflicted about accepting this.

Yes it would be nice to be able to use `assert_called_once_with` but there are many other ways to do exactly that while also being more thorough/correct about what the mocked out request was. Specifically, I'm not convinced that the HTTPDigestAuth equality is correct.

As an entirely separate note, I'm pretty sure you only need to implement `__eq__` or `__ne__`, not both.


I have some concerns about defining equality on auth handlers. One thing almost all auth handlers do is set hooks on a given request, but the auth handler equality functions don't (and cannot check for that). So while a may be equal to b, they're fundamentally very unlike each other, and cannot be used in the place of each other.

Does equality not fall back on identity? Is it not possible to simply confirm that it was called with a specific auth handler?


Hi,

I did not found a bug or discussion about this either.

About `__ne__()`,  the python 2.7 documentation states:

> Accordingly, when defining `__eq__()`, one should also define `__ne__()` so that the operators will behave as expected.

This is no longer the case in python 3, where `__ne__()` is indeed not mandatory.


> Does equality not fall back on identity? Is it not possible to simply confirm that it was called with a specific auth handler?

@Lukasa you're correct. That said it's not exactly simple. Consider a poorly written API wrapper where someone does something like:

``` py
class MyWrapper(object):
    def __init__(self, username, password):
        self.username = username
        self.password = password
        self.session = requests.Session()

    def list_objects(self, *args, **kwargs):
        return session.get(url, auth=HTTPBasicAuth(self.username, self.password))
```

Obviously if ^ were better written it'd be easier to test the way you describe, but we know nothing about @Malizor's case (or anyone else's) and we always get push back for encouraging better design/testing practices.

> the python 2.7 documentation states ...

Ah, I forgot that the always ancient Python 2 has silly things like this.


Well my specific use case is similar to your example @sigmavirus24. It is a wrapper except it actually does some things before (build params depending on args…) and after (error handling, result formatting).

@Lukasa : HTTPBasicAuth and HTTPProxyAuth just add a constant header on each request, so equality should not cause any problem here.

HTTPDigestAuth is indeed more complicated with it's hook system. Perhaps I should only compare the username and password?


@Malizor you could just do

``` py
class MyWrapper(object):
    def __init__(self, username, password):
        self.basic_auth = HTTPBasicAuth(username, password)
        self.digest_auth = HTTPDigestAuth(username, password)

    def list_objects(self):
        return self.session.get(url, auth=self.basic_auth)
```

And then

``` py
self.client.session.assert_called_once_with(url, auth=self.client.basic_auth)
```


Well in fact it is not in a class, it's a simple function.

Something like this:

``` python
def list_objects(user, password):
        return self.session.get(url, auth=HTTPDigestAuth(username, password))
```

with a few more lines of course ;)


@Malizor this seems like a fine usecase to me. I'm going to merge this in, then simplify the digest check to simply verify the parameters: username, password. 

In other news, I hadn't looked at that digest code in a long time! I had a blast writing that long ago. So many memories.