Repository: PyGithub/PyGithub

Issue:
Implement __hash__() and __eq__() on NamedUser
I have a case where I'm processing the list of reviewers on a Pull Request. When the same person does two reviews the `NamedUser` return from the `PullRequest.get_reviews()`, while they have the same `login`, `id`, and `name`, don't have the same hash value. 

If you implement `__hash__()` the python docs strongly recommend implementing `__eq__()` based upon the same values. 

It would be nice to have the python build in functions be able to construct the unique list of reviewers. 


Discussion:
Example 

```
>> prev_reviewers= list(set([review.user for review in pull.get_reviews() if review.state in ['CHANGES_REQUESTED']]))
>> print prev_reviewers
[NamedUser(login="Doug"), NamedUser(login="Larry"), NamedUser(login="Steve"), NamedUser(login="Doug"), NamedUser(login="Steve")]

or reviewer in prev_reviewers:
...     print reviewer, reviewer.id, reviewer.__hash__()
... 

NamedUser(login="Doug") 1690 272863621
NamedUser(login="Larry") 3875 272863633
NamedUser(login="Steve") 447 272863677
NamedUser(login="Doug") 1690 272863589
NamedUser(login="Steve") 447 272863597
```

Resolving patch:
diff --git a/github/NamedUser.py b/github/NamedUser.py
--- a/github/NamedUser.py
+++ b/github/NamedUser.py
@@ -46,6 +46,12 @@ class NamedUser(github.GithubObject.CompletableGithubObject):
     def __repr__(self):
         return self.get__repr__({"login": self._login.value})
 
+    def __hash__(self):
+        return hash((self.id, self.login))
+
+    def __eq__(self, other):
+        return isinstance(other, type(self)) and self.login == other.login and self.id == other.id
+
     @property
     def avatar_url(self):
         """


Test patch:
diff --git a/github/tests/NamedUser.py b/github/tests/NamedUser.py
--- a/github/tests/NamedUser.py
+++ b/github/tests/NamedUser.py
@@ -147,3 +147,10 @@ def testGetReceivedEvents(self):
 
     def testGetKeys(self):
         self.assertListKeyEqual(self.user.get_keys(), lambda k: k.id, [3557894, 3791954, 3937333, 4051357, 4051492])
+
+    def testUserEquality(self):
+        u1 = self.g.get_user("nvie")
+        u2 = self.g.get_user("nvie")
+        self.assertTrue(u1 == u2)
+        self.assertEqual(u1, u2)
+        self.assertEqual(u1.__hash__(), u2.__hash__())    
\ No newline at end of file
diff --git a/github/tests/ReplayData/NamedUser.testUserEquality.txt b/github/tests/ReplayData/NamedUser.testUserEquality.txt
new file mode 100644
--- /dev/null
+++ b/github/tests/ReplayData/NamedUser.testUserEquality.txt
@@ -0,0 +1,21 @@
+https
+GET
+api.github.com
+None
+/users/nvie
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('status', '200 OK'), ('x-ratelimit-remaining', '4994'), ('content-length', '598'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('etag', '"66a516a2007fb7df8bbb3f9cc7cb2da8"'), ('date', 'Fri, 18 May 2012 19:46:37 GMT'), ('content-type', 'application/json; charset=utf-8')]
+{"public_gists":16,"type":"User","hireable":false,"company":"3rd Cloud","url":"https://api.github.com/users/nvie","gravatar_id":"c5a7f21b46df698f3db31c37ed0cf55a","bio":null,"followers":296,"blog":"http://nvie.com","avatar_url":"https://secure.gravatar.com/avatar/c5a7f21b46df698f3db31c37ed0cf55a?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","login":"nvie","email":"vincent@3rdcloud.com","public_repos":61,"html_url":"https://github.com/nvie","name":"Vincent Driessen","created_at":"2009-05-12T21:19:38Z","location":"Netherlands","id":83844,"following":41}
+
+https
+GET
+api.github.com
+None
+/users/nvie
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('status', '200 OK'), ('x-ratelimit-remaining', '4994'), ('content-length', '598'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('etag', '"66a516a2007fb7df8bbb3f9cc7cb2da8"'), ('date', 'Fri, 18 May 2012 19:46:37 GMT'), ('content-type', 'application/json; charset=utf-8')]
+{"public_gists":16,"type":"User","hireable":false,"company":"3rd Cloud","url":"https://api.github.com/users/nvie","gravatar_id":"c5a7f21b46df698f3db31c37ed0cf55a","bio":null,"followers":296,"blog":"http://nvie.com","avatar_url":"https://secure.gravatar.com/avatar/c5a7f21b46df698f3db31c37ed0cf55a?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","login":"nvie","email":"vincent@3rdcloud.com","public_repos":61,"html_url":"https://github.com/nvie","name":"Vincent Driessen","created_at":"2009-05-12T21:19:38Z","location":"Netherlands","id":83844,"following":41}
\ No newline at end of file