Skip to content

Commit

Permalink
Sync NamedUser class with API spec (#3149)
Browse files Browse the repository at this point in the history
Adds the following attributes:
- display_login
- notification_email
- role_name
- score
- starred_at
- text_matches
- user_view_type
  • Loading branch information
EnricoMi authored Jan 9, 2025
1 parent bb3353b commit b481fab
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 49 deletions.
52 changes: 49 additions & 3 deletions github/NamedUser.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,7 @@ class NamedUser(github.GithubObject.CompletableGithubObject):
- /components/schemas/actor
- /components/schemas/collaborator
- /components/schemas/contributor
- /components/schemas/empty-object
- /components/schemas/nullable-git-user
- /components/schemas/nullable-simple-user
- /components/schemas/organization-invitation
- /components/schemas/public-user
- /components/schemas/simple-user
- /components/schemas/user-search-result-item
Expand All @@ -112,6 +109,7 @@ def _initAttributes(self) -> None:
self._contributions: Attribute[int] = NotSet
self._created_at: Attribute[datetime] = NotSet
self._disk_usage: Attribute[int] = NotSet
self._display_login: Attribute[str] = NotSet
self._email: Attribute[str | None] = NotSet
self._events_url: Attribute[str] = NotSet
self._followers: Attribute[int] = NotSet
Expand All @@ -129,6 +127,7 @@ def _initAttributes(self) -> None:
self._login: Attribute[str] = NotSet
self._name: Attribute[str] = NotSet
self._node_id: Attribute[str] = NotSet
self._notification_email: Attribute[str] = NotSet
self._organizations_url: Attribute[str] = NotSet
self._owned_private_repos: Attribute[int] = NotSet
self._permissions: Attribute[Permissions] = NotSet
Expand All @@ -139,16 +138,21 @@ def _initAttributes(self) -> None:
self._received_events_url: Attribute[str] = NotSet
self._repos_url: Attribute[str] = NotSet
self._role: Attribute[str] = NotSet
self._role_name: Attribute[str] = NotSet
self._score: Attribute[float] = NotSet
self._site_admin: Attribute[bool] = NotSet
self._starred_at: Attribute[str] = NotSet
self._starred_url: Attribute[str] = NotSet
self._subscriptions_url: Attribute[str] = NotSet
self._suspended_at: Attribute[datetime | None] = NotSet
self._team_count: Attribute[int] = NotSet
self._text_matches: Attribute[dict[str, Any]] = NotSet
self._total_private_repos: Attribute[int] = NotSet
self._twitter_username: Attribute[str | None] = NotSet
self._type: Attribute[str] = NotSet
self._updated_at: Attribute[datetime] = NotSet
self._url: Attribute[str] = NotSet
self._user_view_type: Attribute[str] = NotSet

def __eq__(self, other: Any) -> bool:
return isinstance(other, type(self)) and self.login == other.login and self.id == other.id
Expand Down Expand Up @@ -203,6 +207,10 @@ def disk_usage(self) -> int:
self._completeIfNotSet(self._disk_usage)
return self._disk_usage.value

@property
def display_login(self) -> str:
return self._display_login.value

@property
def email(self) -> str | None:
self._completeIfNotSet(self._email)
Expand Down Expand Up @@ -288,6 +296,10 @@ def node_id(self) -> str:
self._completeIfNotSet(self._node_id)
return self._node_id.value

@property
def notification_email(self) -> str:
return self._notification_email.value

@property
def organizations_url(self) -> str:
self._completeIfNotSet(self._organizations_url)
Expand Down Expand Up @@ -338,11 +350,23 @@ def role(self) -> str:
self._completeIfNotSet(self._role)
return self._role.value

@property
def role_name(self) -> str:
return self._role_name.value

@property
def score(self) -> float:
return self._score.value

@property
def site_admin(self) -> bool:
self._completeIfNotSet(self._site_admin)
return self._site_admin.value

@property
def starred_at(self) -> str:
return self._starred_at.value

@property
def starred_url(self) -> str:
self._completeIfNotSet(self._starred_url)
Expand All @@ -363,6 +387,10 @@ def team_count(self) -> int:
self._completeIfNotSet(self._team_count)
return self._team_count.value

@property
def text_matches(self) -> dict[str, Any]:
return self._text_matches.value

@property
def total_private_repos(self) -> int | None:
self._completeIfNotSet(self._total_private_repos)
Expand All @@ -388,6 +416,10 @@ def url(self) -> str:
self._completeIfNotSet(self._url)
return self._url.value

@property
def user_view_type(self) -> str:
return self._user_view_type.value

def get_events(self) -> PaginatedList[Event]:
"""
:calls: `GET /users/{user}/events <https://docs.github.com/en/rest/reference/activity#events>`_
Expand Down Expand Up @@ -570,6 +602,8 @@ def _useAttributes(self, attributes: dict[str, Any]) -> None:
self._created_at = self._makeDatetimeAttribute(attributes["created_at"])
if "disk_usage" in attributes: # pragma no branch
self._disk_usage = self._makeIntAttribute(attributes["disk_usage"])
if "display_login" in attributes: # pragma no branch
self._display_login = self._makeStringAttribute(attributes["display_login"])
if "email" in attributes: # pragma no branch
self._email = self._makeStringAttribute(attributes["email"])
if "events_url" in attributes: # pragma no branch
Expand Down Expand Up @@ -604,6 +638,8 @@ def _useAttributes(self, attributes: dict[str, Any]) -> None:
self._name = self._makeStringAttribute(attributes["name"])
if "node_id" in attributes: # pragma no branch
self._node_id = self._makeStringAttribute(attributes["node_id"])
if "notification_email" in attributes: # pragma no branch
self._notification_email = self._makeStringAttribute(attributes["notification_email"])
if "organizations_url" in attributes: # pragma no branch
self._organizations_url = self._makeStringAttribute(attributes["organizations_url"])
if "owned_private_repos" in attributes: # pragma no branch
Expand All @@ -624,8 +660,14 @@ def _useAttributes(self, attributes: dict[str, Any]) -> None:
self._repos_url = self._makeStringAttribute(attributes["repos_url"])
if "role" in attributes: # pragma no branch
self._role = self._makeStringAttribute(attributes["role"])
if "role_name" in attributes: # pragma no branch
self._role_name = self._makeStringAttribute(attributes["role_name"])
if "score" in attributes: # pragma no branch
self._score = self._makeFloatAttribute(attributes["score"])
if "site_admin" in attributes: # pragma no branch
self._site_admin = self._makeBoolAttribute(attributes["site_admin"])
if "starred_at" in attributes: # pragma no branch
self._starred_at = self._makeStringAttribute(attributes["starred_at"])
if "starred_url" in attributes: # pragma no branch
self._starred_url = self._makeStringAttribute(attributes["starred_url"])
if "subscriptions_url" in attributes: # pragma no branch
Expand All @@ -634,6 +676,8 @@ def _useAttributes(self, attributes: dict[str, Any]) -> None:
self._suspended_at = self._makeDatetimeAttribute(attributes["suspended_at"])
if "team_count" in attributes:
self._team_count = self._makeIntAttribute(attributes["team_count"])
if "text_matches" in attributes: # pragma no branch
self._text_matches = self._makeDictAttribute(attributes["text_matches"])
if "total_private_repos" in attributes: # pragma no branch
self._total_private_repos = self._makeIntAttribute(attributes["total_private_repos"])
if "twitter_username" in attributes: # pragma no branch
Expand All @@ -644,3 +688,5 @@ def _useAttributes(self, attributes: dict[str, Any]) -> None:
self._updated_at = self._makeDatetimeAttribute(attributes["updated_at"])
if "url" in attributes: # pragma no branch
self._url = self._makeStringAttribute(attributes["url"])
if "user_view_type" in attributes: # pragma no branch
self._user_view_type = self._makeStringAttribute(attributes["user_view_type"])
102 changes: 58 additions & 44 deletions tests/NamedUser.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
# #
################################################################################

from __future__ import annotations

from datetime import datetime, timezone

from . import Framework
Expand All @@ -48,6 +50,62 @@ def setUp(self):
super().setUp()
self.user = self.g.get_user("jacquev6")

def testAttributes(self):
self.assertEqual(self.user.avatar_url, "https://avatars.githubusercontent.com/u/327146?v=4")
self.assertIsNone(self.user.bio)
self.assertEqual(self.user.blog, "http://vincent-jacques.net")
self.assertIsNone(self.user.collaborators)
self.assertIsNone(self.user.company)
self.assertIsNone(self.user.contributions)
self.assertEqual(self.user.created_at, datetime(2010, 7, 9, 6, 10, 6, tzinfo=timezone.utc))
self.assertIsNone(self.user.disk_usage)
self.assertIsNone(self.user.display_login)
self.assertEqual(self.user.email, "[email protected]")
self.assertEqual(self.user.events_url, "https://api.github.com/users/jacquev6/events{/privacy}")
self.assertEqual(self.user.followers, 98)
self.assertEqual(self.user.followers_url, "https://api.github.com/users/jacquev6/followers")
self.assertEqual(self.user.following, 62)
self.assertEqual(self.user.following_url, "https://api.github.com/users/jacquev6/following{/other_user}")
self.assertEqual(self.user.gists_url, "https://api.github.com/users/jacquev6/gists{/gist_id}")
self.assertEqual(self.user.gravatar_id, "")
self.assertTrue(self.user.hireable)
self.assertEqual(self.user.html_url, "https://github.com/jacquev6")
self.assertEqual(self.user.id, 327146)
self.assertEqual(self.user.location, "France")
self.assertEqual(self.user.login, "jacquev6")
self.assertEqual(self.user.name, "Vincent Jacques")
self.assertEqual(self.user.node_id, "MDQ6VXNlcjMyNzE0Ng==")
self.assertIsNone(self.user.notification_email)
self.assertEqual(self.user.organizations_url, "https://api.github.com/users/jacquev6/orgs")
self.assertIsNone(self.user.owned_private_repos)
self.assertIsNone(self.user.permissions)
self.assertIsNone(self.user.plan)
self.assertIsNone(self.user.plan)
self.assertIsNone(self.user.plan)
self.assertIsNone(self.user.plan)
self.assertIsNone(self.user.private_gists)
self.assertEqual(self.user.public_gists, 18)
self.assertEqual(self.user.public_repos, 38)
self.assertEqual(self.user.received_events_url, "https://api.github.com/users/jacquev6/received_events")
self.assertEqual(self.user.repos_url, "https://api.github.com/users/jacquev6/repos")
self.assertIsNone(self.user.role_name)
self.assertEqual(self.user.score, None)
self.assertEqual(self.user.site_admin, False)
self.assertIsNone(self.user.starred_at)
self.assertEqual(self.user.starred_url, "https://api.github.com/users/jacquev6/starred{/owner}{/repo}")
self.assertEqual(self.user.subscriptions_url, "https://api.github.com/users/jacquev6/subscriptions")
self.assertIsNone(self.user.suspended_at)
self.assertIsNone(self.user.text_matches)
self.assertIsNone(self.user.total_private_repos)
self.assertIsNone(self.user.twitter_username)
self.assertEqual(self.user.type, "User")
self.assertEqual(self.user.updated_at, datetime(2024, 10, 20, 7, 14, 52, tzinfo=timezone.utc))
self.assertEqual(self.user.url, "https://api.github.com/users/jacquev6")
self.assertEqual(self.user.node_id, "MDQ6VXNlcjMyNzE0Ng==")
self.assertEqual(repr(self.user), 'NamedUser(login="jacquev6")')
self.assertEqual(repr(self.user.plan), "None")
self.assertEqual(self.user.user_view_type, "public")

def testAttributesOfOtherUser(self):
self.user = self.g.get_user("nvie")
self.assertEqual(
Expand Down Expand Up @@ -86,50 +144,6 @@ def testAttributesOfOtherUser(self):
self.assertEqual(self.user.node_id, "MDQ6VXNlcjgzODQ0")
self.assertEqual(repr(self.user), 'NamedUser(login="nvie")')

def testAttributesOfSelf(self):
self.assertEqual(
self.user.avatar_url,
"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
)
self.assertEqual(self.user.bio, "")
self.assertEqual(self.user.blog, "http://vincent-jacques.net")
self.assertEqual(self.user.collaborators, 0)
self.assertEqual(self.user.company, "Criteo")
self.assertEqual(
self.user.created_at,
datetime(2010, 7, 9, 6, 10, 6, tzinfo=timezone.utc),
)
self.assertEqual(self.user.disk_usage, 17080)
self.assertEqual(self.user.email, "[email protected]")
self.assertEqual(self.user.followers, 13)
self.assertEqual(self.user.following, 24)
self.assertEqual(self.user.gravatar_id, "b68de5ae38616c296fa345d2b9df2225")
self.assertFalse(self.user.hireable)
self.assertEqual(self.user.html_url, "https://github.com/jacquev6")
self.assertEqual(self.user.id, 327146)
self.assertEqual(self.user.location, "Paris, France")
self.assertEqual(self.user.login, "jacquev6")
self.assertEqual(self.user.name, "Vincent Jacques")
self.assertEqual(self.user.owned_private_repos, 5)
self.assertEqual(self.user.plan.name, "micro")
self.assertEqual(self.user.plan.collaborators, 1)
self.assertEqual(self.user.plan.space, 614400)
self.assertEqual(self.user.plan.private_repos, 5)
self.assertEqual(self.user.private_gists, 5)
self.assertEqual(self.user.public_gists, 2)
self.assertEqual(self.user.public_repos, 11)
self.assertEqual(
self.user.suspended_at,
datetime(2013, 8, 10, 7, 11, 7, tzinfo=timezone.utc),
)
self.assertEqual(self.user.total_private_repos, 5)
self.assertIsNone(self.user.twitter_username)
self.assertEqual(self.user.type, "User")
self.assertEqual(self.user.url, "https://api.github.com/users/jacquev6")
self.assertEqual(self.user.node_id, "MDQ6VXNlcjMyNzE0Ng==")
self.assertEqual(repr(self.user), 'NamedUser(login="jacquev6")')
self.assertEqual(repr(self.user.plan), 'Plan(name="micro")')

def testGetGists(self):
self.assertListKeyEqual(
self.user.get_gists(),
Expand Down
4 changes: 2 additions & 2 deletions tests/ReplayData/NamedUser.setUp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ None
{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
None
200
[('status', '200 OK'), ('x-ratelimit-remaining', '4960'), ('content-length', '801'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('etag', '"2b9d2167029cc33666d02e0b0e95f2b9"'), ('date', 'Sat, 26 May 2012 11:08:21 GMT'), ('content-type', 'application/json; charset=utf-8')]
{"type":"User","disk_usage":17080,"public_gists":2,"url":"https://api.github.com/users/jacquev6","avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","public_repos":11,"hireable":false,"private_gists":5,"plan":{"private_repos":5,"collaborators":1,"name":"micro","space":614400},"bio":"","company":"Criteo","blog":"http://vincent-jacques.net","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","login":"jacquev6","total_private_repos":5,"email":"[email protected]","collaborators":0,"followers":13,"name":"Vincent Jacques","owned_private_repos":5,"created_at":"2010-07-09T06:10:06Z","suspended_at":"2013-08-10T07:11:07Z","location":"Paris, France","id":327146,"following":24,"html_url":"https://github.com/jacquev6", "node_id":"MDQ6VXNlcjMyNzE0Ng=="}
[('Date', 'Fri, 03 Jan 2025 22:05:16 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"cdcdd165941281cdc3948a0cdff00dcb40d91a0ba044e67272d5b433326e8f81"'), ('Last-Modified', 'Sun, 20 Oct 2024 07:14:52 GMT'), ('X-OAuth-Scopes', 'read:discussion, repo'), ('X-Accepted-OAuth-Scopes', ''), ('github-authentication-token-expiration', '2025-02-04 16:42:10 UTC'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('x-github-api-version-selected', '2022-11-28'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4996'), ('X-RateLimit-Reset', '1735944560'), ('X-RateLimit-Used', '4'), ('X-RateLimit-Resource', 'core'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '0'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('Transfer-Encoding', 'chunked'), ('Server', 'github.com'), ('X-GitHub-Request-Id', 'DEEE:4E297:23C6134F:24ABF6D7:67785F1C')]
{"login":"jacquev6","id":327146,"node_id":"MDQ6VXNlcjMyNzE0Ng==","avatar_url":"https://avatars.githubusercontent.com/u/327146?v=4","gravatar_id":"","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User","user_view_type":"public","site_admin":false,"name":"Vincent Jacques","company":null,"blog":"http://vincent-jacques.net","location":"France","email":"[email protected]","hireable":true,"bio":null,"twitter_username":null,"public_repos":38,"public_gists":18,"followers":98,"following":62,"created_at":"2010-07-09T06:10:06Z","updated_at":"2024-10-20T07:14:52Z"}
1 change: 1 addition & 0 deletions tests/Search.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def testPaginateSearchUsers(self):
],
)
self.assertEqual(users.totalCount, 6038)
self.assertEqual(users[0].score, 1.0)

def testGetPageOnSearchUsers(self):
users = self.g.search_users("", location="Berlin")
Expand Down

0 comments on commit b481fab

Please sign in to comment.