Skip to content

Commit

Permalink
Merge pull request #13 from soda480/0.1.0
Browse files Browse the repository at this point in the history
Add total method
  • Loading branch information
soda480 authored Apr 27, 2021
2 parents 5b7e110 + fee75b7 commit 0c9fd26
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 2 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ for page in client.get('/user/repos', _get='page'):
print(repo['full_name'])
```

`total` - Get total number of resources at given endpoint
```python
print(client.total('/user/repos'))
6218
```

### Projects using `github3api` ###

* [edgexfoundry/sync-github-labels](https://github.com/edgexfoundry/cd-management/tree/git-label-sync) A script that synchronizes GitHub labels and milestones
Expand All @@ -79,6 +85,10 @@ for page in client.get('/user/repos', _get='page'):

* [edgexfoundry/create-github-release](https://github.com/edgexfoundry/cd-management/tree/create-github-release) A script to facilitate creation of GitHub releases

* [soda480/prepbadge](https://github.com/soda480/prepbadge) A script that creates multiple pull request workflows to update a target organization repos with badges

* [soda480/github-contributions](https://github.com/soda480/github-contributions) A script to get contribution metrics for all members of a GitHub organization using the GitHub GraphQL API


### Development ###

Expand Down
2 changes: 1 addition & 1 deletion build.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
authors = [Author('Emilio Reyes', 'emilio.reyes@intel.com')]
summary = 'An advanced REST client for the GitHub API'
url = 'https://github.com/soda480/github3api'
version = '0.0.9'
version = '0.1.0'
default_task = [
'clean',
'analyze',
Expand Down
45 changes: 44 additions & 1 deletion src/main/python/github3api/githubapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

HOSTNAME = 'api.github.com'
VERSION = 'v3'
DEFAULT_PAGE_SIZE = 30


class GitHubAPI(RESTclient):
Expand Down Expand Up @@ -61,7 +62,7 @@ def _get_next_endpoint(self, url):
if not url:
logger.debug('link header is empty')
return
endpoint = url.replace(f'https://{self.hostname}', '')
endpoint = self.get_endpoint_from_url(url)
logger.debug(f'next endpoint is: {endpoint}')
return endpoint

Expand Down Expand Up @@ -112,6 +113,48 @@ def get(self, endpoint, **kwargs):
else:
return super(GitHubAPI, self).get(endpoint, **kwargs)

def total(self, endpoint):
""" return total number of resources
"""
# logger.debug(f'get total number of resources at endpoint {endpoint}')
response = self.get(endpoint, raw_response=True)
if response.links:
last_url = response.links['last']['url']
endpoint = self.get_endpoint_from_url(last_url)
items = self.get(endpoint)
per_page = GitHubAPI.get_per_page_from_url(last_url)
last_page = GitHubAPI.get_page_from_url(last_url)
total = per_page * (last_page - 1) + len(items)
else:
items = response.json()
total = len(items)
return total

def get_endpoint_from_url(self, url):
""" return endpoint from url
"""
return url.replace(f'https://{self.hostname}', '')

@staticmethod
def get_page_from_url(url):
""" get page query parameter form url
"""
regex = r'^.*page=(?P<value>\d+).*$'
match = re.match(regex, url)
if match:
return int(match.group('value'))

@staticmethod
def get_per_page_from_url(url):
""" get per_page query parameter from url
"""
per_page = DEFAULT_PAGE_SIZE
regex = r'^.*per_page=(?P<value>\d+).*$'
match = re.match(regex, url)
if match:
per_page = int(match.group('value'))
return per_page

@classmethod
def get_client(cls):
""" return instance of GitHubAPI
Expand Down
47 changes: 47 additions & 0 deletions src/unittest/python/test_githubapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from mock import Mock

from github3api import GitHubAPI
from github3api.githubapi import DEFAULT_PAGE_SIZE

from datetime import datetime

Expand Down Expand Up @@ -345,3 +346,49 @@ def test__retry_chunkedencodingerror_error_Should_Return_False_When_NotChunkEnco
def test__retry_chunkedencodingerror_error_Should_Return_True_When_ChunkEncodingError(self, *patches):

self.assertTrue(GitHubAPI._retry_chunkedencodingerror_error(ChunkedEncodingError()))

def test__get_endpoint_from_url_Should_ReturnExpected_When_Called(self, *patches):
client = GitHubAPI(bearer_token='bearer-token')
result = client.get_endpoint_from_url('https://api.github.com/user/repos?page=2')
expected_result = '/user/repos?page=2'
self.assertEqual(result, expected_result)

def test__get_page_from_url_Should_ReturnExpected_When_Match(self, *patches):
result = GitHubAPI.get_page_from_url('https://api.github.com/user/repos?page=213')
expected_result = 213
self.assertEqual(result, expected_result)

def test__get_page_from_url_Should_ReturnExpected_When_NoMatch(self, *patches):
result = GitHubAPI.get_page_from_url('https://api.github.com/user/repos')
self.assertIsNone(result)

def test__get_per_page_from_url_Should_Return_Expected_When_Match(self, *patches):
result = GitHubAPI.get_per_page_from_url('https://api.github.com/user/repos?page=213&per_page=75')
expected_result = 75
self.assertEqual(result, expected_result)

def test__get_per_page_from_url_Should_Return_Expected_When_NoMatch(self, *patches):
result = GitHubAPI.get_per_page_from_url('https://api.github.com/user/repos?page=213')
expected_result = DEFAULT_PAGE_SIZE
self.assertEqual(result, expected_result)

@patch('github3api.GitHubAPI.get')
def test__get_total_Should_ReturnExpected_When_NoLinks(self, get_patch, *patches):
response_mock = Mock()
response_mock.links = {}
response_mock.json.return_value = ['', '', '']
get_patch.return_value = response_mock
client = GitHubAPI(bearer_token='bearer-token')
result = client.total('/user/repos')
expected_result = len(response_mock.json.return_value)
self.assertEqual(result, expected_result)

@patch('github3api.GitHubAPI.get')
def test__get_total_Should_ReturnExpected_When_Links(self, get_patch, *patches):
response1_mock = Mock()
response1_mock.links = {'next': {'url': 'https://api.github.com/user/repos?page=2', 'rel': 'next'}, 'last': {'url': 'https://api.github.com/user/repos?page=208', 'rel': 'last'}}
get_patch.side_effect = [response1_mock, ['', '', '']]
client = GitHubAPI(bearer_token='bearer-token')
result = client.total('/user/repos')
expected_result = DEFAULT_PAGE_SIZE * 207 + 3
self.assertEqual(result, expected_result)

0 comments on commit 0c9fd26

Please sign in to comment.