mirror of
https://github.com/status-im/PyGithub.git
synced 2026-09-02 11:51:10 +00:00
First step of implementation of Repository.get_stats_xxx (#203)
This commit is contained in:
@@ -61,6 +61,7 @@ import github.Download
|
||||
import github.Permissions
|
||||
import github.Event
|
||||
import github.Legacy
|
||||
import github.StatsContributor
|
||||
|
||||
|
||||
class Repository(github.GithubObject.CompletableGithubObject):
|
||||
@@ -1690,6 +1691,75 @@ class Repository(github.GithubObject.CompletableGithubObject):
|
||||
None
|
||||
)
|
||||
|
||||
def get_stats_contributors(self):
|
||||
"""
|
||||
:calls: `GET /repos/:owner/:repo/stats/contributors <http://developer.github.com/v3/repos/statistics/#get-contributors-list-with-additions-deletions-and-commit-counts>`_
|
||||
:rtype: None or list of :class:`github.StatsContributor.StatsContributor`
|
||||
"""
|
||||
headers, data = self._requester.requestJsonAndCheck(
|
||||
"GET",
|
||||
self.url + "/stats/contributors"
|
||||
)
|
||||
if data == {}:
|
||||
return None
|
||||
else:
|
||||
return [
|
||||
github.StatsContributor.StatsContributor(self._requester, headers, attributes, completed=True)
|
||||
for attributes in data
|
||||
]
|
||||
|
||||
def get_stats_commit_activity(self):
|
||||
"""
|
||||
:calls: `GET /repos/:owner/:repo/stats/commit_activity <developer.github.com/v3/repos/statistics/#get-the-number-of-commits-per-hour-in-each-day>`_
|
||||
"""
|
||||
headers, data = self._requester.requestJsonAndCheck(
|
||||
"GET",
|
||||
self.url + "/stats/commit_activity"
|
||||
)
|
||||
if data == {}:
|
||||
return None
|
||||
else:
|
||||
return data # @todo Return something structured
|
||||
|
||||
def get_stats_code_frequency(self):
|
||||
"""
|
||||
:calls: `GET /repos/:owner/:repo/stats/code_frequency <http://developer.github.com/v3/repos/statistics/#get-the-number-of-additions-and-deletions-per-week>`_
|
||||
"""
|
||||
headers, data = self._requester.requestJsonAndCheck(
|
||||
"GET",
|
||||
self.url + "/stats/code_frequency"
|
||||
)
|
||||
if data == {}:
|
||||
return None
|
||||
else:
|
||||
return data # @todo Return something structured
|
||||
|
||||
def get_stats_participation(self):
|
||||
"""
|
||||
:calls: `GET /repos/:owner/:repo/stats/participation <http://developer.github.com/v3/repos/statistics/#get-the-weekly-commit-count-for-the-repo-owner-and-everyone-else>`_
|
||||
"""
|
||||
headers, data = self._requester.requestJsonAndCheck(
|
||||
"GET",
|
||||
self.url + "/stats/participation"
|
||||
)
|
||||
if data == {}:
|
||||
return None
|
||||
else:
|
||||
return data # @todo Return something structured
|
||||
|
||||
def get_stats_punch_card(self):
|
||||
"""
|
||||
:calls: `GET /repos/:owner/:repo/stats/punch_card <http://developer.github.com/v3/repos/statistics/#get-the-number-of-commits-per-hour-in-each-day>`_
|
||||
"""
|
||||
headers, data = self._requester.requestJsonAndCheck(
|
||||
"GET",
|
||||
self.url + "/stats/punch_card"
|
||||
)
|
||||
if data == {}:
|
||||
return None
|
||||
else:
|
||||
return data # @todo Return something structured
|
||||
|
||||
def get_subscribers(self):
|
||||
"""
|
||||
:calls: `GET /repos/:owner/:repo/subscribers <http://developer.github.com/v3/activity/watching>`_
|
||||
|
||||
Executable
+119
@@ -0,0 +1,119 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
############################ Copyrights and license ############################
|
||||
# #
|
||||
# Copyright 2012 Vincent Jacques <vincent@vincent-jacques.net> #
|
||||
# Copyright 2012 Zearin <zearin@gonk.net> #
|
||||
# Copyright 2013 AKFish <akfish@gmail.com> #
|
||||
# Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net> #
|
||||
# Copyright 2013 martinqt <m.ki2@laposte.net> #
|
||||
# #
|
||||
# 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 <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import github.GithubObject
|
||||
|
||||
import github.NamedUser
|
||||
|
||||
|
||||
class StatsContributor(github.GithubObject.NonCompletableGithubObject):
|
||||
"""
|
||||
This class represents statistics of a contibutor. The reference can be found here http://developer.github.com/v3/repos/statistics/#get-contributors-list-with-additions-deletions-and-commit-counts
|
||||
"""
|
||||
|
||||
class Week(github.GithubObject.NonCompletableGithubObject):
|
||||
"""
|
||||
This class represents weekly statistics of a contibutor.
|
||||
"""
|
||||
|
||||
@property
|
||||
def w(self):
|
||||
"""
|
||||
:type: int
|
||||
"""
|
||||
return self._w.value
|
||||
|
||||
@property
|
||||
def a(self):
|
||||
"""
|
||||
:type: int
|
||||
"""
|
||||
return self._a.value
|
||||
|
||||
@property
|
||||
def d(self):
|
||||
"""
|
||||
:type: int
|
||||
"""
|
||||
return self._d.value
|
||||
|
||||
@property
|
||||
def c(self):
|
||||
"""
|
||||
:type: int
|
||||
"""
|
||||
return self._c.value
|
||||
|
||||
def _initAttributes(self):
|
||||
self._w = github.GithubObject.NotSet
|
||||
self._a = github.GithubObject.NotSet
|
||||
self._d = github.GithubObject.NotSet
|
||||
self._c = github.GithubObject.NotSet
|
||||
|
||||
def _useAttributes(self, attributes):
|
||||
if "w" in attributes: # pragma no branch
|
||||
self._w = self._makeTimestampAttribute(attributes["w"])
|
||||
if "a" in attributes: # pragma no branch
|
||||
self._a = self._makeIntAttribute(attributes["a"])
|
||||
if "d" in attributes: # pragma no branch
|
||||
self._d = self._makeIntAttribute(attributes["d"])
|
||||
if "c" in attributes: # pragma no branch
|
||||
self._c = self._makeIntAttribute(attributes["c"])
|
||||
|
||||
@property
|
||||
def author(self):
|
||||
"""
|
||||
:type: :class:`github.NamedUser.NamedUser`
|
||||
"""
|
||||
return self._author.value
|
||||
|
||||
@property
|
||||
def total(self):
|
||||
"""
|
||||
:type: string
|
||||
"""
|
||||
return self._total.value
|
||||
|
||||
@property
|
||||
def weeks(self):
|
||||
"""
|
||||
:type: list of :class:`.Week`
|
||||
"""
|
||||
return self._weeks.value
|
||||
|
||||
def _initAttributes(self):
|
||||
self._author = github.GithubObject.NotSet
|
||||
self._total = github.GithubObject.NotSet
|
||||
self._weeks = github.GithubObject.NotSet
|
||||
|
||||
def _useAttributes(self, attributes):
|
||||
if "author" in attributes: # pragma no branch
|
||||
self._author = self._makeClassAttribute(github.NamedUser.NamedUser, attributes["author"])
|
||||
if "total" in attributes: # pragma no branch
|
||||
self._total = self._makeIntAttribute(attributes["total"])
|
||||
if "weeks" in attributes: # pragma no branch
|
||||
self._weeks = self._makeListOfClassesAttribute(self.Week, attributes["weeks"])
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,55 @@
|
||||
https
|
||||
GET
|
||||
api.github.com
|
||||
None
|
||||
/repos/jacquev6/PyGithub/stats/contributors
|
||||
{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
|
||||
null
|
||||
202
|
||||
[('status', '202 Accepted'), ('x-ratelimit-remaining', '4965'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('x-github-request-id', '4C79374B:3446:13B76A5:528030E9'), ('content-length', '2'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('access-control-allow-credentials', 'true'), ('date', 'Mon, 11 Nov 2013 01:20:42 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1384134844')]
|
||||
{}
|
||||
|
||||
https
|
||||
GET
|
||||
api.github.com
|
||||
None
|
||||
/repos/jacquev6/PyGithub/stats/commit_activity
|
||||
{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
|
||||
null
|
||||
202
|
||||
[('status', '202 Accepted'), ('x-ratelimit-remaining', '4964'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('x-github-request-id', '4C79374B:3448:429A229:528030EA'), ('content-length', '2'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('access-control-allow-credentials', 'true'), ('date', 'Mon, 11 Nov 2013 01:20:42 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1384134844')]
|
||||
{}
|
||||
|
||||
https
|
||||
GET
|
||||
api.github.com
|
||||
None
|
||||
/repos/jacquev6/PyGithub/stats/code_frequency
|
||||
{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
|
||||
null
|
||||
202
|
||||
[('status', '202 Accepted'), ('x-ratelimit-remaining', '4963'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('x-github-request-id', '4C79374B:3448:429A284:528030EA'), ('content-length', '2'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('access-control-allow-credentials', 'true'), ('date', 'Mon, 11 Nov 2013 01:20:42 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1384134844')]
|
||||
{}
|
||||
|
||||
https
|
||||
GET
|
||||
api.github.com
|
||||
None
|
||||
/repos/jacquev6/PyGithub/stats/participation
|
||||
{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
|
||||
null
|
||||
200
|
||||
[('status', '202 Accepted'), ('x-ratelimit-remaining', '4962'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('x-github-request-id', '4C79374B:3447:29BC88A:528030EB'), ('access-control-allow-credentials', 'true'), ('vary', 'Accept, Authorization, Cookie, Accept-Encoding'), ('content-length', '260'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('etag', '"a896655765faac08fb15ce0da319416c"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Mon, 11 Nov 2013 01:20:43 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1384134844')]
|
||||
{}
|
||||
|
||||
https
|
||||
GET
|
||||
api.github.com
|
||||
None
|
||||
/repos/jacquev6/PyGithub/stats/punch_card
|
||||
{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
|
||||
null
|
||||
200
|
||||
[('status', '202 Accepted'), ('x-ratelimit-remaining', '4961'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('x-github-request-id', '4C79374B:3448:429A33C:528030EB'), ('access-control-allow-credentials', 'true'), ('vary', 'Accept, Authorization, Cookie, Accept-Encoding'), ('content-length', '1490'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('etag', '"41cbe788b8174e5a98906512e68a825d"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Mon, 11 Nov 2013 01:20:43 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1384134844')]
|
||||
{}
|
||||
|
||||
@@ -448,3 +448,34 @@ class Repository(Framework.TestCase):
|
||||
|
||||
def testUnsubscribePubSubHubbub(self):
|
||||
self.repo.unsubscribe_from_hub("push", "http://requestb.in/1bc1sc61")
|
||||
|
||||
def testStatisticsBeforeCaching(self):
|
||||
self.assertIsNone(self.repo.get_stats_contributors())
|
||||
self.assertIsNone(self.repo.get_stats_commit_activity())
|
||||
self.assertIsNone(self.repo.get_stats_code_frequency())
|
||||
# ReplayData for those last two get_stats is forged because I was not
|
||||
# able to find a repo where participation and punch_card had never been
|
||||
# computed, and pushing to master did not reset the cache for them
|
||||
self.assertIsNone(self.repo.get_stats_participation())
|
||||
self.assertIsNone(self.repo.get_stats_punch_card())
|
||||
|
||||
def testStatisticsAfterCaching(self):
|
||||
stats = self.repo.get_stats_contributors()
|
||||
seenJacquev6 = False
|
||||
for s in stats:
|
||||
adTotal = 0
|
||||
total = 0
|
||||
for w in s.weeks:
|
||||
total += w.c
|
||||
adTotal += w.a + w.d
|
||||
self.assertEqual(total, s.total)
|
||||
if s.author.login == "jacquev6":
|
||||
seenJacquev6 = True
|
||||
self.assertEqual(adTotal, 282147)
|
||||
self.assertEqual(s.weeks[0].w, datetime.datetime(2012, 2, 12))
|
||||
self.assertTrue(seenJacquev6)
|
||||
|
||||
self.repo.get_stats_commit_activity()
|
||||
self.repo.get_stats_code_frequency()
|
||||
self.repo.get_stats_participation()
|
||||
self.repo.get_stats_punch_card()
|
||||
|
||||
Reference in New Issue
Block a user