From d31742a71955e830af17add7a89ec428ea52129d Mon Sep 17 00:00:00 2001 From: Dan Vanderkam Date: Wed, 14 Oct 2015 15:10:46 -0400 Subject: [PATCH] Add repo.get_stargazers_with_dates() --- github/Repository.py | 14 ++++ github/Stargazer.py | 64 +++++++++++++++++++ .../Repository.testGetStargazersWithDates.txt | 33 ++++++++++ github/tests/Repository.py | 15 +++++ 4 files changed, 126 insertions(+) create mode 100644 github/Stargazer.py create mode 100644 github/tests/ReplayData/Repository.testGetStargazersWithDates.txt diff --git a/github/Repository.py b/github/Repository.py index 640bb857..8c8892f4 100644 --- a/github/Repository.py +++ b/github/Repository.py @@ -67,6 +67,7 @@ import github.StatsCommitActivity import github.StatsCodeFrequency import github.StatsParticipation import github.StatsPunchCard +import github.Stargazer class Repository(github.GithubObject.CompletableGithubObject): @@ -1739,6 +1740,19 @@ class Repository(github.GithubObject.CompletableGithubObject): None ) + def get_stargazers_with_dates(self): + """ + :calls: `GET /repos/:owner/:repo/stargazers `_ + :rtype: :class:`github.PaginatedList.PaginatedList` of :class:`github.Stargazer.Stargazer` + """ + return github.PaginatedList.PaginatedList( + github.Stargazer.Stargazer, + self._requester, + self.url + "/stargazers", + None, + headers={'Accept': 'application/vnd.github.v3.star+json'} + ) + def get_stats_contributors(self): """ :calls: `GET /repos/:owner/:repo/stats/contributors `_ diff --git a/github/Stargazer.py b/github/Stargazer.py new file mode 100644 index 00000000..4f261c64 --- /dev/null +++ b/github/Stargazer.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# ########################## Copyrights and license ############################ +# # +# Copyright 2012 Christopher Gilbert # +# Copyright 2012 Steve English # +# Copyright 2012 Vincent Jacques # +# Copyright 2012 Zearin # +# Copyright 2013 AKFish # +# Copyright 2013 Adrian Petrescu # +# Copyright 2013 Mark Roddy # +# Copyright 2013 Vincent Jacques # +# Copyright 2013 martinqt # +# Copyright 2015 Dan Vanderkam # +# # +# This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ # +# # +# PyGithub is free software: you can redistribute it and/or modify it under # +# the terms of the GNU Lesser General Public License as published by the Free # +# Software Foundation, either version 3 of the License, or (at your option) # +# any later version. # +# # +# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # +# details. # +# # +# You should have received a copy of the GNU Lesser General Public License # +# along with PyGithub. If not, see . # +# # +# ############################################################################## + +import github + + +class Stargazer(github.GithubObject.NonCompletableGithubObject): + """ + This class represents Stargazers with the date of starring as returned by + https://developer.github.com/v3/activity/starring/#alternative-response-with-star-creation-timestamps + """ + @property + def starred_at(self): + """ + :type: datetime.datetime + """ + return self._starred_at.value + + @property + def user(self): + """ + :type: :class:`github.NamedUser` + """ + return self._user.value + + def _initAttributes(self): + self._starred_at = github.GithubObject.NotSet + self._user = github.GithubObject.NotSet + self._url = github.GithubObject.NotSet + + def _useAttributes(self, attributes): + if 'starred_at' in attributes: + self._starred_at = self._makeDatetimeAttribute(attributes['starred_at']) + if 'user' in attributes: + self._user = self._makeClassAttribute(github.NamedUser.NamedUser, attributes['user']) diff --git a/github/tests/ReplayData/Repository.testGetStargazersWithDates.txt b/github/tests/ReplayData/Repository.testGetStargazersWithDates.txt new file mode 100644 index 00000000..ef6e0dd1 --- /dev/null +++ b/github/tests/ReplayData/Repository.testGetStargazersWithDates.txt @@ -0,0 +1,33 @@ +https +GET +api.github.com +None +/users/danvk +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +null +200 +[('content-length', '1295'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding'), ('x-served-by', '13d09b732ebe76f892093130dc088652'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('etag', '"646d82e27d1cb55020ba0b6c901d15ce"'), ('access-control-allow-credentials', 'true'), ('status', '200 OK'), ('x-ratelimit-remaining', '4915'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('x-github-request-id', '44AE6A38:AB2B:3D4623E:561EA76C'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('last-modified', 'Wed, 07 Oct 2015 13:43:17 GMT'), ('date', 'Wed, 14 Oct 2015 19:05:17 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1444851351')] +{"login":"danvk","id":98301,"avatar_url":"https://avatars.githubusercontent.com/u/98301?v=3","gravatar_id":"","url":"https://api.github.com/users/danvk","html_url":"https://github.com/danvk","followers_url":"https://api.github.com/users/danvk/followers","following_url":"https://api.github.com/users/danvk/following{/other_user}","gists_url":"https://api.github.com/users/danvk/gists{/gist_id}","starred_url":"https://api.github.com/users/danvk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danvk/subscriptions","organizations_url":"https://api.github.com/users/danvk/orgs","repos_url":"https://api.github.com/users/danvk/repos","events_url":"https://api.github.com/users/danvk/events{/privacy}","received_events_url":"https://api.github.com/users/danvk/received_events","type":"User","site_admin":false,"name":"Dan Vanderkam","company":null,"blog":"http://danvk.org","location":"New York, NY","email":"danvdk@gmail.com","hireable":null,"bio":null,"public_repos":69,"public_gists":76,"followers":103,"following":3,"created_at":"2009-06-23T20:44:04Z","updated_at":"2015-10-07T13:43:17Z","private_gists":0,"total_private_repos":0,"owned_private_repos":0,"disk_usage":269679,"collaborators":0,"plan":{"name":"free","space":976562499,"collaborators":0,"private_repos":0}} + +https +GET +api.github.com +None +/repos/danvk/comparea +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +null +200 +[('content-length', '4432'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding'), ('x-served-by', '065b43cd9674091fec48a221b420fbb3'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('etag', '"2cc0aa4e78ef70f886d92ac338e3e22b"'), ('access-control-allow-credentials', 'true'), ('status', '200 OK'), ('x-ratelimit-remaining', '4914'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('x-github-request-id', '44AE6A38:AB2F:94E8736:561EA76D'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('last-modified', 'Sat, 09 May 2015 19:14:45 GMT'), ('date', 'Wed, 14 Oct 2015 19:05:17 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1444851351')] +{"id":22370702,"name":"comparea","full_name":"danvk/comparea","owner":{"login":"danvk","id":98301,"avatar_url":"https://avatars.githubusercontent.com/u/98301?v=3","gravatar_id":"","url":"https://api.github.com/users/danvk","html_url":"https://github.com/danvk","followers_url":"https://api.github.com/users/danvk/followers","following_url":"https://api.github.com/users/danvk/following{/other_user}","gists_url":"https://api.github.com/users/danvk/gists{/gist_id}","starred_url":"https://api.github.com/users/danvk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danvk/subscriptions","organizations_url":"https://api.github.com/users/danvk/orgs","repos_url":"https://api.github.com/users/danvk/repos","events_url":"https://api.github.com/users/danvk/events{/privacy}","received_events_url":"https://api.github.com/users/danvk/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/danvk/comparea","description":"Compare geographic features","fork":false,"url":"https://api.github.com/repos/danvk/comparea","forks_url":"https://api.github.com/repos/danvk/comparea/forks","keys_url":"https://api.github.com/repos/danvk/comparea/keys{/key_id}","collaborators_url":"https://api.github.com/repos/danvk/comparea/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/danvk/comparea/teams","hooks_url":"https://api.github.com/repos/danvk/comparea/hooks","issue_events_url":"https://api.github.com/repos/danvk/comparea/issues/events{/number}","events_url":"https://api.github.com/repos/danvk/comparea/events","assignees_url":"https://api.github.com/repos/danvk/comparea/assignees{/user}","branches_url":"https://api.github.com/repos/danvk/comparea/branches{/branch}","tags_url":"https://api.github.com/repos/danvk/comparea/tags","blobs_url":"https://api.github.com/repos/danvk/comparea/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/danvk/comparea/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/danvk/comparea/git/refs{/sha}","trees_url":"https://api.github.com/repos/danvk/comparea/git/trees{/sha}","statuses_url":"https://api.github.com/repos/danvk/comparea/statuses/{sha}","languages_url":"https://api.github.com/repos/danvk/comparea/languages","stargazers_url":"https://api.github.com/repos/danvk/comparea/stargazers","contributors_url":"https://api.github.com/repos/danvk/comparea/contributors","subscribers_url":"https://api.github.com/repos/danvk/comparea/subscribers","subscription_url":"https://api.github.com/repos/danvk/comparea/subscription","commits_url":"https://api.github.com/repos/danvk/comparea/commits{/sha}","git_commits_url":"https://api.github.com/repos/danvk/comparea/git/commits{/sha}","comments_url":"https://api.github.com/repos/danvk/comparea/comments{/number}","issue_comment_url":"https://api.github.com/repos/danvk/comparea/issues/comments{/number}","contents_url":"https://api.github.com/repos/danvk/comparea/contents/{+path}","compare_url":"https://api.github.com/repos/danvk/comparea/compare/{base}...{head}","merges_url":"https://api.github.com/repos/danvk/comparea/merges","archive_url":"https://api.github.com/repos/danvk/comparea/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/danvk/comparea/downloads","issues_url":"https://api.github.com/repos/danvk/comparea/issues{/number}","pulls_url":"https://api.github.com/repos/danvk/comparea/pulls{/number}","milestones_url":"https://api.github.com/repos/danvk/comparea/milestones{/number}","notifications_url":"https://api.github.com/repos/danvk/comparea/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/danvk/comparea/labels{/name}","releases_url":"https://api.github.com/repos/danvk/comparea/releases{/id}","created_at":"2014-07-29T07:02:43Z","updated_at":"2015-05-09T19:14:45Z","pushed_at":"2015-04-19T00:30:46Z","git_url":"git://github.com/danvk/comparea.git","ssh_url":"git@github.com:danvk/comparea.git","clone_url":"https://github.com/danvk/comparea.git","svn_url":"https://github.com/danvk/comparea","homepage":null,"size":24675,"stargazers_count":6,"watchers_count":6,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":23,"forks":3,"open_issues":23,"watchers":6,"default_branch":"master","permissions":{"admin":true,"push":true,"pull":true},"network_count":3,"subscribers_count":1} + +https +GET +api.github.com +None +/repos/danvk/comparea/stargazers +{'Authorization': 'Basic login_and_password_removed', 'Accept': 'application/vnd.github.v3.star+json', 'User-Agent': 'PyGithub/Python'} +null +200 +[('content-length', '5547'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding'), ('x-served-by', '2c18a09f3ac5e4dd1e004af7c5a94769'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('etag', '"83247ceb0b43ff0c9c1d97c5cc427ceb"'), ('access-control-allow-credentials', 'true'), ('status', '200 OK'), ('x-ratelimit-remaining', '4913'), ('x-github-media-type', 'github.v3; param=star; format=json'), ('access-control-expose-headers', 'ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('x-github-request-id', '44AE6A38:AB2F:94E8764:561EA76D'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Wed, 14 Oct 2015 19:05:17 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1444851351')] +[{"starred_at":"2014-08-13T19:22:05Z","user":{"login":"sAlexander","id":20961,"avatar_url":"https://avatars.githubusercontent.com/u/20961?v=3","gravatar_id":"","url":"https://api.github.com/users/sAlexander","html_url":"https://github.com/sAlexander","followers_url":"https://api.github.com/users/sAlexander/followers","following_url":"https://api.github.com/users/sAlexander/following{/other_user}","gists_url":"https://api.github.com/users/sAlexander/gists{/gist_id}","starred_url":"https://api.github.com/users/sAlexander/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sAlexander/subscriptions","organizations_url":"https://api.github.com/users/sAlexander/orgs","repos_url":"https://api.github.com/users/sAlexander/repos","events_url":"https://api.github.com/users/sAlexander/events{/privacy}","received_events_url":"https://api.github.com/users/sAlexander/received_events","type":"User","site_admin":false}},{"starred_at":"2014-10-15T05:02:30Z","user":{"login":"ThomasG77","id":642120,"avatar_url":"https://avatars.githubusercontent.com/u/642120?v=3","gravatar_id":"","url":"https://api.github.com/users/ThomasG77","html_url":"https://github.com/ThomasG77","followers_url":"https://api.github.com/users/ThomasG77/followers","following_url":"https://api.github.com/users/ThomasG77/following{/other_user}","gists_url":"https://api.github.com/users/ThomasG77/gists{/gist_id}","starred_url":"https://api.github.com/users/ThomasG77/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ThomasG77/subscriptions","organizations_url":"https://api.github.com/users/ThomasG77/orgs","repos_url":"https://api.github.com/users/ThomasG77/repos","events_url":"https://api.github.com/users/ThomasG77/events{/privacy}","received_events_url":"https://api.github.com/users/ThomasG77/received_events","type":"User","site_admin":false}},{"starred_at":"2015-04-14T15:22:40Z","user":{"login":"therusek","id":4291399,"avatar_url":"https://avatars.githubusercontent.com/u/4291399?v=3","gravatar_id":"","url":"https://api.github.com/users/therusek","html_url":"https://github.com/therusek","followers_url":"https://api.github.com/users/therusek/followers","following_url":"https://api.github.com/users/therusek/following{/other_user}","gists_url":"https://api.github.com/users/therusek/gists{/gist_id}","starred_url":"https://api.github.com/users/therusek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/therusek/subscriptions","organizations_url":"https://api.github.com/users/therusek/orgs","repos_url":"https://api.github.com/users/therusek/repos","events_url":"https://api.github.com/users/therusek/events{/privacy}","received_events_url":"https://api.github.com/users/therusek/received_events","type":"User","site_admin":false}},{"starred_at":"2015-04-29T00:09:40Z","user":{"login":"athomann","id":605577,"avatar_url":"https://avatars.githubusercontent.com/u/605577?v=3","gravatar_id":"","url":"https://api.github.com/users/athomann","html_url":"https://github.com/athomann","followers_url":"https://api.github.com/users/athomann/followers","following_url":"https://api.github.com/users/athomann/following{/other_user}","gists_url":"https://api.github.com/users/athomann/gists{/gist_id}","starred_url":"https://api.github.com/users/athomann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/athomann/subscriptions","organizations_url":"https://api.github.com/users/athomann/orgs","repos_url":"https://api.github.com/users/athomann/repos","events_url":"https://api.github.com/users/athomann/events{/privacy}","received_events_url":"https://api.github.com/users/athomann/received_events","type":"User","site_admin":false}},{"starred_at":"2015-04-29T14:26:46Z","user":{"login":"jcapron","id":2346847,"avatar_url":"https://avatars.githubusercontent.com/u/2346847?v=3","gravatar_id":"","url":"https://api.github.com/users/jcapron","html_url":"https://github.com/jcapron","followers_url":"https://api.github.com/users/jcapron/followers","following_url":"https://api.github.com/users/jcapron/following{/other_user}","gists_url":"https://api.github.com/users/jcapron/gists{/gist_id}","starred_url":"https://api.github.com/users/jcapron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jcapron/subscriptions","organizations_url":"https://api.github.com/users/jcapron/orgs","repos_url":"https://api.github.com/users/jcapron/repos","events_url":"https://api.github.com/users/jcapron/events{/privacy}","received_events_url":"https://api.github.com/users/jcapron/received_events","type":"User","site_admin":false}},{"starred_at":"2015-05-09T19:14:45Z","user":{"login":"JoePython1","id":307737,"avatar_url":"https://avatars.githubusercontent.com/u/307737?v=3","gravatar_id":"","url":"https://api.github.com/users/JoePython1","html_url":"https://github.com/JoePython1","followers_url":"https://api.github.com/users/JoePython1/followers","following_url":"https://api.github.com/users/JoePython1/following{/other_user}","gists_url":"https://api.github.com/users/JoePython1/gists{/gist_id}","starred_url":"https://api.github.com/users/JoePython1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JoePython1/subscriptions","organizations_url":"https://api.github.com/users/JoePython1/orgs","repos_url":"https://api.github.com/users/JoePython1/repos","events_url":"https://api.github.com/users/JoePython1/events{/privacy}","received_events_url":"https://api.github.com/users/JoePython1/received_events","type":"User","site_admin":false}}] + diff --git a/github/tests/Repository.py b/github/tests/Repository.py index 8bba7e01..a2d9bb76 100644 --- a/github/tests/Repository.py +++ b/github/tests/Repository.py @@ -344,6 +344,21 @@ class Repository(Framework.TestCase): def testGetStargazers(self): self.assertListKeyEqual(self.repo.get_stargazers(), lambda u: u.login, ["Stals", "att14", "jardon-u", "huxley", "mikofski", "L42y", "fanzeyi", "abersager", "waylan", "adericbourg", "tallforasmurf", "pvicente", "roskakori", "michaelpedersen", "stefanfoulis", "equus12", "JuRogn", "joshmoore", "jsilter", "dasapich", "ritratt", "hcilab", "vxnick", "pmuilu", "herlo", "malexw", "ahmetvurgun", "PengGu", "cosmin", "Swop", "kennethreitz", "bryandyck", "jason2506", "zsiciarz", "waawal", "gregorynicholas", "sente", "richmiller55", "thouis", "mazubieta", "michaelhood", "engie", "jtriley", "oangeor", "coryking", "noddi", "alejo8591", "omab", "Carreau", "bilderbuchi", "schwa", "rlerallut", "PengHub", "zoek1", "xobb1t", "notgary", "hattya", "ZebtinRis", "aaronhall", "youngsterxyf", "ailling", "gregwjacobs", "n0rmrx", "awylie", "firstthumb", "joshbrand", "berndca"]) + def testGetStargazersWithDates(self): + repo = self.g.get_user("danvk").get_repo("comparea") + self.assertListKeyEqual( + repo.get_stargazers_with_dates(), + lambda stargazer: (stargazer.starred_at, stargazer.user.login), + [ + (datetime.datetime(2014, 8, 13, 19, 22, 5), u'sAlexander'), + (datetime.datetime(2014, 10, 15, 5, 2, 30), u'ThomasG77'), + (datetime.datetime(2015, 4, 14, 15, 22, 40), u'therusek'), + (datetime.datetime(2015, 4, 29, 0, 9, 40), u'athomann'), + (datetime.datetime(2015, 4, 29, 14, 26, 46), u'jcapron'), + (datetime.datetime(2015, 5, 9, 19, 14, 45), u'JoePython1') + ] + ) + def testGetSubscribers(self): self.assertListKeyEqual(self.repo.get_subscribers(), lambda u: u.login, ["jacquev6", "equus12", "bilderbuchi", "hcilab", "hattya", "firstthumb", "gregwjacobs", "sagarsane", "liang456", "berndca", "Lyloa"])