From cebb7d5e25bdf0b7fa57f29fbb1337f782a233b4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 15 Jan 2014 21:22:56 -0600 Subject: [PATCH 001/972] Fix module doc-string --- github3/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github3/api.py b/github3/api.py index b54b6cfaf..75597293f 100644 --- a/github3/api.py +++ b/github3/api.py @@ -3,7 +3,7 @@ github3.api =========== -:copyright: (c) 2012 by SigmaVirus24 +:copyright: (c) 2012-2014 by Ian Cordasco :license: Modified BSD, see LICENSE for more details """ From edbcced249ace7e52e307d951eacd3fa3d283fe9 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 15 Jan 2014 21:23:29 -0600 Subject: [PATCH 002/972] Split out enterprise support in github3.login Add github3.enterprise_login --- github3/api.py | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/github3/api.py b/github3/api.py index 75597293f..175bb786f 100644 --- a/github3/api.py +++ b/github3/api.py @@ -38,16 +38,19 @@ def authorize(login, password, scopes, note='', note_url='', client_id='', client_secret) -def login(username=None, password=None, token=None, url=None, - two_factor_callback=None): +def login(username=None, password=None, token=None, two_factor_callback=None): """Construct and return an authenticated GitHub session. - This will return a GitHubEnterprise session if a url is provided. + .. note:: + + To allow you to specify either a username and password combination or + a token, none of the parameters are required. If you provide none of + them, you will receive a + :class:`NullObject ` :param str username: login name :param str password: password for the login :param str token: OAuth token - :param str url: (optional), URL of a GitHub Enterprise instance :param func two_factor_callback: (optional), function you implement to provide the Two Factor Authentication code to GitHub when necessary :returns: :class:`GitHub ` @@ -56,7 +59,40 @@ def login(username=None, password=None, token=None, url=None, g = None if (username and password) or token: - g = GitHubEnterprise(url) if url is not None else GitHub() + g = GitHub() + g.login(username, password, token, two_factor_callback) + + return g + + +def enterprise_login(username=None, password=None, token=None, url=None, + two_factor_callback=None): + """Construct and return an authenticated GitHubEnterprise session. + + .. note:: + + To allow you to specify either a username and password combination or + a token, none of the parameters are required. If you provide none of + them, you will receive a + :class:`NullObject ` + + :param str username: login name + :param str password: password for the login + :param str token: OAuth token + :param str url: URL of a GitHub Enterprise instance + :param func two_factor_callback: (optional), function you implement to + provide the Two Factor Authentication code to GitHub when necessary + :returns: :class:`GitHubEnterprise ` + + """ + if not url: + raise ValueError('GitHub Enterprise requires you provide the URL of' + ' the instance') + + g = None + + if (username and password) or token: + g = GitHubEnterprise(url) g.login(username, password, token, two_factor_callback) return g From 422cf7b708de80e454ed873c0d1ab1d9d64b3da7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 15 Jan 2014 21:23:56 -0600 Subject: [PATCH 003/972] Rename all the iter_(*) methods to \1 - Above regular expression example: iter_all_users -> all_users --- github3/api.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/github3/api.py b/github3/api.py index 175bb786f..823ecc623 100644 --- a/github3/api.py +++ b/github3/api.py @@ -131,7 +131,7 @@ def gitignore_templates(): return gh.gitignore_templates() -def iter_all_repos(number=-1, etag=None): +def all_repos(number=-1, etag=None): """Iterate over every repository in the order they were created. :param int number: (optional), number of repositories to return. @@ -144,7 +144,7 @@ def iter_all_repos(number=-1, etag=None): return gh.iter_all_repos(number, etag) -def iter_all_users(number=-1, etag=None): +def all_users(number=-1, etag=None): """Iterate over every user in the order they signed up for GitHub. :param int number: (optional), number of users to return. Default: -1, @@ -157,7 +157,7 @@ def iter_all_users(number=-1, etag=None): return gh.iter_all_users(number, etag) -def iter_events(number=-1, etag=None): +def events(number=-1, etag=None): """Iterate over public events. :param int number: (optional), number of events to return. Default: -1 @@ -170,7 +170,7 @@ def iter_events(number=-1, etag=None): return gh.iter_events(number, etag) -def iter_followers(username, number=-1, etag=None): +def followers(username, number=-1, etag=None): """List the followers of ``username``. :param str username: (required), login of the person to list the followers @@ -185,7 +185,7 @@ def iter_followers(username, number=-1, etag=None): return gh.iter_followers(username, number, etag) if username else [] -def iter_following(username, number=-1, etag=None): +def following(username, number=-1, etag=None): """List the people ``username`` follows. :param str username: (required), login of the user @@ -199,7 +199,7 @@ def iter_following(username, number=-1, etag=None): return gh.iter_following(username, number, etag) if username else [] -def iter_gists(username=None, number=-1, etag=None): +def gists(username=None, number=-1, etag=None): """Iterate over public gists or gists for the provided username. :param str username: (optional), if provided, get the gists for this user @@ -214,16 +214,10 @@ def iter_gists(username=None, number=-1, etag=None): return gh.iter_gists(username, number, etag) -def iter_repo_issues(owner, repository, milestone=None, state=None, - assignee=None, mentioned=None, labels=None, sort=None, - direction=None, since=None, number=-1, etag=None): - """List issues on owner/repository. Only owner and repository are - required. - - .. versionchanged:: 0.9.0 - - - The ``state`` parameter now accepts 'all' in addition to 'open' - and 'closed'. +def repo_issues(owner, repository, milestone=None, state=None, assignee=None, + mentioned=None, labels=None, sort=None, direction=None, + since=None, number=-1, etag=None): + """Iterate over issues on owner/repository. :param str owner: login of the owner of the repository :param str repository: name of the repository @@ -256,7 +250,7 @@ def iter_repo_issues(owner, repository, milestone=None, state=None, return iter([]) -def iter_orgs(username, number=-1, etag=None): +def orgs(username, number=-1, etag=None): """List the organizations associated with ``username``. :param str username: (required), login of the user @@ -271,8 +265,8 @@ def iter_orgs(username, number=-1, etag=None): return gh.iter_orgs(username, number, etag) if username else [] -def iter_user_repos(login, type=None, sort=None, direction=None, number=-1, - etag=None): +def user_repos(login, type=None, sort=None, direction=None, number=-1, + etag=None): """List public repositories for the specified ``login``. .. versionadded:: 0.6 @@ -302,7 +296,7 @@ def iter_user_repos(login, type=None, sort=None, direction=None, number=-1, return iter([]) -def iter_starred(username, number=-1, etag=None): +def starred(username, number=-1, etag=None): """Iterate over repositories starred by ``username``. :param str username: (optional), name of user whose stars you want to see @@ -316,7 +310,7 @@ def iter_starred(username, number=-1, etag=None): return gh.iter_starred(username, number, etag) -def iter_subscriptions(username, number=-1, etag=None): +def subscriptions(username, number=-1, etag=None): """Iterate over repositories subscribed to by ``username``. :param str username: (optional), name of user whose subscriptions you want From 0c155ded50a7f2cc674457f62b39ad96e4669e01 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 18 Jan 2014 15:22:23 -0600 Subject: [PATCH 004/972] Remove bad API for (subscribing to|ignoring) repo notifications --- github3/repos/repo.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 50630cb76..607dcbbb4 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -996,6 +996,20 @@ def hook(self, id_num): json = self._json(self._get(url), 200) return Hook(json, self) if json else None + @requires_auth + def ignore(self): + """Ignore notifications from this repository for the user. + + .. versionadded:: 1.0 + + This replaces ``Repository#set_subscription``. + + :returns: :class:`Subscription ` + """ + url = self._build_url('subscription', base_url=self._api) + json = self._json(self._put(url, data=dumps({'ignored': True})), 200) + return Subscription(json, self) if json else None + def is_assignee(self, login): """Check if the user is a possible assignee for an issue on this repository. @@ -1735,18 +1749,18 @@ def remove_collaborator(self, login): return resp @requires_auth - def set_subscription(self, subscribed, ignored): - """Set the user's subscription for this repository + def subscribe(self): + """Subscribe the user to this repository's notifications. + + .. versionadded:: 1.0 + + This replaces ``Repository#set_subscription`` - :param bool subscribed: (required), determines if notifications should - be received from this repository. - :param bool ignored: (required), determines if notifications should be - ignored from this repository. :returns: :class:`Subscription ` """ - sub = {'subscribed': subscribed, 'ignored': ignored} url = self._build_url('subscription', base_url=self._api) - json = self._json(self._put(url, data=dumps(sub)), 200) + json = self._json(self._put(url, data=dumps({'subcribed': True})), + 200) return Subscription(json, self) if json else None @requires_auth From a4444203618657d37a4645062f10c679a5face74 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 18 Jan 2014 15:23:49 -0600 Subject: [PATCH 005/972] Remove legacy/deprecated watching API --- github3/github.py | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/github3/github.py b/github3/github.py index c87afcfa3..5cf60422a 100644 --- a/github3/github.py +++ b/github3/github.py @@ -380,20 +380,6 @@ def is_starred(self, login, repo): json = self._boolean(self._get(url), 204, 404) return json - @requires_auth - def is_subscribed(self, login, repo): - """Check if the authenticated user is subscribed to login/repo. - - :param str login: (required), owner of repository - :param str repo: (required), name of repository - :returns: bool - """ - json = False - if login and repo: - url = self._build_url('user', 'subscriptions', login, repo) - json = self._boolean(self._get(url), 204, 404) - return json - def issue(self, owner, repository, number): """Fetch issue #:number: from https://github.com/:owner:/:repository: @@ -1374,20 +1360,6 @@ def star(self, login, repo): resp = self._boolean(self._put(url), 204, 404) return resp - @requires_auth - def subscribe(self, login, repo): - """Subscribe to login/repo - - :param str login: (required), owner of the repo - :param str repo: (required), name of the repo - :return: bool - """ - resp = False - if login and repo: - url = self._build_url('user', 'subscriptions', login, repo) - resp = self._boolean(self._put(url), 204, 404) - return resp - @requires_auth def unfollow(self, login): """Make the authenticated user stop following login @@ -1415,20 +1387,6 @@ def unstar(self, login, repo): resp = self._boolean(self._delete(url), 204, 404) return resp - @requires_auth - def unsubscribe(self, login, repo): - """Unsubscribe to login/repo - - :param str login: (required), owner of the repo - :param str repo: (required), name of the repo - :return: bool - """ - resp = False - if login and repo: - url = self._build_url('user', 'subscriptions', login, repo) - resp = self._boolean(self._delete(url), 204, 404) - return resp - @requires_auth def update_user(self, name=None, email=None, blog=None, company=None, location=None, hireable=False, bio=None): From 3951767346e771c4f65d50a94334e68c8c36c01c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 18 Jan 2014 15:38:03 -0600 Subject: [PATCH 006/972] Update HISTORY.rst with changes --- HISTORY.rst | 112 +++++++++++++++++----------------------------------- 1 file changed, 37 insertions(+), 75 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 83387d0dd..7f2718e97 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,96 +1,58 @@ History/Changelog ----------------- -0.9.3: 2014-11-04 +1.0.0: 2014-xx-xx ~~~~~~~~~~~~~~~~~ -- Backport of ``PullRequest#create_review_comment`` by Adrian Moisey +1.0.0 is a huge release. It includes a great deal of changes to +``github3.py``. It is suggested you read the following release notes *very* +carefully. -- Backport of ``PullRequest#review_comments`` by Adrian Moisey +Breaking Changes +```````````````` -- Backport of a fix that allows authenticated users to download Release - Assets. Original bug reported by Eugene Fidelin in issue #288. +- All methods and functions starting with ``iter_`` have been renamed. -- Documentation typo fix by Marc Abramowitz + ============================== ========================= + Old name New name + ============================== ========================= + ``github3.iter_all_repos`` ``github3.all_repos`` + ``github3.iter_all_users`` ``github3.all_users`` + ``github3.iter_events`` ``github3.events`` + ``github3.iter_followers`` ``github3.followers`` + ``github3.iter_following`` ``github3.following`` + ``github3.iter_gists`` ``github3.gists`` + ``github3.iter_repo_issues`` ``github3.repo_issues`` + ``github3.iter_orgs`` ``github3.orgs`` + ``github3.iter_user_repos`` ``github3.user_repos`` + ``github3.iter_starred`` ``github3.starred`` + ``github3.iter_subscriptions`` ``github3.subscriptions`` + ``github3.iter_subscriptions`` ``github3.subscriptions`` + ============================== ========================= -0.9.2: 2014-10-05 -~~~~~~~~~~~~~~~~~ - -- Updates for `new team management`_ API changes - - - Add ``Team#invite``, ``Team#membership_for``, and - ``Team#revoke_membership`` - - - Deprecate ``Team#add_member``, ``Team#remove_member``, and - ``Organization#add_member``. - - - Update payload handler for ``TeamAddEvent``. - -.. _new team management: - https://developer.github.com/changes/2014-09-23-one-more-week-before-the-add-team-member-api-breaking-change/ - -0.9.1: 2014-08-10 -~~~~~~~~~~~~~~~~~ - -- Correct Repository attribute ``fork_count`` should be ``forks_count`` - -0.9.0: 2014-05-04 -~~~~~~~~~~~~~~~~~ - -- Add Deployments API - -- Add Pages API +- ``github3.login`` has been simplified and split into two functions: -- Add support so applications can revoke a `single authorization`_ or `all - authorizations`_ created by the application + - ``github3.login`` serves the majority use case and only provides an + authenticated ``GitHub`` object. -- Add the ability for users to ping_ hooks + - ``github3.enterprise_login`` allows GitHub Enterprise users to log into + their service. -- Allow users to list a `Repository's collaborators`_ +- Remove legacy watching API: -- Allow users to create an empty blob on a Repository + - ``GitHub#subscribe`` -- Update how users can list issues and pull requests. See: - http://developer.github.com/changes/2014-02-28-issue-and-pull-query-enhancements/ - This includes breaking changes to ``Repository#iter_pulls``. + - ``GitHub#unsubscribe`` -- Update methods to handle the `pagination changes`_. + - ``GitHub#is_subscribed`` -- Fix typo `stargarzers_url`_ - -- Add ``assets`` attribute to ``Release`` object. - -- Fix wrong argument to ``Organization#create_team`` (``permissions`` versus - ``permission``) - -- Fix Issue Search Result's representation and initialization - -- Fix Repository Search Result's initialization - -- Allow users to pass a two-factor authentication callback to - ``GitHub#authorize``. - -.. _single authorization: https://github3py.readthedocs.org/en/latest/github.html#github3.github.GitHub.revoke_authorization -.. _all authorizations: https://github3py.readthedocs.org/en/latest/github.html#github3.github.GitHub.revoke_authorizations -.. _ping: https://github3py.readthedocs.org/en/latest/repos.html?highlight=ping#github3.repos.hook.Hook.ping -.. _Repository's collaborators: https://github3py.readthedocs.org/en/latest/repos.html#github3.repos.repo.Repository.iter_collaborators -.. _pagination changes: https://developer.github.com/changes/2014-03-18-paginating-method-changes/ -.. _stargarzers_url: https://github.com/sigmavirus24/github3.py/pull/240 - -0.8.2: 2014-02-11 -~~~~~~~~~~~~~~~~~ - -- Fix bug in ``GitHub#search_users`` (and ``github3.search_users``). Thanks - @abesto - -- Expose the stargazers count for repositories. Thanks @seveas - -0.8.1: 2014-01-26 -~~~~~~~~~~~~~~~~~ +- ``Repository#set_subscription`` was split into two simpler functions -- Add documentation for using Two Factor Authentication + - ``Repository#subscribe`` subscribes the authenticated user to the + repository's notifications -- Fix oversight where ``github3.login`` could not be used for 2FA + - ``Repository#ignore`` ignores notifications from the repository for the + authenticated user 0.8.0: 2014-01-03 ~~~~~~~~~~~~~~~~~ From edea8b9b8a8db487dff09f579ad129e5ee438209 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 18 Jan 2014 15:45:16 -0600 Subject: [PATCH 007/972] Dedent the table It probably should not have been indented in the first place --- HISTORY.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 7f2718e97..cee54402d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,22 +13,22 @@ Breaking Changes - All methods and functions starting with ``iter_`` have been renamed. - ============================== ========================= - Old name New name - ============================== ========================= - ``github3.iter_all_repos`` ``github3.all_repos`` - ``github3.iter_all_users`` ``github3.all_users`` - ``github3.iter_events`` ``github3.events`` - ``github3.iter_followers`` ``github3.followers`` - ``github3.iter_following`` ``github3.following`` - ``github3.iter_gists`` ``github3.gists`` - ``github3.iter_repo_issues`` ``github3.repo_issues`` - ``github3.iter_orgs`` ``github3.orgs`` - ``github3.iter_user_repos`` ``github3.user_repos`` - ``github3.iter_starred`` ``github3.starred`` - ``github3.iter_subscriptions`` ``github3.subscriptions`` - ``github3.iter_subscriptions`` ``github3.subscriptions`` - ============================== ========================= +============================== ========================= +Old name New name +============================== ========================= +``github3.iter_all_repos`` ``github3.all_repos`` +``github3.iter_all_users`` ``github3.all_users`` +``github3.iter_events`` ``github3.events`` +``github3.iter_followers`` ``github3.followers`` +``github3.iter_following`` ``github3.following`` +``github3.iter_gists`` ``github3.gists`` +``github3.iter_repo_issues`` ``github3.repo_issues`` +``github3.iter_orgs`` ``github3.orgs`` +``github3.iter_user_repos`` ``github3.user_repos`` +``github3.iter_starred`` ``github3.starred`` +``github3.iter_subscriptions`` ``github3.subscriptions`` +``github3.iter_subscriptions`` ``github3.subscriptions`` +============================== ========================= - ``github3.login`` has been simplified and split into two functions: From 6835ea9d582e4b0d8f0586e1f38af6a5f61e3026 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 20 Jan 2014 20:56:36 -0600 Subject: [PATCH 008/972] Rename github3.orgs to github3.organizations --- HISTORY.rst | 2 +- github3/api.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index cee54402d..a6825c147 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -23,7 +23,7 @@ Old name New name ``github3.iter_following`` ``github3.following`` ``github3.iter_gists`` ``github3.gists`` ``github3.iter_repo_issues`` ``github3.repo_issues`` -``github3.iter_orgs`` ``github3.orgs`` +``github3.iter_orgs`` ``github3.organizations`` ``github3.iter_user_repos`` ``github3.user_repos`` ``github3.iter_starred`` ``github3.starred`` ``github3.iter_subscriptions`` ``github3.subscriptions`` diff --git a/github3/api.py b/github3/api.py index 823ecc623..0f303d0c3 100644 --- a/github3/api.py +++ b/github3/api.py @@ -250,7 +250,7 @@ def repo_issues(owner, repository, milestone=None, state=None, assignee=None, return iter([]) -def orgs(username, number=-1, etag=None): +def organizations(username, number=-1, etag=None): """List the organizations associated with ``username``. :param str username: (required), login of the user From a69eebbf40b4de3567d321f6fc31b1b9d14d9ca5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 20 Jan 2014 21:06:42 -0600 Subject: [PATCH 009/972] Rework the public functional API --- HISTORY.rst | 11 +++++++++-- github3/api.py | 29 ++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index a6825c147..d0213627f 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -18,10 +18,9 @@ Old name New name ============================== ========================= ``github3.iter_all_repos`` ``github3.all_repos`` ``github3.iter_all_users`` ``github3.all_users`` -``github3.iter_events`` ``github3.events`` +``github3.iter_events`` ``github3.all_events`` ``github3.iter_followers`` ``github3.followers`` ``github3.iter_following`` ``github3.following`` -``github3.iter_gists`` ``github3.gists`` ``github3.iter_repo_issues`` ``github3.repo_issues`` ``github3.iter_orgs`` ``github3.organizations`` ``github3.iter_user_repos`` ``github3.user_repos`` @@ -38,6 +37,14 @@ Old name New name - ``github3.enterprise_login`` allows GitHub Enterprise users to log into their service. +- ``github3.iter_gists`` was split into two functions: + + - ``github3.all_gists`` which iterates over all of the public gists on + GitHub + + - ``github3.gists_for`` which iterates over all the public gists of a + specific user + - Remove legacy watching API: - ``GitHub#subscribe`` diff --git a/github3/api.py b/github3/api.py index 0f303d0c3..41c3c92c1 100644 --- a/github3/api.py +++ b/github3/api.py @@ -157,7 +157,7 @@ def all_users(number=-1, etag=None): return gh.iter_all_users(number, etag) -def events(number=-1, etag=None): +def all_events(number=-1, etag=None): """Iterate over public events. :param int number: (optional), number of events to return. Default: -1 @@ -199,10 +199,27 @@ def following(username, number=-1, etag=None): return gh.iter_following(username, number, etag) if username else [] -def gists(username=None, number=-1, etag=None): - """Iterate over public gists or gists for the provided username. +def all_gists(number=-1, etag=None): + """Iterate over public gists. - :param str username: (optional), if provided, get the gists for this user + .. versionadded:: 1.0 + + This was split from ``github3.iter_gists`` before 1.0. + + :param int number: (optional), number of gists to return. Default: -1, + return all of them + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Gist ` + + """ + return gh.iter_gists(None, number, etag) + + +def gists_for(username, number=-1, etag=None): + """Iterate over gists for the provided username. + + :param str username: (required), if provided, get the gists for this user instead of the authenticated user. :param int number: (optional), number of gists to return. Default: -1, return all of them @@ -211,7 +228,9 @@ def gists(username=None, number=-1, etag=None): :returns: generator of :class:`Gist ` """ - return gh.iter_gists(username, number, etag) + if username: + return gh.iter_gists(username, number, etag) + return iter([]) def repo_issues(owner, repository, milestone=None, state=None, assignee=None, From 5d2ca77ad848331cba0517aa9020504fff3d6f67 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 20 Jan 2014 21:29:23 -0600 Subject: [PATCH 010/972] Add NullObject --- github3/structs.py | 49 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/github3/structs.py b/github3/structs.py index 31c46ad8c..579be5afd 100644 --- a/github3/structs.py +++ b/github3/structs.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from collections import Iterator -from .models import GitHubCore -from requests.compat import urlparse, urlencode +from github3.models import GitHubCore +from requests.compat import is_py3, urlparse, urlencode class GitHubIterator(GitHubCore, Iterator): @@ -141,3 +141,48 @@ def _get_json(self, response): self.items = json.get('items', []) # If we return None then it will short-circuit the while loop. return json.get('items') + + +class NullObject(object): + def __init__(self, initializer=None): + self.__dict__['initializer'] = initializer + + def __str__(self): + return '' + + def __unicode__(self): + return '' if is_py3 else ''.decode() + + def __repr__(self): + return ''.format( + repr(self.__getattribute__('initializer')) + ) + + def __getitem__(self, index): + return self + + def __setitem__(self, index, value): + pass + + def __getattr__(self, attr): + return self + + def __setattr__(self, attr, value): + pass + + def __call__(self, *args, **kwargs): + return self + + def __contains__(self, other): + return False + + def __iter__(self): + yield self + + def __next__(self): + raise StopIteration + + next = __next__ + + def is_null(self): + return True From dabad2f192eb098a406f69909ec71e67a2c34e39 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 22 Jan 2014 21:15:30 -0600 Subject: [PATCH 011/972] Add tests around new methods - Add cassettes for new methods --- tests/cassettes/Repository_ignore.json | 1 + tests/cassettes/Repository_subscription.json | 1 + tests/integration/test_repos_repo.py | 33 +++++++++++--------- 3 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 tests/cassettes/Repository_ignore.json create mode 100644 tests/cassettes/Repository_subscription.json diff --git a/tests/cassettes/Repository_ignore.json b/tests/cassettes/Repository_ignore.json new file mode 100644 index 000000000..9ff2bc3db --- /dev/null +++ b/tests/cassettes/Repository_ignore.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": "", "headers": {"Accept-Encoding": "gzip, deflate, compress", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/jnewland/gmond_python_modules"}, "response": {"body": {"base64_string": "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", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "4999", "x-github-media-type": "github.v3; param=full; 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-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D9:6648:5F7302:52E08944", "content-encoding": "gzip", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "server": "GitHub.com", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Fri, 17 Jan 2014 08:49:05 GMT", "x-ratelimit-limit": "5000", "etag": "\"c71b2e4d0895731ab1a0a5d67aff9eec\"", "access-control-allow-credentials": "true", "date": "Thu, 23 Jan 2014 03:15:17 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1390450517"}, "url": "https://api.github.com/repos/jnewland/gmond_python_modules", "status_code": 200}, "recorded_at": "2014-01-23T03:14:04"}, {"request": {"body": "{\"ignored\": true}", "headers": {"Content-Length": "17", "Accept-Encoding": "gzip, deflate, compress", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/repos/jnewland/gmond_python_modules/subscription"}, "response": {"body": {"base64_string": "H4sIAAAAAAAAA6WOQQqDMBBF7zJrNUZbCjlHV92EaFJNiTMhmSBSevdG6A26fHz+/+8NuUx5Tn5yFtTThOwa8AtSOplTqZicyYSgsITQwFyRndWGQcHQy0vby3YY7/2o5FXJ2wMaKCnUcGWOWQlhou8Wz2uZupk2kVykLF7o9mDQimUjtDoevBLqjWwJLoufVGRfj0+DWvFM6dD/TsPnC5V04K3zAAAA", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "4998", "x-github-media-type": "github.v3; param=full; 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-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D9:6648:5F7329:52E08945", "content-encoding": "gzip", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "server": "GitHub.com", "cache-control": "private, max-age=60, s-maxage=60", "x-ratelimit-limit": "5000", "etag": "\"45310e47156abe9eebf8787541e89ac5\"", "access-control-allow-credentials": "true", "date": "Thu, 23 Jan 2014 03:15:17 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1390450517"}, "url": "https://api.github.com/repos/jnewland/gmond_python_modules/subscription", "status_code": 200}, "recorded_at": "2014-01-23T03:14:04"}], "recorded_with": "betamax"} \ No newline at end of file diff --git a/tests/cassettes/Repository_subscription.json b/tests/cassettes/Repository_subscription.json new file mode 100644 index 000000000..f4c0e146d --- /dev/null +++ b/tests/cassettes/Repository_subscription.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": "", "headers": {"Accept-Encoding": "gzip, deflate, compress", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/vcr/vcr"}, "response": {"body": {"base64_string": "H4sIAAAAAAAAA+1YPXPjNhD9Kxw2KU4WKUq2IjWXMl0yGVdpNCAJihiTBAcf8sgc//c8APzUzZ2E1G5sidr3+LDYxe6iC1keHp+3z8nLyypsSE3DY3jJRLgKC11Vp+lJ5J7y94aK8NiFFT+zZjQ2LMkhTg77/SokF6KIOGlR4fdSqVYeo4jltFEs441cn5kqdbrOeB29HA6Ebuhhs0mft/F2n8UJ3e2T/b6I412SJuu2OUPLWfSc5j0NhK3CJTtp2ZxWSypkr7hUdXWjZSagXyuvKv4OzI3hz2ijYgAYR9nPrDn7gQHoIq5KCk9B7qdZJpPqYQnWuIvMvxPLDVzC64Lmj8rozSHC7OlnFwnacsujU5kJ1iqG3XqYbQ4CCRdn0rAP4kUCkATWCHn4xdYYIHpBgD2MctZd1Ap2IdnVLFvQjLIL/OfHdAMDkbq2Jo3+mnnAeJUpeiJ5bbKmIJWkn6vQvl3B2D5YIVnuxGof0zkdNwgv+odmXOTBlWsRKCpVIDXe9ZsM/nx9/TtgjaKCZHYfAtLkARxWkWuAyKuDXAvEYVBopQV1YKFhV3ARFESqVZBTwCEaYcayVUCyTAtItrZyjXXB9G1cwC+z0u6UWUG/CoO8s2ELCLIOALzyjV69cMa+i/C3T5QMGUtSjnXweym/FLAAdtH8q4kgRUntJcwCACw59/OEBQDIpNT0oYBdLsTiZDRkQaPr1B1Bj8T+ksohoIVIyc4NpV4eGEFdNJyCqSBNVvrRDJgucp/sbpCzlxRjD1ha8dQLh2oSWVAXyZK4c1ydfN9uWAxmQSJo4S3FYEYSJTz3w8owoJECZUJha7x0DJio6z1SkeasydmPZQRhV0yxOpOPuyV6GZsTChToPZRgqfZP+glnlLhCh3zxc8kEm0hsif11hb1Z0KzK2iXVNbtX9G6PMAtZhNn/oDFx0sNGKvP9fg3+UY7BdNF0BrlDrWfz8U5/qg06om7iNJvvr81hou5bS1RpMhvULRHUR1QPibqUoOav1+uupMT2azUVnhnhEIASkZXoVXx0dAMGVbQmyvZ7hZGRo/+rOMm9wnkEgcC53UeLQ8z3vEVT7yXAAuYMNavQkvDG74yZUHOuhitWsOyR5nUZzgtg912yJqMrgnkFUYP+iSGO0G8Zr6MBoX4rdgjIxJTm+tWKIqS8vCaow3SYx2w8C4pmLj8RhT4yiTfxU5w8Jc+v8f64eTnG8b+w0W2+sNk9xZunJHmFwWZ7fN4Zm1bLckZzY7I1Jjgx+hDBJwyEyyHMtIRmgoOhlOVk+Mdkduw7x94sq7DXN0H3c87L7TH7oyleXfKatihT/dwKlXAYQw1rWzuuTr2rZB+w2se73xe1KeO6gSs3L/FuFb4ThT4GZWLxdKhqpnHX6dW8lciTy4jwqIQ2cwCeTBk2e/jO3thg5NrnnjuJtzhQmBC8H7zdlMxb2vTco4rE9ewSE7sBzUwgHD8Osodl5LQgulIn11lBdo3BAJcA2HUzGaDrw2RhrgTmw40LiXEuMNnqdGPqmY+GX1cJX1cJ7ipovLOJFvcPCLOvq4QHrhIaqt4xHg9ZblN73qr258T28Pkf7TVhk/QTAAA=", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "4997", "x-github-media-type": "github.v3; param=full; 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-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D9:6645:3DC7D2:52E08945", "content-encoding": "gzip", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "server": "GitHub.com", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Wed, 22 Jan 2014 16:13:54 GMT", "x-ratelimit-limit": "5000", "etag": "\"12e45225ab723495b03cb5ad5a00a88d\"", "access-control-allow-credentials": "true", "date": "Thu, 23 Jan 2014 03:15:17 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1390450517"}, "url": "https://api.github.com/repos/vcr/vcr", "status_code": 200}, "recorded_at": "2014-01-23T03:14:05"}, {"request": {"body": "{\"subcribed\": true}", "headers": {"Content-Length": "19", "Accept-Encoding": "gzip, deflate, compress", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/repos/vcr/vcr/subscription"}, "response": {"body": {"base64_string": "H4sIAAAAAAAAA42NQQrDIBBF7zJrEzVpKXiOrroJamwi2CgzY6CU3r2m9ABd/MXjwX8voOrIY3RhBsNYg4C4bBkPvNtEjTFYyhuYraYkwDfkME+WwcCg9KlTuhvGqxqNPht9uYGAiqnJlbmQkdKW2C+R1+p6nx8SQ8kkd4/f/fKFY0scrSYjZ3xO/5/A+wO8XQcdxwAAAA==", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "4996", "x-github-media-type": "github.v3; param=full; 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-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D9:6645:3DC7F2:52E08945", "content-encoding": "gzip", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "server": "GitHub.com", "cache-control": "private, max-age=60, s-maxage=60", "x-ratelimit-limit": "5000", "etag": "\"e91b34818ae0d9ddd7757e21599b340d\"", "access-control-allow-credentials": "true", "date": "Thu, 23 Jan 2014 03:15:17 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1390450517"}, "url": "https://api.github.com/repos/vcr/vcr/subscription", "status_code": 200}, "recorded_at": "2014-01-23T03:14:05"}], "recorded_with": "betamax"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 1da94cba3..963bd0a37 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -41,23 +41,16 @@ def test_create_release(self): assert isinstance(release, github3.repos.release.Release) - def test_iter_deployments(self): - """Test that a repository's deployments may be retrieved.""" - cassette_name = self.cassette_name('iter_deployments') - with self.recorder.use_cassette(cassette_name): - repository = self.gh.repository('sigmavirus24', 'github3.py') - assert repository is not None - for d in repository.iter_deployments(): - assert isinstance(d, github3.repos.deployment.Deployment) - - def test_iter_issues_accepts_state_all(self): - """Test that the state parameter accets 'all'.""" - cassette_name = self.cassette_name('issues_state_all') + def test_ignore(self): + """Test that a user can ignore the notifications on a repository.""" + self.basic_login() + cassette_name = self.cassette_name('ignore') with self.recorder.use_cassette(cassette_name): - repository = self.gh.repository('sigmavirus24', 'betamax') + repository = self.gh.repository('jnewland', + 'gmond_python_modules') assert repository is not None - for issue in repository.iter_issues(state='all'): - assert issue.state in ('open', 'closed') + subscription = repository.ignore() + assert subscription.ignore is True def test_iter_languages(self): """Test that a repository's languages can be retrieved.""" @@ -112,3 +105,13 @@ def test_release(self): release = repository.release(76677) assert isinstance(release, github3.repos.release.Release) + + def test_subscription(self): + """Test the ability to subscribe to a repository's notifications.""" + self.basic_login() + cassette_name = self.cassette_name('subscription') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('vcr', 'vcr') + assert repository is not None + subscription = repository.subscribe() + assert subscription.subscribed is True From 88d723ad735254d323502677d829da97e062924e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 22 Jan 2014 22:33:51 -0600 Subject: [PATCH 012/972] Start rewriting unit tests properly --- tests/unit/test_api.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/unit/test_api.py diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py new file mode 100644 index 000000000..8a10b0b77 --- /dev/null +++ b/tests/unit/test_api.py @@ -0,0 +1,34 @@ +import github3 +import mock +import unittest + + +class TestAPI(unittest.TestCase): + def setUp(self): + self.mocked_github = mock.patch('github3.api.gh', + autospec=github3.GitHub) + self.gh = self.mocked_github.start() + + def tearDown(self): + self.mocked_github.stop() + + def test_authorize(self): + args = ('login', 'password', ['scope'], 'note', 'url.com', '', '') + github3.authorize(*args) + self.gh.authorize.assert_called_once_with(*args) + + def test_enterprise_login(self): + args = ('login', 'password', None, 'https://url.com/', None) + with mock.patch.object(github3.GitHubEnterprise, 'login') as login: + g = github3.login(*args) + assert isinstance(g, github3.GitHubEnterprise) + assert not isinstance(g, github3.GitHub) + login.assert_called_once_with(*args) + + def test_login(self): + args = ('login', 'password', None, None) + with mock.patch.object(github3.GitHub, 'login') as login: + g = github3.login(*args) + assert isinstance(g, github3.GitHub) + assert not isinstance(g, github3.GitHubEnterprise) + login.assert_called_once_with(*args) From d238db55b7ad0bf01052e1d9bca345d5f6315f24 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 25 Jan 2014 22:05:39 -0600 Subject: [PATCH 013/972] Fix failing unit test We were incorrectly testing github3.enterprise_login --- tests/unit/test_api.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 8a10b0b77..7d56769ca 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -20,10 +20,9 @@ def test_authorize(self): def test_enterprise_login(self): args = ('login', 'password', None, 'https://url.com/', None) with mock.patch.object(github3.GitHubEnterprise, 'login') as login: - g = github3.login(*args) + g = github3.enterprise_login(*args) assert isinstance(g, github3.GitHubEnterprise) - assert not isinstance(g, github3.GitHub) - login.assert_called_once_with(*args) + login.assert_called_once_with('login', 'password', None, None) def test_login(self): args = ('login', 'password', None, None) From 8c17a660645d56d1715004d7efdbb5e6a69fe65d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 27 Jan 2014 20:19:52 -0600 Subject: [PATCH 014/972] Return what I really expect __iter__ to do What convinces me of this is what happens if you do `list(NullObject())`. The list should be empty but instead you received a single-element list with the NullObject instance in it. That's just wrong. --- github3/structs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github3/structs.py b/github3/structs.py index 579be5afd..d5cb61873 100644 --- a/github3/structs.py +++ b/github3/structs.py @@ -177,7 +177,7 @@ def __contains__(self, other): return False def __iter__(self): - yield self + return iter([]) def __next__(self): raise StopIteration From 5321495e05835bd7669cdcca734f54106590783e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 27 Jan 2014 20:34:40 -0600 Subject: [PATCH 015/972] Test NullObject --- tests/unit/test_structs.py | 55 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_structs.py b/tests/unit/test_structs.py index eb25e617e..d82b4aa14 100644 --- a/tests/unit/test_structs.py +++ b/tests/unit/test_structs.py @@ -1,5 +1,8 @@ -from .helper import UnitHelper, mock -from github3.structs import GitHubIterator +from .helper import UnitHelper +from github3.structs import GitHubIterator, NullObject + +import mock +import pytest class TestGitHubIterator(UnitHelper): @@ -36,3 +39,51 @@ def test_stores_headers_properly(self): i = GitHubIterator(count, url, cls, session, headers=headers) assert i.headers != {} assert i.headers.get('Accept') == 'foo' + + +class TestNullObject(UnitHelper): + described_class = NullObject + + def create_instance_of_described_class(self): + return self.described_class() + + def test_returns_empty_list(self): + assert list(self.instance) == [] + + def test_contains_nothing(self): + assert 'foo' not in self.instance + + def test_returns_itself_when_called(self): + assert self.instance('foo', 'bar', 'bogus') is self.instance + + def test_returns_empty_string(self): + assert str(self.instance) == '' + + def test_allows_arbitrary_attributes(self): + assert self.instance.attr is self.instance + + def test_allows_arbitrary_attributes_to_be_set(self): + self.instance.attr = 'new' + assert self.instance.attr is self.instance + + def test_provides_an_api_to_check_if_it_is_null(self): + assert self.instance.is_null() + + def test_stops_iteration(self): + with pytest.raises(StopIteration): + next(self.instance) + + def test_next_raises_stops_iteration(self): + with pytest.raises(StopIteration): + self.instance.next() + + def test_getitem_returns_itself(self): + assert self.instance['attr'] is self.instance + + def test_setitem_sets_nothing(self): + self.instance['attr'] = 'attr' + assert self.instance['attr'] is self.instance + + def test_turns_into_unicode(self): + unicode_str = b''.decode('utf-8') + assert unicode(self.instance) == unicode_str From f1d39b0700d06953d6513a073058e03b2a289b9f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 27 Jan 2014 21:41:54 -0600 Subject: [PATCH 016/972] Start migrating old tests --- tests/test_api.py | 52 ------------------------------------------ tests/unit/test_api.py | 36 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index a57813e8c..c7ee7c5b9 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -12,54 +12,6 @@ def setUp(self): def tearDown(self): self.mock.stop() - def test_authorize(self): - args = ('login', 'password', ['scope1'], 'note', 'note_url.com', '', - '') - with mock.patch.object(github3.api.GitHub, 'authorize') as authorize: - github3.authorize(*args) - authorize.assert_called_once_with(*args) - - def test_login(self): - args = ('login', 'password', None, None) - with mock.patch.object(github3.api.GitHub, 'login') as login: - g = github3.login(*args) - assert isinstance(g, github3.github.GitHub) - assert not isinstance(g, github3.github.GitHubEnterprise) - login.assert_called_with(*args) - - def test_enterprise_login(self): - args = ('login', 'password', None, 'http://ghe.invalid/', None) - with mock.patch.object(github3.api.GitHubEnterprise, 'login') as login: - g = github3.login(*args) - assert isinstance(g, github3.github.GitHubEnterprise) - login.assert_called_with('login', 'password', None, None) - - def test_gist(self): - args = (123,) - github3.gist(*args) - self.gh.gist.assert_called_with(*args) - - def test_gitignore_template(self): - args = ('Python',) - github3.gitignore_template(*args) - self.gh.gitignore_template.assert_called_with(*args) - - def test_gitignore_templates(self): - github3.gitignore_templates() - assert self.gh.gitignore_templates.called is True - - def test_iter_all_repos(self): - github3.iter_all_repos() - self.gh.iter_all_repos.assert_called_with(-1, None) - - def test_iter_all_users(self): - github3.iter_all_users() - self.gh.iter_all_users.assert_called_with(-1, None) - - def test_iter_events(self): - github3.iter_events() - self.gh.iter_events.assert_called_with(-1, None) - def test_iter_followers(self): github3.iter_followers('login') self.gh.iter_followers.assert_called_with('login', -1, None) @@ -68,10 +20,6 @@ def test_iter_following(self): github3.iter_following('login') self.gh.iter_following.assert_called_with('login', -1, None) - def test_iter_gists(self): - github3.iter_gists() - self.gh.iter_gists.assert_called_with(None, -1, None) - def test_iter_repo_issues(self): args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 7d56769ca..5277141db 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -12,6 +12,24 @@ def setUp(self): def tearDown(self): self.mocked_github.stop() + def test_all_events(self): + github3.all_events() + self.gh.iter_events.assert_called_once_with(-1, None) + + def test_all_gists(self): + github3.all_gists() + self.gh.iter_gists.assert_called_once_with(None, -1, None) + + def test_all_repos(self): + github3.all_repos() + # TODO(Ian): When you fix GitHub, fix this test too + self.gh.iter_all_repos.assert_called_once_with(-1, None) + + def test_all_users(self): + github3.all_users() + # TODO(Ian): Fix this when GitHub changes + self.gh.iter_all_users.assert_called_once_with(-1, None) + def test_authorize(self): args = ('login', 'password', ['scope'], 'note', 'url.com', '', '') github3.authorize(*args) @@ -24,6 +42,24 @@ def test_enterprise_login(self): assert isinstance(g, github3.GitHubEnterprise) login.assert_called_once_with('login', 'password', None, None) + def test_gist(self): + gist_id = 123 + github3.gist(gist_id) + self.gh.gist.assert_called_once_with(gist_id) + + def test_gists_for(self): + github3.gists_for('username') + self.gh.iter_gists.assert_called_once_with('username', -1, None) + + def test_gitignore_template(self): + language = 'Python' + github3.gitignore_template(language) + self.gh.gitignore_template.assert_called_once_with(language) + + def test_gitignore_templates(self): + github3.gitignore_templates() + assert self.gh.gitignore_templates.called is True + def test_login(self): args = ('login', 'password', None, None) with mock.patch.object(github3.GitHub, 'login') as login: From eff36d2030d9656c7cf83a559a95ec3c89bf98aa Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 30 Jan 2014 06:30:06 -0600 Subject: [PATCH 017/972] Add a bunch of urls and url templates we were missing --- github3/repos/repo.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 607dcbbb4..dabbf9f9f 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -95,6 +95,15 @@ def __init__(self, repo, session=None): #: URL of the home page for the project. self.homepage = repo.get('homepage', '') + #: URL of the pure diff of the pull request + self.diff_url = repo.get('diff_url', '') + + #: URL of the pure patch of the pull request + self.patch_url = repo.get('patch_url', '') + + #: API URL of the issue representation of this Pull Request + self.issue_url = repo.get('issue_url', '') + # e.g. https://github.com/sigmavirus24/github3.py #: URL of the project at GitHub. self.html_url = repo.get('html_url', '') @@ -240,6 +249,14 @@ def __init__(self, repo, session=None): #: Comments URL Template. Expand with ``number`` self.comments_urlt = URITemplate(comments) if comments else None + comments = repo.get('review_comments_url') + #: Pull Request Review Comments URL + self.review_comments_url = URITemplate(comments) if comments else None + + comments = repo.get('review_comment_url') + #: Pull Request Review Comments URL Template. Expand with ``number`` + self.review_comment_urlt = URITemplate(comments) if comments else None + comments = repo.get('issue_comment_url') #: Issue comment URL Template. Expand with ``number`` self.issue_comment_urlt = URITemplate(comments) if comments else None From ea3cee64bae6fcdc44a688da0bd6fbe3f58fb347 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 1 Feb 2014 14:17:25 -0600 Subject: [PATCH 018/972] Use pep257 for Subscription's docstring --- github3/notifications.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/github3/notifications.py b/github3/notifications.py index 01f9f4e2a..3e64fba96 100644 --- a/github3/notifications.py +++ b/github3/notifications.py @@ -104,12 +104,14 @@ def subscription(self): class Subscription(GitHubCore): - """The :class:`Subscription ` object wraps thread and - repository subscription information. + + """This object wraps thread and repository subscription information. See also: - http://developer.github.com/v3/activity/notifications/#get-a-thread-subscription + developer.github.com/v3/activity/notifications/#get-a-thread-subscription + """ + def __init__(self, sub, session=None): super(Subscription, self).__init__(sub, session) self._api = sub.get('url') From ee9bce3624250e87718ebec019df34ffb93766af Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 1 Feb 2014 14:17:41 -0600 Subject: [PATCH 019/972] Assert condition about correct attribute --- tests/integration/test_repos_repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 963bd0a37..348eb7102 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -50,7 +50,7 @@ def test_ignore(self): 'gmond_python_modules') assert repository is not None subscription = repository.ignore() - assert subscription.ignore is True + assert subscription.ignored is True def test_iter_languages(self): """Test that a repository's languages can be retrieved.""" From a1128bcdcb8bac7d3c44608a2d1acceb3fe73306 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 1 Feb 2014 14:18:07 -0600 Subject: [PATCH 020/972] Remove tests around removed legacy API --- tests/test_github.py | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 30392f07b..3a9db978a 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -196,20 +196,6 @@ def test_is_starred(self): assert self.g.is_starred('user', 'repo') is True self.mock_assertions() - def test_is_subscribed(self): - self.response(None, 204) - self.get('https://api.github.com/user/subscriptions/user/repo') - - self.assertRaises(github3.GitHubError, self.g.is_subscribed, - 'user', 'repo') - - self.login() - assert self.g.is_subscribed(None, None) is False - assert self.request.called is False - - assert self.g.is_subscribed('user', 'repo') - self.mock_assertions() - def test_issue(self): self.response('issue', 200) self.get('https://api.github.com/repos/sigmavirus24/github3.py/' @@ -708,19 +694,6 @@ def test_star(self): assert self.g.star('sigmavirus24', 'github3.py') self.mock_assertions() - def test_subscribe(self): - self.response('', 204) - self.put('https://api.github.com/user/subscriptions/' - 'sigmavirus24/github3.py') - self.conf = {'data': None} - - self.assertRaises(github3.GitHubError, self.g.subscribe, 'foo', 'bar') - - self.login() - assert self.g.subscribe(None, None) is False - assert self.g.subscribe('sigmavirus24', 'github3.py') - self.mock_assertions() - def test_unfollow(self): self.response('', 204) self.delete('https://api.github.com/user/following/' @@ -747,20 +720,6 @@ def test_unstar(self): assert self.g.unstar('sigmavirus24', 'github3.py') self.mock_assertions() - def test_unsubscribe(self): - self.response('', 204) - self.delete('https://api.github.com/user/subscriptions/' - 'sigmavirus24/github3.py') - self.conf = {} - - self.assertRaises(github3.GitHubError, self.g.unsubscribe, - 'foo', 'bar') - - self.login() - assert self.g.unsubscribe(None, None) is False - assert self.g.unsubscribe('sigmavirus24', 'github3.py') - self.mock_assertions() - def test_update_user(self): self.login() args = ('Ian Cordasco', 'example@mail.com', 'www.blog.com', 'company', From d4ca2ea2df7afa8b84f0abc29c7e62163d7a775b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 1 Feb 2014 14:19:26 -0600 Subject: [PATCH 021/972] Remove test around pre-1.x API --- tests/test_repos.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index 154963139..acc2a4c6f 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -961,20 +961,6 @@ def test_source(self): r = repos.Repository(json) assert isinstance(r.source, repos.Repository) - def test_set_subscription(self): - self.response('subscription') - self.put(self.api + 'subscription') - self.conf = {'data': {'subscribed': True, 'ignored': False}} - - self.assertRaises(github3.GitHubError, self.repo.set_subscription, - True, False) - self.not_called() - - self.login() - s = self.repo.set_subscription(True, False) - assert isinstance(s, github3.notifications.Subscription) - self.mock_assertions() - def test_subscription(self): self.response('subscription') self.get(self.api + 'subscription') From 7c5ea7f0dc6432e77c13e29f38cb199dcaa55a14 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 1 Feb 2014 19:49:38 -0600 Subject: [PATCH 022/972] Fix a few more broken tests --- tests/test_api.py | 16 ---------------- tests/unit/test_api.py | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index c7ee7c5b9..80f548f56 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -20,14 +20,6 @@ def test_iter_following(self): github3.iter_following('login') self.gh.iter_following.assert_called_with('login', -1, None) - def test_iter_repo_issues(self): - args = ('owner', 'repository', None, None, None, None, None, None, - None, None, -1, None) - github3.iter_repo_issues(*args) - self.gh.iter_repo_issues.assert_called_with(*args) - - github3.iter_repo_issues(None, None) - def test_iter_orgs(self): args = ('login', -1, None) github3.iter_orgs(*args) @@ -40,14 +32,6 @@ def test_iter_user_repos(self): github3.iter_user_repos(None) - def test_iter_starred(self): - github3.iter_starred('login') - self.gh.iter_starred.assert_called_with('login', -1, None) - - def test_iter_subcriptions(self): - github3.iter_subscriptions('login') - self.gh.iter_subscriptions.assert_called_with('login', -1, None) - def test_create_gist(self): args = ('description', {'files': ['files']}) github3.create_gist(*args) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 5277141db..7dfd8ac88 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -67,3 +67,17 @@ def test_login(self): assert isinstance(g, github3.GitHub) assert not isinstance(g, github3.GitHubEnterprise) login.assert_called_once_with(*args) + + def test_repo_issues(self): + args = ('owner', 'repository', None, None, None, None, None, None, + None, None, -1, None) + github3.repo_issues(*args) + self.gh.iter_repo_issues.assert_called_with(*args) + + def test_starred(self): + github3.starred('login') + self.gh.iter_starred.assert_called_with('login', -1, None) + + def test_subcriptions(self): + github3.subscriptions('login') + self.gh.iter_subscriptions.assert_called_with('login', -1, None) From 5a647e0411b06b59ac56e1c47e1c570df3589ee2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 1 Feb 2014 20:07:05 -0600 Subject: [PATCH 023/972] Fix the last of the tests --- HISTORY.rst | 4 ++-- github3/api.py | 4 ++-- tests/test_api.py | 20 -------------------- tests/unit/test_api.py | 18 ++++++++++++++++++ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index d0213627f..4665b57a8 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -19,8 +19,8 @@ Old name New name ``github3.iter_all_repos`` ``github3.all_repos`` ``github3.iter_all_users`` ``github3.all_users`` ``github3.iter_events`` ``github3.all_events`` -``github3.iter_followers`` ``github3.followers`` -``github3.iter_following`` ``github3.following`` +``github3.iter_followers`` ``github3.followers_of`` +``github3.iter_following`` ``github3.followed_by`` ``github3.iter_repo_issues`` ``github3.repo_issues`` ``github3.iter_orgs`` ``github3.organizations`` ``github3.iter_user_repos`` ``github3.user_repos`` diff --git a/github3/api.py b/github3/api.py index 41c3c92c1..46dc9f8bf 100644 --- a/github3/api.py +++ b/github3/api.py @@ -170,7 +170,7 @@ def all_events(number=-1, etag=None): return gh.iter_events(number, etag) -def followers(username, number=-1, etag=None): +def followers_of(username, number=-1, etag=None): """List the followers of ``username``. :param str username: (required), login of the person to list the followers @@ -185,7 +185,7 @@ def followers(username, number=-1, etag=None): return gh.iter_followers(username, number, etag) if username else [] -def following(username, number=-1, etag=None): +def followed_by(username, number=-1, etag=None): """List the people ``username`` follows. :param str username: (required), login of the user diff --git a/tests/test_api.py b/tests/test_api.py index 80f548f56..6d13cb088 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -12,26 +12,6 @@ def setUp(self): def tearDown(self): self.mock.stop() - def test_iter_followers(self): - github3.iter_followers('login') - self.gh.iter_followers.assert_called_with('login', -1, None) - - def test_iter_following(self): - github3.iter_following('login') - self.gh.iter_following.assert_called_with('login', -1, None) - - def test_iter_orgs(self): - args = ('login', -1, None) - github3.iter_orgs(*args) - self.gh.iter_orgs.assert_called_with(*args) - - def test_iter_user_repos(self): - args = ('login', None, None, None, -1, None) - github3.iter_user_repos('login') - self.gh.iter_user_repos.assert_called_with(*args) - - github3.iter_user_repos(None) - def test_create_gist(self): args = ('description', {'files': ['files']}) github3.create_gist(*args) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 7dfd8ac88..174e2b5b0 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -42,6 +42,14 @@ def test_enterprise_login(self): assert isinstance(g, github3.GitHubEnterprise) login.assert_called_once_with('login', 'password', None, None) + def test_followers_of(self): + github3.followers_of('login') + self.gh.iter_followers.assert_called_with('login', -1, None) + + def test_followed_by(self): + github3.followed_by('login') + self.gh.iter_following.assert_called_with('login', -1, None) + def test_gist(self): gist_id = 123 github3.gist(gist_id) @@ -68,6 +76,11 @@ def test_login(self): assert not isinstance(g, github3.GitHubEnterprise) login.assert_called_once_with(*args) + def test_organizations(self): + args = ('login', -1, None) + github3.organizations(*args) + self.gh.iter_orgs.assert_called_with(*args) + def test_repo_issues(self): args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) @@ -81,3 +94,8 @@ def test_starred(self): def test_subcriptions(self): github3.subscriptions('login') self.gh.iter_subscriptions.assert_called_with('login', -1, None) + + def test_user_repos(self): + args = ('login', None, None, None, -1, None) + github3.user_repos('login') + self.gh.iter_user_repos.assert_called_with(*args) From 773a093aee9e435645b1ef91e6248212b3657517 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 2 Feb 2014 11:33:53 -0600 Subject: [PATCH 024/972] Properly test on python 3 --- tests/unit/test_structs.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_structs.py b/tests/unit/test_structs.py index d82b4aa14..f2e8f780a 100644 --- a/tests/unit/test_structs.py +++ b/tests/unit/test_structs.py @@ -86,4 +86,7 @@ def test_setitem_sets_nothing(self): def test_turns_into_unicode(self): unicode_str = b''.decode('utf-8') - assert unicode(self.instance) == unicode_str + try: + assert unicode(self.instance) == unicode_str + except NameError: + assert str(self.instance) == unicode_str From db8ccf161e3b693d2a425e0c3da249ec2bd97bd7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 2 Feb 2014 14:19:49 -0600 Subject: [PATCH 025/972] Make the NullObject false-y --- github3/structs.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/github3/structs.py b/github3/structs.py index d5cb61873..36d881191 100644 --- a/github3/structs.py +++ b/github3/structs.py @@ -147,6 +147,11 @@ class NullObject(object): def __init__(self, initializer=None): self.__dict__['initializer'] = initializer + def __bool__(self): + return False + + __nonzero__ = __bool__ + def __str__(self): return '' From d5079010d4ffc75100fa052e899e7988d895dd70 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 2 Feb 2014 14:35:50 -0600 Subject: [PATCH 026/972] Test for falsey-ness of NullObject instances --- tests/unit/test_structs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/test_structs.py b/tests/unit/test_structs.py index f2e8f780a..364294f03 100644 --- a/tests/unit/test_structs.py +++ b/tests/unit/test_structs.py @@ -90,3 +90,7 @@ def test_turns_into_unicode(self): assert unicode(self.instance) == unicode_str except NameError: assert str(self.instance) == unicode_str + + def test_instances_are_falsey(self): + if self.instance: + pytest.fail() From 515d9fb5e4ca70e67da7bd5d67a323b4266a9b2f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 4 Feb 2014 21:21:43 -0600 Subject: [PATCH 027/972] Use a better parameter name --- github3/github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github3/github.py b/github3/github.py index 5cf60422a..0f2588814 100644 --- a/github3/github.py +++ b/github3/github.py @@ -68,8 +68,8 @@ def __exit__(self, *args): pass @requires_auth - def _iter_follow(self, which, number, etag): - url = self._build_url('user', which) + def _iter_follow(self, follow_path, number, etag): + url = self._build_url('user', follow_path) return self._iter(number, url, User, etag=etag) @requires_basic_auth From 3c0205218c46b2adee080191df002dd0e58d1d10 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 4 Feb 2014 21:36:30 -0600 Subject: [PATCH 028/972] Rename all the GitHub#iter Update the HISTORY --- HISTORY.rst | 27 ++++++++++++++++++--- github3/github.py | 60 +++++++++++++++++++++++------------------------ 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 4665b57a8..cc9dbb0dc 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,9 +13,9 @@ Breaking Changes - All methods and functions starting with ``iter_`` have been renamed. -============================== ========================= +============================== ============================== Old name New name -============================== ========================= +============================== ============================== ``github3.iter_all_repos`` ``github3.all_repos`` ``github3.iter_all_users`` ``github3.all_users`` ``github3.iter_events`` ``github3.all_events`` @@ -27,7 +27,28 @@ Old name New name ``github3.iter_starred`` ``github3.starred`` ``github3.iter_subscriptions`` ``github3.subscriptions`` ``github3.iter_subscriptions`` ``github3.subscriptions`` -============================== ========================= +``GitHub#iter_all_repos`` ``GitHub#all_repos`` +``GitHub#iter_all_users`` ``GitHub#all_users`` +``GitHub#iter_authorizations`` ``GitHub#authorizations`` +``GitHub#iter_emails`` ``GitHub#emails`` +``GitHub#iter_events`` ``GitHub#events`` +``GitHub#iter_followers`` ``GitHub#followers`` +``GitHub#iter_following`` ``GitHub#following`` +``GitHub#iter_gists`` ``GitHub#gists`` +``GitHub#iter_notifications`` ``GitHub#notifications`` +``GitHub#iter_org_issues`` ``GitHub#organization_issues`` +``GitHub#iter_issues`` ``GitHub#issues`` +``GitHub#iter_user_issues`` ``GitHub#user_issues`` +``GitHub#iter_repo_issues`` ``GitHub#repo_issues`` +``GitHub#iter_keys`` ``GitHub#keys`` +``GitHub#iter_orgs`` ``GitHub#organizations`` +``GitHub#iter_repos`` ``GitHub#repos`` +``GitHub#iter_starred`` ``GitHub#starred`` +``GitHub#iter_subscriptions`` ``GitHub#subscriptions`` +``GitHub#iter_user_repos`` ``GitHub#user_repos`` +``GitHub#iter_user_teams`` ``GitHub#user_teams`` + +============================== ============================== - ``github3.login`` has been simplified and split into two functions: diff --git a/github3/github.py b/github3/github.py index 0f2588814..ff4bac916 100644 --- a/github3/github.py +++ b/github3/github.py @@ -393,7 +393,7 @@ def issue(self, owner, repository, number): return repo.issue(number) return None - def iter_all_repos(self, number=-1, since=None, etag=None, per_page=None): + def all_repos(self, number=-1, since=None, etag=None, per_page=None): """Iterate over every repository in the order they were created. :param int number: (optional), number of repositories to return. @@ -411,7 +411,7 @@ def iter_all_repos(self, number=-1, since=None, etag=None, per_page=None): params={'since': since, 'per_page': per_page}, etag=etag) - def iter_all_users(self, number=-1, etag=None, per_page=None): + def all_users(self, number=-1, etag=None, per_page=None): """Iterate over every user in the order they signed up for GitHub. :param int number: (optional), number of users to return. Default: -1, @@ -426,7 +426,7 @@ def iter_all_users(self, number=-1, etag=None, per_page=None): params={'per_page': per_page}, etag=etag) @requires_basic_auth - def iter_authorizations(self, number=-1, etag=None): + def authorizations(self, number=-1, etag=None): """Iterate over authorizations for the authenticated user. This will return a 404 if you are using a token for authentication. @@ -440,7 +440,7 @@ def iter_authorizations(self, number=-1, etag=None): return self._iter(int(number), url, Authorization, etag=etag) @requires_auth - def iter_emails(self, number=-1, etag=None): + def emails(self, number=-1, etag=None): """Iterate over email addresses for the authenticated user. :param int number: (optional), number of email addresses to return. @@ -452,7 +452,7 @@ def iter_emails(self, number=-1, etag=None): url = self._build_url('user', 'emails') return self._iter(int(number), url, dict, etag=etag) - def iter_events(self, number=-1, etag=None): + def events(self, number=-1, etag=None): """Iterate over public events. :param int number: (optional), number of events to return. Default: -1 @@ -464,7 +464,7 @@ def iter_events(self, number=-1, etag=None): url = self._build_url('events') return self._iter(int(number), url, Event, etag=etag) - def iter_followers(self, login=None, number=-1, etag=None): + def followers(self, login=None, number=-1, etag=None): """If login is provided, iterate over a generator of followers of that login name; otherwise return a generator of followers of the authenticated user. @@ -480,7 +480,7 @@ def iter_followers(self, login=None, number=-1, etag=None): return self.user(login).iter_followers() return self._iter_follow('followers', int(number), etag=etag) - def iter_following(self, login=None, number=-1, etag=None): + def following(self, login=None, number=-1, etag=None): """If login is provided, iterate over a generator of users being followed by login; otherwise return a generator of people followed by the authenticated user. @@ -496,7 +496,7 @@ def iter_following(self, login=None, number=-1, etag=None): return self.user(login).iter_following() return self._iter_follow('following', int(number), etag=etag) - def iter_gists(self, username=None, number=-1, etag=None): + def gists(self, username=None, number=-1, etag=None): """If no username is specified, GET /gists, otherwise GET /users/:username/gists @@ -514,8 +514,8 @@ def iter_gists(self, username=None, number=-1, etag=None): return self._iter(int(number), url, Gist, etag=etag) @requires_auth - def iter_notifications(self, all=False, participating=False, number=-1, - etag=None): + def notifications(self, all=False, participating=False, number=-1, + etag=None): """Iterate over the user's notification. :param bool all: (optional), iterate over all notifications @@ -537,8 +537,8 @@ def iter_notifications(self, all=False, participating=False, number=-1, return self._iter(int(number), url, Thread, params, etag=etag) @requires_auth - def iter_org_issues(self, name, filter='', state='', labels='', sort='', - direction='', since=None, number=-1, etag=None): + def organization_issues(self, name, filter='', state='', labels='', sort='', + direction='', since=None, number=-1, etag=None): """Iterate over the organnization's issues if the authenticated user belongs to it. @@ -570,8 +570,8 @@ def iter_org_issues(self, name, filter='', state='', labels='', sort='', return self._iter(int(number), url, Issue, params, etag) @requires_auth - def iter_issues(self, filter='', state='', labels='', sort='', - direction='', since=None, number=-1, etag=None): + def issues(self, filter='', state='', labels='', sort='', direction='', + since=None, number=-1, etag=None): """List all of the authenticated user's (and organization's) issues. .. versionchanged:: 0.9.0 @@ -606,8 +606,8 @@ def iter_issues(self, filter='', state='', labels='', sort='', return self._iter(int(number), url, Issue, params, etag) @requires_auth - def iter_user_issues(self, filter='', state='', labels='', sort='', - direction='', since=None, number=-1, etag=None): + def user_issues(self, filter='', state='', labels='', sort='', + direction='', since=None, number=-1, etag=None): """List only the authenticated user's issues. Will not list organization's issues @@ -642,10 +642,10 @@ def iter_user_issues(self, filter='', state='', labels='', sort='', params = issue_params(filter, state, labels, sort, direction, since) return self._iter(int(number), url, Issue, params, etag) - def iter_repo_issues(self, owner, repository, milestone=None, - state=None, assignee=None, mentioned=None, - labels=None, sort=None, direction=None, since=None, - number=-1, etag=None): + def repo_issues(self, owner, repository, milestone=None, + state=None, assignee=None, mentioned=None, + labels=None, sort=None, direction=None, since=None, + number=-1, etag=None): """List issues on owner/repository. Only owner and repository are required. @@ -685,7 +685,7 @@ def iter_repo_issues(self, owner, repository, milestone=None, return iter([]) @requires_auth - def iter_keys(self, number=-1, etag=None): + def keys(self, number=-1, etag=None): """Iterate over public keys for the authenticated user. :param int number: (optional), number of keys to return. Default: -1 @@ -697,7 +697,7 @@ def iter_keys(self, number=-1, etag=None): url = self._build_url('user', 'keys') return self._iter(int(number), url, Key, etag=etag) - def iter_orgs(self, login=None, number=-1, etag=None): + def organizations(self, login=None, number=-1, etag=None): """Iterate over public organizations for login if provided; otherwise iterate over public and private organizations for the authenticated user. @@ -718,8 +718,8 @@ def iter_orgs(self, login=None, number=-1, etag=None): return self._iter(int(number), url, Organization, etag=etag) @requires_auth - def iter_repos(self, type=None, sort=None, direction=None, number=-1, - etag=None): + def repos(self, type=None, sort=None, direction=None, number=-1, + etag=None): """List public repositories for the authenticated user. .. versionchanged:: 0.6 @@ -754,8 +754,8 @@ def iter_repos(self, type=None, sort=None, direction=None, number=-1, return self._iter(int(number), url, Repository, params, etag) - def iter_starred(self, login=None, sort=None, direction=None, number=-1, - etag=None): + def starred(self, login=None, sort=None, direction=None, number=-1, + etag=None): """Iterate over repositories starred by ``login`` or the authenticated user. @@ -782,7 +782,7 @@ def iter_starred(self, login=None, sort=None, direction=None, number=-1, url = self._build_url('user', 'starred') return self._iter(int(number), url, Repository, params, etag) - def iter_subscriptions(self, login=None, number=-1, etag=None): + def subscriptions(self, login=None, number=-1, etag=None): """Iterate over repositories subscribed to by ``login`` or the authenticated user. @@ -800,8 +800,8 @@ def iter_subscriptions(self, login=None, number=-1, etag=None): url = self._build_url('user', 'subscriptions') return self._iter(int(number), url, Repository, etag=etag) - def iter_user_repos(self, login, type=None, sort=None, direction=None, - number=-1, etag=None): + def user_repos(self, login, type=None, sort=None, direction=None, + number=-1, etag=None): """List public repositories for the specified ``login``. .. versionadded:: 0.6 @@ -836,7 +836,7 @@ def iter_user_repos(self, login, type=None, sort=None, direction=None, return self._iter(int(number), url, Repository, params, etag) @requires_auth - def iter_user_teams(self, number=-1, etag=None): + def user_teams(self, number=-1, etag=None): """Gets the authenticated user's teams across all of organizations. List all of the teams across all of the organizations to which the From 322d4e7124642ee894d6a3e3f682977ca78df3bc Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 5 Feb 2014 21:37:48 -0600 Subject: [PATCH 029/972] Improve the API further --- github3/github.py | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/github3/github.py b/github3/github.py index ff4bac916..8f282088a 100644 --- a/github3/github.py +++ b/github3/github.py @@ -452,7 +452,7 @@ def emails(self, number=-1, etag=None): url = self._build_url('user', 'emails') return self._iter(int(number), url, dict, etag=etag) - def events(self, number=-1, etag=None): + def all_events(self, number=-1, etag=None): """Iterate over public events. :param int number: (optional), number of events to return. Default: -1 @@ -464,7 +464,7 @@ def events(self, number=-1, etag=None): url = self._build_url('events') return self._iter(int(number), url, Event, etag=etag) - def followers(self, login=None, number=-1, etag=None): + def followers_of(self, login, number=-1, etag=None): """If login is provided, iterate over a generator of followers of that login name; otherwise return a generator of followers of the authenticated user. @@ -476,11 +476,13 @@ def followers(self, login=None, number=-1, etag=None): endpoint :returns: generator of :class:`User `\ s """ - if login: - return self.user(login).iter_followers() + return self.user(login).iter_followers() + + @requires_auth + def followers(self, number=-1, etag=None): return self._iter_follow('followers', int(number), etag=etag) - def following(self, login=None, number=-1, etag=None): + def followed_by(self, login, number=-1, etag=None): """If login is provided, iterate over a generator of users being followed by login; otherwise return a generator of people followed by the authenticated user. @@ -492,25 +494,35 @@ def following(self, login=None, number=-1, etag=None): endpoint :returns: generator of :class:`User `\ s """ - if login: - return self.user(login).iter_following() + return self.user(login).iter_following() + + @requires_auth + def following(self, number=-1, etag=None): return self._iter_follow('following', int(number), etag=etag) - def gists(self, username=None, number=-1, etag=None): - """If no username is specified, GET /gists, otherwise GET - /users/:username/gists + def all_gists(self, number=-1, etag=None): + """Retrieve all gists and iterate over them. - :param str login: (optional), login of the user to check :param int number: (optional), number of gists to return. Default: -1 returns all available gists :param str etag: (optional), ETag from a previous request to the same endpoint :returns: generator of :class:`Gist `\ s """ - if username: - url = self._build_url('users', username, 'gists') - else: - url = self._build_url('gists') + url = self._build_url('gists') + return self._iter(int(number), url, Gist, etag=etag) + + def gists_for(self, username, number=-1, etag=None): + """Iterate over the gists owned by a user. + + :param str login: login of the user who owns the gists + :param int number: (optional), number of gists to return. Default: -1 + returns all available gists + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Gist `\ s + """ + url = self._build_url('users', username, 'gists') return self._iter(int(number), url, Gist, etag=etag) @requires_auth From 2ac702638905ccd480d2f814ffba83c168662021 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 5 Feb 2014 21:45:07 -0600 Subject: [PATCH 030/972] Public API now uses the correct methods Tests are marginally less failing --- github3/api.py | 22 +++++++++++----------- tests/unit/test_api.py | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/github3/api.py b/github3/api.py index 46dc9f8bf..27cdad15b 100644 --- a/github3/api.py +++ b/github3/api.py @@ -141,7 +141,7 @@ def all_repos(number=-1, etag=None): :returns: generator of :class:`Repository ` """ - return gh.iter_all_repos(number, etag) + return gh.all_repos(number, etag) def all_users(number=-1, etag=None): @@ -154,7 +154,7 @@ def all_users(number=-1, etag=None): :returns: generator of :class:`User ` """ - return gh.iter_all_users(number, etag) + return gh.all_users(number, etag) def all_events(number=-1, etag=None): @@ -167,7 +167,7 @@ def all_events(number=-1, etag=None): :returns: generator of :class:`Event ` """ - return gh.iter_events(number, etag) + return gh.all_events(number, etag) def followers_of(username, number=-1, etag=None): @@ -182,7 +182,7 @@ def followers_of(username, number=-1, etag=None): :returns: generator of :class:`User ` """ - return gh.iter_followers(username, number, etag) if username else [] + return gh.followers_of(username, number, etag) if username else [] def followed_by(username, number=-1, etag=None): @@ -196,7 +196,7 @@ def followed_by(username, number=-1, etag=None): :returns: generator of :class:`User ` """ - return gh.iter_following(username, number, etag) if username else [] + return gh.followed_by(username, number, etag) if username else [] def all_gists(number=-1, etag=None): @@ -213,7 +213,7 @@ def all_gists(number=-1, etag=None): :returns: generator of :class:`Gist ` """ - return gh.iter_gists(None, number, etag) + return gh.all_gists(None, number, etag) def gists_for(username, number=-1, etag=None): @@ -229,7 +229,7 @@ def gists_for(username, number=-1, etag=None): """ if username: - return gh.iter_gists(username, number, etag) + return gh.gists_for(username, number, etag) return iter([]) @@ -281,7 +281,7 @@ def organizations(username, number=-1, etag=None): :class:`Organization ` """ - return gh.iter_orgs(username, number, etag) if username else [] + return gh.organizations(username, number, etag) if username else [] def user_repos(login, type=None, sort=None, direction=None, number=-1, @@ -311,7 +311,7 @@ def user_repos(login, type=None, sort=None, direction=None, number=-1, """ if login: - return gh.iter_user_repos(login, type, sort, direction, number, etag) + return gh.user_repos(login, type, sort, direction, number, etag) return iter([]) @@ -326,7 +326,7 @@ def starred(username, number=-1, etag=None): :returns: generator of :class:`Repository ` """ - return gh.iter_starred(username, number, etag) + return gh.starred(username, number, etag) def subscriptions(username, number=-1, etag=None): @@ -341,7 +341,7 @@ def subscriptions(username, number=-1, etag=None): :returns: generator of :class:`Repository ` """ - return gh.iter_subscriptions(username, number, etag) + return gh.subscriptions(username, number, etag) def create_gist(description, files): diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 174e2b5b0..b0ab57a61 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -14,21 +14,21 @@ def tearDown(self): def test_all_events(self): github3.all_events() - self.gh.iter_events.assert_called_once_with(-1, None) + self.gh.all_events.assert_called_once_with(-1, None) def test_all_gists(self): github3.all_gists() - self.gh.iter_gists.assert_called_once_with(None, -1, None) + self.gh.all_gists.assert_called_once_with(None, -1, None) def test_all_repos(self): github3.all_repos() # TODO(Ian): When you fix GitHub, fix this test too - self.gh.iter_all_repos.assert_called_once_with(-1, None) + self.gh.all_repos.assert_called_once_with(-1, None) def test_all_users(self): github3.all_users() # TODO(Ian): Fix this when GitHub changes - self.gh.iter_all_users.assert_called_once_with(-1, None) + self.gh.all_users.assert_called_once_with(-1, None) def test_authorize(self): args = ('login', 'password', ['scope'], 'note', 'url.com', '', '') @@ -44,11 +44,11 @@ def test_enterprise_login(self): def test_followers_of(self): github3.followers_of('login') - self.gh.iter_followers.assert_called_with('login', -1, None) + self.gh.followers_of.assert_called_with('login', -1, None) def test_followed_by(self): github3.followed_by('login') - self.gh.iter_following.assert_called_with('login', -1, None) + self.gh.followed_by.assert_called_with('login', -1, None) def test_gist(self): gist_id = 123 @@ -57,7 +57,7 @@ def test_gist(self): def test_gists_for(self): github3.gists_for('username') - self.gh.iter_gists.assert_called_once_with('username', -1, None) + self.gh.gists_for.assert_called_once_with('username', -1, None) def test_gitignore_template(self): language = 'Python' @@ -79,23 +79,23 @@ def test_login(self): def test_organizations(self): args = ('login', -1, None) github3.organizations(*args) - self.gh.iter_orgs.assert_called_with(*args) + self.gh.organizations.assert_called_with(*args) def test_repo_issues(self): args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) github3.repo_issues(*args) - self.gh.iter_repo_issues.assert_called_with(*args) + self.gh.repo_issues.assert_called_with(*args) def test_starred(self): github3.starred('login') - self.gh.iter_starred.assert_called_with('login', -1, None) + self.gh.starred.assert_called_with('login', -1, None) def test_subcriptions(self): github3.subscriptions('login') - self.gh.iter_subscriptions.assert_called_with('login', -1, None) + self.gh.subscriptions.assert_called_with('login', -1, None) def test_user_repos(self): args = ('login', None, None, None, -1, None) github3.user_repos('login') - self.gh.iter_user_repos.assert_called_with(*args) + self.gh.user_repos.assert_called_with(*args) From 64d45e5a45c4e316f0ac44f914c5ae52908ac994 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 11:40:52 -0600 Subject: [PATCH 031/972] Fix usage of all_gists and repo_issues --- github3/api.py | 8 ++++---- tests/unit/test_api.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/github3/api.py b/github3/api.py index 27cdad15b..cb53474cb 100644 --- a/github3/api.py +++ b/github3/api.py @@ -213,7 +213,7 @@ def all_gists(number=-1, etag=None): :returns: generator of :class:`Gist ` """ - return gh.all_gists(None, number, etag) + return gh.all_gists(number, etag) def gists_for(username, number=-1, etag=None): @@ -263,9 +263,9 @@ def repo_issues(owner, repository, milestone=None, state=None, assignee=None, """ if owner and repository: - return gh.iter_repo_issues(owner, repository, milestone, state, - assignee, mentioned, labels, sort, - direction, since, number, etag) + return gh.repo_issues(owner, repository, milestone, state, + assignee, mentioned, labels, sort, + direction, since, number, etag) return iter([]) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index b0ab57a61..ed0e74021 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -18,7 +18,7 @@ def test_all_events(self): def test_all_gists(self): github3.all_gists() - self.gh.all_gists.assert_called_once_with(None, -1, None) + self.gh.all_gists.assert_called_once_with(-1, None) def test_all_repos(self): github3.all_repos() From 496af2ad27625d8c256667b55d5b3c90507bf674 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 11:56:01 -0600 Subject: [PATCH 032/972] Fix test reference to iter_user_teams --- tests/integration/test_github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 6fba572af..c98ad63f0 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -156,12 +156,12 @@ def test_iter_followers(self): for u in self.gh.iter_followers('sigmavirus24', number=25): assert isinstance(u, github3.users.User) - def test_iter_user_teams(self): + def test_user_teams(self): """Test the ability to iterate over a user's teams""" self.basic_login() cassette_name = self.cassette_name('iter_user_teams') with self.recorder.use_cassette(cassette_name): - for t in self.gh.iter_user_teams(): + for t in self.gh.user_teams(): assert isinstance(t, github3.orgs.Team) def test_meta(self): From 53f99827708fba04edd33d8fe9070834aa6cd566 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 11:56:44 -0600 Subject: [PATCH 033/972] Fix references to iter_followers --- tests/integration/test_github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index c98ad63f0..65a7dfdc9 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -149,11 +149,11 @@ def test_iter_events(self): for e in self.gh.iter_events(number=25): assert isinstance(e, github3.events.Event) - def test_iter_followers(self): + def test_followers_of(self): """Test the ability to iterate over a user's followers""" cassette_name = self.cassette_name('iter_followers') with self.recorder.use_cassette(cassette_name): - for u in self.gh.iter_followers('sigmavirus24', number=25): + for u in self.gh.followers_of('sigmavirus24', number=25): assert isinstance(u, github3.users.User) def test_user_teams(self): From 33bca0faaa82eaf245fb478d74a122b0b5c35eb1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 12:00:38 -0600 Subject: [PATCH 034/972] Add integration test for GitHub#followers --- tests/cassettes/GitHub_followers_auth.json | 1 + tests/integration/test_github.py | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/cassettes/GitHub_followers_auth.json diff --git a/tests/cassettes/GitHub_followers_auth.json b/tests/cassettes/GitHub_followers_auth.json new file mode 100644 index 000000000..b4b286f6d --- /dev/null +++ b/tests/cassettes/GitHub_followers_auth.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": "", "headers": {"Accept-Encoding": "gzip, deflate, compress", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/user/followers?per_page=100"}, "response": {"body": {"base64_string": "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", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "4997", "x-github-media-type": "github.v3; param=full; 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-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D9:0890:4371B62:52F7C28C", "content-encoding": "gzip", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "server": "GitHub.com", "cache-control": "private, max-age=60, s-maxage=60", "x-ratelimit-limit": "5000", "etag": "\"e5b6ddbd8c3173fee0a8c3b06a4dee7b\"", "access-control-allow-credentials": "true", "date": "Sun, 09 Feb 2014 18:01:49 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1391971387"}, "url": "https://api.github.com/user/followers?per_page=100", "status_code": 200}, "recorded_at": "2014-02-09T18:00:20"}], "recorded_with": "betamax"} \ No newline at end of file diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 65a7dfdc9..d07cb7abf 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -156,6 +156,16 @@ def test_followers_of(self): for u in self.gh.followers_of('sigmavirus24', number=25): assert isinstance(u, github3.users.User) + def test_followers(self): + """ + Test the ability to iterate over an authenticated user's followers. + """ + self.basic_login() + cassette_name = self.cassette_name('followers_auth') + with self.recorder.use_cassette(cassette_name): + for u in self.gh.followers(): + assert isinstance(u, github3.users.User) + def test_user_teams(self): """Test the ability to iterate over a user's teams""" self.basic_login() From 3236205d97e4c1d470fb16618f1c7b238df241cb Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 12:17:50 -0600 Subject: [PATCH 035/972] Fix reference to GitHub#iter_events --- tests/integration/test_github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index d07cb7abf..9cc31fd2a 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -142,11 +142,11 @@ def test_iter_all_users(self): for u in self.gh.iter_all_users(number=25): assert isinstance(u, github3.users.User) - def test_iter_events(self): + def test_all_events(self): """Test the ability to iterate over all public events""" cassette_name = self.cassette_name('iter_events') with self.recorder.use_cassette(cassette_name): - for e in self.gh.iter_events(number=25): + for e in self.gh.all_events(number=25): assert isinstance(e, github3.events.Event) def test_followers_of(self): From 5b18133c4c54e58bfb45a20865afa6988c4167d8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 12:18:29 -0600 Subject: [PATCH 036/972] Fix reference to GitHub#iter_all_repos --- tests/integration/test_github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 9cc31fd2a..1e8806a4e 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -128,11 +128,11 @@ def test_issue(self): assert isinstance(i, github3.issues.Issue) - def test_iter_all_repos(self): + def test_all_repos(self): """Test the ability to iterate over all of the repositories""" cassette_name = self.cassette_name('iter_all_repos') with self.recorder.use_cassette(cassette_name): - for r in self.gh.iter_all_repos(number=25): + for r in self.gh.all_repos(number=25): assert isinstance(r, github3.repos.repo.Repository) def test_iter_all_users(self): From 2b92ca47fa1e4f0d6328d858e0c22eeda2b3adfb Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 12:18:53 -0600 Subject: [PATCH 037/972] Fix reference to GitHub#iter_all_users --- tests/integration/test_github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 1e8806a4e..aabd96a1c 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -135,11 +135,11 @@ def test_all_repos(self): for r in self.gh.all_repos(number=25): assert isinstance(r, github3.repos.repo.Repository) - def test_iter_all_users(self): + def test_all_users(self): """Test the ability to iterate over all of the users""" cassette_name = self.cassette_name('iter_all_users') with self.recorder.use_cassette(cassette_name): - for u in self.gh.iter_all_users(number=25): + for u in self.gh.all_users(number=25): assert isinstance(u, github3.users.User) def test_all_events(self): From 346eac248e39a9497fcc0fe9dfc8fe52fcb73ec5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 14:40:07 -0600 Subject: [PATCH 038/972] Remove old useless test --- tests/test_github.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 3a9db978a..116b163e7 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -495,23 +495,6 @@ def test_iter_repos(self): next(self.g.iter_repos('all', direction='desc')) self.mock_assertions() - def test_iter_user_repos(self): - self.response('repo', _iter=True) - self.get('https://api.github.com/users/sigmavirus24/repos') - self.conf.update(params={'type': 'all', 'direction': 'desc', - 'per_page': 100}) - - next(self.g.iter_user_repos('sigmavirus24', 'all', direction='desc')) - self.mock_assertions() - - self.conf.update(params={'sort': 'created', 'per_page': 100}) - self.get('https://api.github.com/users/sigmavirus24/repos') - - assert isinstance(next(self.g.iter_user_repos('sigmavirus24', - sort="created")), - github3.repos.Repository) - self.mock_assertions() - def test_iter_repos_sort(self): self.response('repo', _iter=True) self.conf.update(params={'sort': 'created', 'per_page': 100}) From d8a1d2599e39c947b9c40b8fa26589aafb1c4ccf Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 9 Feb 2014 14:41:47 -0600 Subject: [PATCH 039/972] Add new Unit Iterator Helper Add tests around iterable methods on GitHub --- tests/unit/helper.py | 37 ++++++++++++++++++++++++++ tests/unit/test_github.py | 55 ++++++++++++++++++--------------------- 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index cab367351..dbb15e869 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -53,3 +53,40 @@ def setUp(self): # we can assert things about the call that will be attempted to the # internet self.described_class._build_url = build_url + + +class UnitIteratorHelper(UnitHelper): + def create_session_mock(self, *args): + # Retrieve a mocked session object + session = super(UnitIteratorHelper, self).create_mocked_session(*args) + # Initialize a NullObject + null = github3.structs.NullObject() + # Set it as the return value for every method + session.delete.return_value = null + session.get.return_value = null + session.patch.return_value = null + session.post.return_value = null + session.put.return_value = null + return session + + def get_next(self, iterator): + try: + next(iterator) + except StopIteration: + pass + + def patch_get_json(self): + """Patch a GitHubIterator's _get_json method""" + self.get_json_mock = mock.patch.object( + github3.structs.GitHubIterator, '_get_json' + ) + self.patched_get_json = self.get_json_mock.start() + self.patched_get_json.return_value = [] + + def setUp(self): + super(UnitIteratorHelper, self).setUp() + self.patch_get_json() + + def tearDown(self): + super(UnitIteratorHelper, self).tearDown() + self.get_json_mock.stop() diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 97645a8f4..9e4a5844e 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -1,6 +1,10 @@ from github3.github import GitHub -from .helper import UnitHelper +from .helper import UnitHelper, UnitIteratorHelper + + +def url_for(path=''): + return 'https://api.github.com/' + path.strip('/') class TestGitHub(UnitHelper): @@ -16,40 +20,33 @@ def test_can_login_without_two_factor_callback(self): self.instance.login(token='token') -class TestGitHubAuthorizations(UnitHelper): +class TestGitHubIterators(UnitIteratorHelper): described_class = GitHub example_data = None - def create_session_mock(self, *args): - session = super(TestGitHubAuthorizations, - self).create_session_mock(*args) - session.retrieve_client_credentials.return_value = ('id', 'secret') - return session + def test_user_repos(self): + """Test that one can iterate over a user's repositories.""" + i = self.instance.user_repos('sigmavirus24') - def test_revoke_authorization(self): - """Test that GitHub#revoke_authorization calls the expected methods. + # Get the next item from the iterator + self.get_next(i) - It should use the session's delete and temporary_basic_auth methods. - """ - self.instance.revoke_authorization('access_token') - self.session.delete.assert_called_once_with( - 'https://api.github.com/applications/id/tokens/access_token', - params={'client_id': None, 'client_secret': None} + self.session.get.assert_called_once_with( + url_for('users/sigmavirus24/repos'), + params={'per_page': 100}, + headers={} ) - self.session.temporary_basic_auth.assert_called_once_with( - 'id', 'secret' - ) - - def test_revoke_authorizations(self): - """Test that GitHub#revoke_authorizations calls the expected methods. - It should use the session's delete and temporary_basic_auth methods. + def test_user_repos_with_type(self): """ - self.instance.revoke_authorizations() - self.session.delete.assert_called_once_with( - 'https://api.github.com/applications/id/tokens', - params={'client_id': None, 'client_secret': None} - ) - self.session.temporary_basic_auth.assert_called_once_with( - 'id', 'secret' + Test that one can iterate over a user's repositories with a type. + """ + i = self.instance.user_repos('sigmavirus24', 'all') + + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users/sigmavirus24/repos'), + params={'per_page': 100, 'type': 'all'}, + headers={} ) From fb2156cc362988482decd3afe8179e4fda9b0ea5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 10 Feb 2014 07:33:39 -0600 Subject: [PATCH 040/972] Test that NullObject's can be coerced to ints We expect int(NullObject()) to be equal to 0 --- tests/unit/test_structs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit/test_structs.py b/tests/unit/test_structs.py index 364294f03..193330913 100644 --- a/tests/unit/test_structs.py +++ b/tests/unit/test_structs.py @@ -94,3 +94,6 @@ def test_turns_into_unicode(self): def test_instances_are_falsey(self): if self.instance: pytest.fail() + + def test_instances_can_be_coerced_to_zero(self): + assert int(self.instance) == 0 From 4ef95ee0785a999c0d86e89d64c1a27d7f9dd0e7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 10 Feb 2014 07:34:29 -0600 Subject: [PATCH 041/972] Provide way to coerce NullObject's to ints --- github3/structs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/github3/structs.py b/github3/structs.py index 36d881191..d5044ac8e 100644 --- a/github3/structs.py +++ b/github3/structs.py @@ -147,6 +147,9 @@ class NullObject(object): def __init__(self, initializer=None): self.__dict__['initializer'] = initializer + def __int__(self): + return 0 + def __bool__(self): return False From f0cc500d951a02b0d450935f31d86b8e2b54207f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 13:34:51 -0600 Subject: [PATCH 042/972] Fix up for PEP8 --- github3/github.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/github3/github.py b/github3/github.py index 8f282088a..ddbff026a 100644 --- a/github3/github.py +++ b/github3/github.py @@ -549,8 +549,9 @@ def notifications(self, all=False, participating=False, number=-1, return self._iter(int(number), url, Thread, params, etag=etag) @requires_auth - def organization_issues(self, name, filter='', state='', labels='', sort='', - direction='', since=None, number=-1, etag=None): + def organization_issues(self, name, filter='', state='', labels='', + sort='', direction='', since=None, number=-1, + etag=None): """Iterate over the organnization's issues if the authenticated user belongs to it. From 26232c8d25657959f1bbb94e41506ef4a1e16a5a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 13:35:42 -0600 Subject: [PATCH 043/972] Add per_page param to user_issues - Convert old test to new tests --- github3/github.py | 9 +++++---- tests/test_github.py | 21 -------------------- tests/unit/test_github.py | 42 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/github3/github.py b/github3/github.py index ddbff026a..e9e5f085c 100644 --- a/github3/github.py +++ b/github3/github.py @@ -620,14 +620,14 @@ def issues(self, filter='', state='', labels='', sort='', direction='', @requires_auth def user_issues(self, filter='', state='', labels='', sort='', - direction='', since=None, number=-1, etag=None): + direction='', since=None, per_page=None, number=-1, + etag=None): """List only the authenticated user's issues. Will not list organization's issues - .. versionchanged:: 0.9.0 + .. versionchanged:: 1.0 - - The ``state`` parameter now accepts 'all' in addition to 'open' - and 'closed'. + ``per_page`` parameter added before ``number`` :param str filter: accepted values: ('assigned', 'created', 'mentioned', 'subscribed') @@ -653,6 +653,7 @@ def user_issues(self, filter='', state='', labels='', sort='', url = self._build_url('user', 'issues') # issue_params will handle the since parameter params = issue_params(filter, state, labels, sort, direction, since) + params.update(per_page=per_page) return self._iter(int(number), url, Issue, params, etag) def repo_issues(self, owner, repository, milestone=None, diff --git a/tests/test_github.py b/tests/test_github.py index 116b163e7..9347caa34 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -413,27 +413,6 @@ def test_iter_issues(self): github3.issues.Issue) self.mock_assertions() - def test_iter_user_issues(self): - self.response('issue', _iter=True) - self.get('https://api.github.com/user/issues') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_user_issues) - - self.login() - assert isinstance(next(self.g.iter_user_issues()), - github3.issues.Issue) - self.mock_assertions() - - params = {'filter': 'assigned', 'state': 'closed', 'labels': 'bug', - 'sort': 'created', 'direction': 'asc', - 'since': '2012-05-20T23:10:27Z'} - request_params = merge(params, per_page=100) - self.conf.update(params=request_params) - assert isinstance(next(self.g.iter_user_issues(**params)), - github3.issues.Issue) - self.mock_assertions() - def test_iter_repo_issues(self): self.response('issue', _iter=True) self.get('https://api.github.com/repos/sigmavirus24/github3.py/' diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 9e4a5844e..af096c346 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -1,3 +1,6 @@ +import pytest + +from github3 import GitHubError from github3.github import GitHub from .helper import UnitHelper, UnitIteratorHelper @@ -24,6 +27,45 @@ class TestGitHubIterators(UnitIteratorHelper): described_class = GitHub example_data = None + def test_user_issues(self): + """Test that one can iterate over a user's issues.""" + self.instance.login('test', 'test') + i = self.instance.user_issues() + # Get the next item from the iterator + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/issues'), + params={'per_page': 100}, + headers={} + ) + + @pytest.xfail + def test_user_issues_requires_auth(self): + """ + Test that one must authenticate to interate over a user's issues. + """ + with pytest.raises(GitHubError): + self.instance.user_issues() + + def test_user_issues_with_parameters(self): + """Test that one may pass parameters to GitHub#user_issues.""" + # Set up the parameters to be sent + params = {'filter': 'assigned', 'state': 'closed', 'labels': 'bug', + 'sort': 'created', 'direction': 'asc', + 'since': '2012-05-20T23:10:27Z', 'per_page': 25} + + self.instance.login('test', 'test') + # Make the call with the paramters + i = self.instance.user_issues(**params) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/issues'), + params=params, + headers={} + ) + def test_user_repos(self): """Test that one can iterate over a user's repositories.""" i = self.instance.user_repos('sigmavirus24') From 718f1747f9a9086117338338e646ea952bc6ca97 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 13:35:55 -0600 Subject: [PATCH 044/972] Fix reference to iter_user_repos --- github3/github.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github3/github.py b/github3/github.py index e9e5f085c..8c42831ac 100644 --- a/github3/github.py +++ b/github3/github.py @@ -737,7 +737,7 @@ def repos(self, type=None, sort=None, direction=None, number=-1, """List public repositories for the authenticated user. .. versionchanged:: 0.6 - Removed the login parameter for correctness. Use iter_user_repos + Removed the login parameter for correctness. Use user_repos instead :param str type: (optional), accepted values: From 4718a2e39fdccae1cd254c195bced8f5a3849fb0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 13:36:26 -0600 Subject: [PATCH 045/972] Try to set auth to None on MockedSession --- github3/session.py | 2 ++ tests/unit/helper.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/github3/session.py b/github3/session.py index c851d6097..ef05e8dc1 100644 --- a/github3/session.py +++ b/github3/session.py @@ -18,6 +18,8 @@ def requires_2fa(response): class GitHubSession(requests.Session): + auth = None + def __init__(self): super(GitHubSession, self).__init__() self.headers.update({ diff --git a/tests/unit/helper.py b/tests/unit/helper.py index dbb15e869..09253d85f 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -19,7 +19,8 @@ class UnitHelper(unittest.TestCase): example_data = {} def create_mocked_session(self): - MockedSession = mock.create_autospec(github3.session.GitHubSession) + MockedSession = mock.create_autospec(github3.session.GitHubSession, + auth=None) return MockedSession() def create_session_mock(self, *args): @@ -34,6 +35,7 @@ def create_session_mock(self, *args): session.patch.return_value = None session.post.return_value = None session.put.return_value = None + session.auth = None return session def create_instance_of_described_class(self): From 897e1a294d0249b71afd67158657e0b6181764b2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 13:50:05 -0600 Subject: [PATCH 046/972] Add a has_auth predicate to GitHubSession --- github3/session.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/github3/session.py b/github3/session.py index ef05e8dc1..c3ecd4d64 100644 --- a/github3/session.py +++ b/github3/session.py @@ -69,6 +69,9 @@ def handle_two_factor_auth(self, args, kwargs): kwargs.update(headers=headers) return super(GitHubSession, self).request(*args, **kwargs) + def has_auth(self): + return (self.auth or self.headers.get('Authorization')) + def oauth2_auth(self, client_id, client_secret): """Use OAuth2 for authentication. From 0cf820f2986b671b536bb13b11340a50c7def1dd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 13:50:48 -0600 Subject: [PATCH 047/972] Interim mocking solution Mock doesn't pick up attributes defined during `__init__` so it doesn't have `headers` or `auth`. `mock.create_autospec` does not let you set these up either so you need to work around that. :headdesk: --- tests/unit/helper.py | 6 ++---- tests/unit/test_github.py | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index 09253d85f..c742470f5 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -19,9 +19,8 @@ class UnitHelper(unittest.TestCase): example_data = {} def create_mocked_session(self): - MockedSession = mock.create_autospec(github3.session.GitHubSession, - auth=None) - return MockedSession() + return mock.NonCallableMagicMock(auth=None, headers={}, + spec=github3.session.GitHubSession) def create_session_mock(self, *args): session = self.create_mocked_session() @@ -35,7 +34,6 @@ def create_session_mock(self, *args): session.patch.return_value = None session.post.return_value = None session.put.return_value = None - session.auth = None return session def create_instance_of_described_class(self): diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index af096c346..f162b1206 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -29,7 +29,7 @@ class TestGitHubIterators(UnitIteratorHelper): def test_user_issues(self): """Test that one can iterate over a user's issues.""" - self.instance.login('test', 'test') + self.session.auth = ('test', 'test') i = self.instance.user_issues() # Get the next item from the iterator self.get_next(i) @@ -40,7 +40,6 @@ def test_user_issues(self): headers={} ) - @pytest.xfail def test_user_issues_requires_auth(self): """ Test that one must authenticate to interate over a user's issues. @@ -55,7 +54,7 @@ def test_user_issues_with_parameters(self): 'sort': 'created', 'direction': 'asc', 'since': '2012-05-20T23:10:27Z', 'per_page': 25} - self.instance.login('test', 'test') + self.session.auth = ('test', 'test') # Make the call with the paramters i = self.instance.user_issues(**params) self.get_next(i) From be323709687be0ecb0e499196ea037065df5a1ae Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 13:56:17 -0600 Subject: [PATCH 048/972] Much better solution to testing protected methods --- github3/decorators.py | 3 +-- tests/unit/helper.py | 5 +++-- tests/unit/test_github.py | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/github3/decorators.py b/github3/decorators.py index 01f396bdb..de6b2746f 100644 --- a/github3/decorators.py +++ b/github3/decorators.py @@ -31,8 +31,7 @@ def requires_auth(func): def auth_wrapper(self, *args, **kwargs): auth = False if hasattr(self, '_session'): - auth = (self._session.auth or - self._session.headers.get('Authorization')) + auth = self._session.has_auth() if auth: return func(self, *args, **kwargs) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index c742470f5..71bfe0644 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -19,8 +19,8 @@ class UnitHelper(unittest.TestCase): example_data = {} def create_mocked_session(self): - return mock.NonCallableMagicMock(auth=None, headers={}, - spec=github3.session.GitHubSession) + MockedSession = mock.create_autospec(github3.session.GitHubSession) + return MockedSession() def create_session_mock(self, *args): session = self.create_mocked_session() @@ -34,6 +34,7 @@ def create_session_mock(self, *args): session.patch.return_value = None session.post.return_value = None session.put.return_value = None + session.has_auth.return_value = True return session def create_instance_of_described_class(self): diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index f162b1206..68b430ee6 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -29,7 +29,6 @@ class TestGitHubIterators(UnitIteratorHelper): def test_user_issues(self): """Test that one can iterate over a user's issues.""" - self.session.auth = ('test', 'test') i = self.instance.user_issues() # Get the next item from the iterator self.get_next(i) @@ -44,6 +43,7 @@ def test_user_issues_requires_auth(self): """ Test that one must authenticate to interate over a user's issues. """ + self.session.has_auth.return_value = False with pytest.raises(GitHubError): self.instance.user_issues() @@ -54,7 +54,6 @@ def test_user_issues_with_parameters(self): 'sort': 'created', 'direction': 'asc', 'since': '2012-05-20T23:10:27Z', 'per_page': 25} - self.session.auth = ('test', 'test') # Make the call with the paramters i = self.instance.user_issues(**params) self.get_next(i) From 77a16ceeb1bedee55f51f3787868aec526aa4d13 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 16:41:34 -0600 Subject: [PATCH 049/972] Update subscriptions - Split into subscriptions_for and subscriptions --- HISTORY.rst | 12 +++++++++--- github3/api.py | 7 +++---- github3/github.py | 25 +++++++++++++++++-------- tests/unit/test_api.py | 6 +++--- tests/unit/test_github.py | 11 +++++++++++ 5 files changed, 43 insertions(+), 18 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index cc9dbb0dc..7a155536d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -25,8 +25,7 @@ Old name New name ``github3.iter_orgs`` ``github3.organizations`` ``github3.iter_user_repos`` ``github3.user_repos`` ``github3.iter_starred`` ``github3.starred`` -``github3.iter_subscriptions`` ``github3.subscriptions`` -``github3.iter_subscriptions`` ``github3.subscriptions`` +``github3.iter_subscriptions`` ``github3.subscriptions_for`` ``GitHub#iter_all_repos`` ``GitHub#all_repos`` ``GitHub#iter_all_users`` ``GitHub#all_users`` ``GitHub#iter_authorizations`` ``GitHub#authorizations`` @@ -44,7 +43,6 @@ Old name New name ``GitHub#iter_orgs`` ``GitHub#organizations`` ``GitHub#iter_repos`` ``GitHub#repos`` ``GitHub#iter_starred`` ``GitHub#starred`` -``GitHub#iter_subscriptions`` ``GitHub#subscriptions`` ``GitHub#iter_user_repos`` ``GitHub#user_repos`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` @@ -66,6 +64,14 @@ Old name New name - ``github3.gists_for`` which iterates over all the public gists of a specific user +- ``GitHub#iter_subscriptions`` was split into two functions: + + - ``GitHub#subscriptions_for`` which iterates over an arbitrary user's + subscriptions + + - ``GitHub#subscriptions`` which iterates over the authenticated user's + subscriptions + - Remove legacy watching API: - ``GitHub#subscribe`` diff --git a/github3/api.py b/github3/api.py index cb53474cb..6585ff73d 100644 --- a/github3/api.py +++ b/github3/api.py @@ -329,11 +329,10 @@ def starred(username, number=-1, etag=None): return gh.starred(username, number, etag) -def subscriptions(username, number=-1, etag=None): +def subscriptions_for(username, number=-1, etag=None): """Iterate over repositories subscribed to by ``username``. - :param str username: (optional), name of user whose subscriptions you want - to see + :param str username: name of user whose subscriptions you want to see :param int number: (optional), number of repositories to return. Default: -1 returns all repositories :param str etag: (optional), ETag from a previous request to the same @@ -341,7 +340,7 @@ def subscriptions(username, number=-1, etag=None): :returns: generator of :class:`Repository ` """ - return gh.subscriptions(username, number, etag) + return gh.subscriptions_for(username, number, etag) def create_gist(description, files): diff --git a/github3/github.py b/github3/github.py index 8c42831ac..950c364fc 100644 --- a/github3/github.py +++ b/github3/github.py @@ -796,24 +796,33 @@ def starred(self, login=None, sort=None, direction=None, number=-1, url = self._build_url('user', 'starred') return self._iter(int(number), url, Repository, params, etag) - def subscriptions(self, login=None, number=-1, etag=None): - """Iterate over repositories subscribed to by ``login`` or the - authenticated user. + @requires_auth + def subscriptions(self, number=-1, etag=None): + """Iterate over repositories subscribed to by the authenticated user. - :param str login: (optional), name of user whose subscriptions you want - to see :param int number: (optional), number of repositories to return. Default: -1 returns all repositories :param str etag: (optional), ETag from a previous request to the same endpoint :returns: generator of :class:`Repository ` """ - if login: - return self.user(login).iter_subscriptions() - url = self._build_url('user', 'subscriptions') return self._iter(int(number), url, Repository, etag=etag) + def subscriptions_for(self, login, number=-1, etag=None): + """Iterate over repositories subscribed to by ``login``. + + :param str login: , name of user whose subscriptions you want + to see + :param int number: (optional), number of repositories to return. + Default: -1 returns all repositories + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Repository ` + """ + url = self._build_url('users', str(login), 'subscriptions') + return self._iter(int(number), url, Repository, etag=etag) + def user_repos(self, login, type=None, sort=None, direction=None, number=-1, etag=None): """List public repositories for the specified ``login``. diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index ed0e74021..b5192c0db 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -91,9 +91,9 @@ def test_starred(self): github3.starred('login') self.gh.starred.assert_called_with('login', -1, None) - def test_subcriptions(self): - github3.subscriptions('login') - self.gh.subscriptions.assert_called_with('login', -1, None) + def test_subcriptions_for(self): + github3.subscriptions_for('login') + self.gh.subscriptions_for.assert_called_with('login', -1, None) def test_user_repos(self): args = ('login', None, None, None, -1, None) diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 68b430ee6..61c04e797 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -27,6 +27,17 @@ class TestGitHubIterators(UnitIteratorHelper): described_class = GitHub example_data = None + def test_subscriptions(self): + """Show that one can iterate over a user's subscriptions.""" + i = self.instance.subscriptions() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user', 'subscriptions'), + params={'per_page': 100}, + headers={} + ) + def test_user_issues(self): """Test that one can iterate over a user's issues.""" i = self.instance.user_issues() From 631147b4beb7ce12e15252761412169fb48f82ab Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 16:45:11 -0600 Subject: [PATCH 050/972] Update all_gists - Split into gists and public_gists --- HISTORY.rst | 8 +++++--- github3/api.py | 4 ++-- github3/github.py | 23 +++++++++++++++++++++-- tests/unit/test_api.py | 6 +++--- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 7a155536d..5d9125060 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -56,14 +56,16 @@ Old name New name - ``github3.enterprise_login`` allows GitHub Enterprise users to log into their service. -- ``github3.iter_gists`` was split into two functions: +- ``GitHub#iter_gists`` was split into two functions: - - ``github3.all_gists`` which iterates over all of the public gists on + - ``GitHub#public_gists`` which iterates over all of the public gists on GitHub - - ``github3.gists_for`` which iterates over all the public gists of a + - ``GitHub#gists_for`` which iterates over all the public gists of a specific user + - ``GitHub#gists`` which iterates over the authenticated users gists + - ``GitHub#iter_subscriptions`` was split into two functions: - ``GitHub#subscriptions_for`` which iterates over an arbitrary user's diff --git a/github3/api.py b/github3/api.py index 6585ff73d..60ccfce0f 100644 --- a/github3/api.py +++ b/github3/api.py @@ -199,7 +199,7 @@ def followed_by(username, number=-1, etag=None): return gh.followed_by(username, number, etag) if username else [] -def all_gists(number=-1, etag=None): +def public_gists(number=-1, etag=None): """Iterate over public gists. .. versionadded:: 1.0 @@ -213,7 +213,7 @@ def all_gists(number=-1, etag=None): :returns: generator of :class:`Gist ` """ - return gh.all_gists(number, etag) + return gh.public_gists(number, etag) def gists_for(username, number=-1, etag=None): diff --git a/github3/github.py b/github3/github.py index 950c364fc..113ae9049 100644 --- a/github3/github.py +++ b/github3/github.py @@ -500,8 +500,10 @@ def followed_by(self, login, number=-1, etag=None): def following(self, number=-1, etag=None): return self._iter_follow('following', int(number), etag=etag) - def all_gists(self, number=-1, etag=None): - """Retrieve all gists and iterate over them. + def public_gists(self, number=-1, etag=None): + """Retrieve all public gists and iterate over them. + + .. versionadded:: 1.0 :param int number: (optional), number of gists to return. Default: -1 returns all available gists @@ -509,12 +511,29 @@ def all_gists(self, number=-1, etag=None): endpoint :returns: generator of :class:`Gist `\ s """ + url = self._build_url('gists', 'public') + return self._iter(int(number), url, Gist, etag=etag) + + @requires_auth + def gists(self, number=-1, etag=None): + """Retrieve the authenticated user's gists. + + .. versionadded:: 1.0 + + :param int number: (optional), number of gists to return. Default: -1, + returns all available gists + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Gist `\ s + """ url = self._build_url('gists') return self._iter(int(number), url, Gist, etag=etag) def gists_for(self, username, number=-1, etag=None): """Iterate over the gists owned by a user. + .. versionadded:: 1.0 + :param str login: login of the user who owns the gists :param int number: (optional), number of gists to return. Default: -1 returns all available gists diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index b5192c0db..654bc71ed 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -16,9 +16,9 @@ def test_all_events(self): github3.all_events() self.gh.all_events.assert_called_once_with(-1, None) - def test_all_gists(self): - github3.all_gists() - self.gh.all_gists.assert_called_once_with(-1, None) + def test_public_gists(self): + github3.public_gists() + self.gh.public_gists.assert_called_once_with(-1, None) def test_all_repos(self): github3.all_repos() From 8b667512fa8d7f89644ed5892df2ab10e38cc958 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 14 Feb 2014 16:45:21 -0600 Subject: [PATCH 051/972] Fix up subscriptions tests --- tests/test_github.py | 18 ------------------ tests/unit/test_github.py | 17 +++++++++++++++-- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 9347caa34..0c5ef56d0 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -501,24 +501,6 @@ def test_iter_starred(self): github3.repos.Repository) self.mock_assertions() - def test_iter_subscriptions(self): - self.response('repo', _iter=True) - self.get('https://api.github.com/user/subscriptions') - self.conf.update(params={'per_page': 100}) - - self.login() - assert isinstance(next(self.g.iter_subscriptions()), - github3.repos.Repository) - self.mock_assertions() - - with mock.patch.object(github3.github.GitHub, 'user') as user: - user.return_value = github3.users.User(load('user')) - self.get('https://api.github.com/users/sigmavirus24/' - 'subscriptions') - assert isinstance(next(self.g.iter_subscriptions('sigmavirus24')), - github3.repos.Repository) - self.mock_assertions() - def test_login(self): self.g.login('user', 'password') assert self.g._session.auth == ('user', 'password') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 61c04e797..1bd1bd0c4 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -28,12 +28,25 @@ class TestGitHubIterators(UnitIteratorHelper): example_data = None def test_subscriptions(self): - """Show that one can iterate over a user's subscriptions.""" + """ + Show that one can iterate over an authenticated user's subscriptions. + """ i = self.instance.subscriptions() self.get_next(i) self.session.get.assert_called_once_with( - url_for('user', 'subscriptions'), + url_for('user/subscriptions'), + params={'per_page': 100}, + headers={} + ) + + def test_subscriptions_for(self): + """Show that one can iterate over a user's subscriptions.""" + i = self.instance.subscriptions_for('sigmavirus24') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users/sigmavirus24/subscriptions'), params={'per_page': 100}, headers={} ) From c3a07f54678789ee4990b8a25d981c876e793d6b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 16 Feb 2014 13:21:16 -0600 Subject: [PATCH 052/972] Fix up starred API --- HISTORY.rst | 9 +++++++-- github3/api.py | 4 ++-- github3/github.py | 38 ++++++++++++++++++++++++++++++-------- tests/test_github.py | 17 ----------------- tests/unit/test_api.py | 4 ++-- tests/unit/test_github.py | 30 ++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 31 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 5d9125060..59b6f264c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -24,7 +24,7 @@ Old name New name ``github3.iter_repo_issues`` ``github3.repo_issues`` ``github3.iter_orgs`` ``github3.organizations`` ``github3.iter_user_repos`` ``github3.user_repos`` -``github3.iter_starred`` ``github3.starred`` +``github3.iter_starred`` ``github3.starred_by`` ``github3.iter_subscriptions`` ``github3.subscriptions_for`` ``GitHub#iter_all_repos`` ``GitHub#all_repos`` ``GitHub#iter_all_users`` ``GitHub#all_users`` @@ -42,7 +42,6 @@ Old name New name ``GitHub#iter_keys`` ``GitHub#keys`` ``GitHub#iter_orgs`` ``GitHub#organizations`` ``GitHub#iter_repos`` ``GitHub#repos`` -``GitHub#iter_starred`` ``GitHub#starred`` ``GitHub#iter_user_repos`` ``GitHub#user_repos`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` @@ -74,6 +73,12 @@ Old name New name - ``GitHub#subscriptions`` which iterates over the authenticated user's subscriptions +- ``GitHub#iter_starred`` was split into two functions: + + - ``GitHub#starred_by`` which iterates over an arbitrary user's stars + + - ``GitHub#starred`` which iterates over the authenticated user's stars + - Remove legacy watching API: - ``GitHub#subscribe`` diff --git a/github3/api.py b/github3/api.py index 60ccfce0f..4c122e406 100644 --- a/github3/api.py +++ b/github3/api.py @@ -315,7 +315,7 @@ def user_repos(login, type=None, sort=None, direction=None, number=-1, return iter([]) -def starred(username, number=-1, etag=None): +def starred_by(username, number=-1, etag=None): """Iterate over repositories starred by ``username``. :param str username: (optional), name of user whose stars you want to see @@ -326,7 +326,7 @@ def starred(username, number=-1, etag=None): :returns: generator of :class:`Repository ` """ - return gh.starred(username, number, etag) + return gh.starred_by(username, number, etag) def subscriptions_for(username, number=-1, etag=None): diff --git a/github3/github.py b/github3/github.py index 113ae9049..d52074d66 100644 --- a/github3/github.py +++ b/github3/github.py @@ -787,14 +787,14 @@ def repos(self, type=None, sort=None, direction=None, number=-1, return self._iter(int(number), url, Repository, params, etag) + @requires_auth def starred(self, login=None, sort=None, direction=None, number=-1, etag=None): - """Iterate over repositories starred by ``login`` or the authenticated - user. + """Iterate over repositories starred by the authenticated user. + + .. versionchanged:: 1.0 - .. versionchanged:: 0.5 - Added sort and direction parameters (optional) as per the change in - GitHub's API. + This was split from ``iter_starred`` and requires authentication. :param str login: (optional), name of user whose stars you want to see :param str sort: (optional), either 'created' (when the star was @@ -807,14 +807,36 @@ def starred(self, login=None, sort=None, direction=None, number=-1, endpoint :returns: generator of :class:`Repository ` """ - if login: - return self.user(login).iter_starred(sort, direction) - params = {'sort': sort, 'direction': direction} self._remove_none(params) url = self._build_url('user', 'starred') return self._iter(int(number), url, Repository, params, etag) + def starred_by(self, login, sort=None, direction=None, number=-1, + etag=None): + """Iterate over repositories starred by ``login``. + + .. versionadded:: 1.0 + + This was split from ``iter_starred`` and requires the login + parameter. + + :param str login: name of user whose stars you want to see + :param str sort: (optional), either 'created' (when the star was + created) or 'updated' (when the repository was last pushed to) + :param str direction: (optional), either 'asc' or 'desc'. Default: + 'desc' + :param int number: (optional), number of repositories to return. + Default: -1 returns all repositories + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Repository ` + """ + params = {'sort': sort, 'direction': direction} + self._remove_none(params) + url = self._build_url('users', str(login), 'starred') + return self._iter(int(number), url, Repository, params, etag) + @requires_auth def subscriptions(self, number=-1, etag=None): """Iterate over repositories subscribed to by the authenticated user. diff --git a/tests/test_github.py b/tests/test_github.py index 0c5ef56d0..c4caf8a85 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -484,23 +484,6 @@ def test_iter_repos_sort(self): github3.repos.Repository) self.mock_assertions() - def test_iter_starred(self): - self.response('repo', _iter=True) - self.get('https://api.github.com/user/starred') - self.conf.update(params={'per_page': 100}) - - self.login() - assert isinstance(next(self.g.iter_starred()), - github3.repos.Repository) - self.mock_assertions() - - with mock.patch.object(github3.github.GitHub, 'user') as user: - user.return_value = github3.users.User(load('user')) - self.get('https://api.github.com/users/sigmavirus24/starred') - assert isinstance(next(self.g.iter_starred('sigmavirus24')), - github3.repos.Repository) - self.mock_assertions() - def test_login(self): self.g.login('user', 'password') assert self.g._session.auth == ('user', 'password') diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 654bc71ed..42897223f 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -88,8 +88,8 @@ def test_repo_issues(self): self.gh.repo_issues.assert_called_with(*args) def test_starred(self): - github3.starred('login') - self.gh.starred.assert_called_with('login', -1, None) + github3.starred_by('login') + self.gh.starred_by.assert_called_with('login', -1, None) def test_subcriptions_for(self): github3.subscriptions_for('login') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 1bd1bd0c4..248f5a16d 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -27,6 +27,36 @@ class TestGitHubIterators(UnitIteratorHelper): described_class = GitHub example_data = None + def test_starred(self): + """ + Show that one can iterate over an authenticated user's stars. + """ + i = self.instance.starred() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/starred'), + params={'per_page': 100}, + headers={} + ) + + def test_starred_requires_auth(self): + """Show that one needs to authenticate to use #starred.""" + self.session.has_auth.return_value = False + with pytest.raises(GitHubError): + self.instance.starred() + + def test_starred_by(self): + """Show that one can iterate over a user's stars.""" + i = self.instance.starred_by('sigmavirus24') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users/sigmavirus24/starred'), + params={'per_page': 100}, + headers={} + ) + def test_subscriptions(self): """ Show that one can iterate over an authenticated user's subscriptions. From 63d444d7030c69b03918ae3d796d9fe52dba28ca Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 16:41:25 -0500 Subject: [PATCH 053/972] Migrate old iter_all_repos unit tests --- tests/test_github.py | 22 ---------------------- tests/unit/test_github.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index c4caf8a85..b50837a9b 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,28 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_all_repos(self): - self.response('repo', _iter=True) - self.get('https://api.github.com/repositories') - self.conf.update(params={'per_page': 100}) - - repo = next(self.g.iter_all_repos()) - assert isinstance(repo, github3.repos.Repository) - self.mock_assertions() - - self.response('repo', _iter=True) - self.get('https://api.github.com/repositories') - self.conf.update(params={'since': 100000, 'per_page': 100}) - repo = next(self.g.iter_all_repos(since=100000)) - assert isinstance(repo, github3.repos.Repository) - assert(repo.id > 100000) - self.mock_assertions() - - repo = next(self.g.iter_all_repos(per_page=100)) - self.conf.update(params={'per_page': 100}) - assert isinstance(repo, github3.repos.Repository) - self.mock_assertions() - def test_iter_all_users(self): self.response('user', _iter=True) self.get('https://api.github.com/users') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 248f5a16d..9edcbb0fd 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -27,6 +27,40 @@ class TestGitHubIterators(UnitIteratorHelper): described_class = GitHub example_data = None + def test_all_repos(self): + """Show that one can iterate over all repositories.""" + i = self.instance.all_repos() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('repositories'), + params={'per_page': 100}, + headers={} + ) + + def test_all_repos_per_page(self): + """Show that one can iterate over all repositories with per_page.""" + i = self.instance.all_repos(per_page=25) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('repositories'), + params={'per_page': 25}, + headers={} + ) + + def test_all_repos_since(self): + """Show that one can limit the repositories returned.""" + since = 100000 + i = self.instance.all_repos(since=since) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('repositories'), + params={'per_page': 100, 'since': since}, + headers={} + ) + def test_starred(self): """ Show that one can iterate over an authenticated user's stars. From 99811b4ddb47624b8c3377264c2498b463d8a9b8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 17:04:58 -0500 Subject: [PATCH 054/972] Add since to all_users Update all_users tests --- github3/github.py | 11 ++++++++--- tests/test_github.py | 14 -------------- tests/unit/test_github.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/github3/github.py b/github3/github.py index d52074d66..4bb960f31 100644 --- a/github3/github.py +++ b/github3/github.py @@ -411,19 +411,24 @@ def all_repos(self, number=-1, since=None, etag=None, per_page=None): params={'since': since, 'per_page': per_page}, etag=etag) - def all_users(self, number=-1, etag=None, per_page=None): + def all_users(self, number=-1, etag=None, per_page=None, since=None): """Iterate over every user in the order they signed up for GitHub. + .. versionchanged:: 1.0.0 + + Inserted the ``since`` parameter after the ``number`` parameter. + :param int number: (optional), number of users to return. Default: -1, returns all of them + :param int since: (optional), ID of the last user that you've seen. :param str etag: (optional), ETag from a previous request to the same endpoint :param int per_page: (optional), number of users to list per request :returns: generator of :class:`User ` """ url = self._build_url('users') - return self._iter(int(number), url, User, - params={'per_page': per_page}, etag=etag) + return self._iter(int(number), url, User, etag=etag, + params={'per_page': per_page, 'since': since}) @requires_basic_auth def authorizations(self, number=-1, etag=None): diff --git a/tests/test_github.py b/tests/test_github.py index b50837a9b..3c347625d 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,20 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_all_users(self): - self.response('user', _iter=True) - self.get('https://api.github.com/users') - self.conf.update(params={'per_page': 100}) - - repo = next(self.g.iter_all_users()) - assert isinstance(repo, github3.users.User) - self.mock_assertions() - - repo = next(self.g.iter_all_users(per_page=100)) - self.conf.update(params={'per_page': 100}) - assert isinstance(repo, github3.users.User) - self.mock_assertions() - def test_iter_authorizations(self): self.response('authorization', _iter=True) self.get('https://api.github.com/authorizations') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 9edcbb0fd..da6a66483 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -61,6 +61,40 @@ def test_all_repos_since(self): headers={} ) + def test_all_users(self): + """Show that one can iterate over all users.""" + i = self.instance.all_users() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users'), + params={'per_page': 100}, + headers={} + ) + + def test_all_users_per_page(self): + """Show that one can iterate over all users with per_page.""" + i = self.instance.all_users(per_page=25) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users'), + params={'per_page': 25}, + headers={} + ) + + def test_all_users_since(self): + """Show that one can limit the users returned.""" + since = 100000 + i = self.instance.all_users(since=since) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users'), + params={'per_page': 100, 'since': since}, + headers={} + ) + def test_starred(self): """ Show that one can iterate over an authenticated user's stars. From 86d13fee434f0c77c9d04d218bfb5f9b4b6306ab Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 17:16:57 -0500 Subject: [PATCH 055/972] Move iter_authorizations tests --- tests/test_github.py | 13 ------------- tests/unit/test_github.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 3c347625d..10c15a699 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,19 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_authorizations(self): - self.response('authorization', _iter=True) - self.get('https://api.github.com/authorizations') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_authorizations) - assert self.request.called is False - - self.login() - auth = next(self.g.iter_authorizations()) - assert isinstance(auth, github3.auths.Authorization) - self.mock_assertions() - def test_iter_emails(self): self.response('emails', _iter=True) self.get('https://api.github.com/user/emails') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index da6a66483..627deeaa6 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -95,6 +95,25 @@ def test_all_users_since(self): headers={} ) + def test_authorizations(self): + """ + Show that an authenticated user can iterate over their authorizations. + """ + i = self.instance.authorizations() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('authorizations'), + params={'per_page': 100}, + headers={} + ) + + def test_authorizations_requires_auth(self): + """Show that one needs to authenticate to use #authorizations.""" + self.session.auth = None + with pytest.raises(GitHubError): + self.instance.authorizations() + def test_starred(self): """ Show that one can iterate over an authenticated user's stars. From 5891a4cd6d323d0a0db9aea0d70c1b3bf6155ee8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 17:28:27 -0500 Subject: [PATCH 056/972] Migrate tests for iter_{emails,events} --- tests/test_github.py | 22 ---------------------- tests/unit/test_github.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 10c15a699..3038055ea 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,28 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_emails(self): - self.response('emails', _iter=True) - self.get('https://api.github.com/user/emails') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_emails) - assert self.request.called is False - - self.login() - email = next(self.g.iter_emails()) - assert email['email'] == 'graffatcolmingov@gmail.com' - self.mock_assertions() - - def test_iter_events(self): - self.response('event', _iter=True) - self.get('https://api.github.com/events') - self.conf.update(params={'per_page': 100}) - - event = next(self.g.iter_events()) - assert isinstance(event, github3.events.Event) - self.mock_assertions() - def test_iter_followers(self): self.response('user', _iter=True) self.get('https://api.github.com/users/sigmavirus24/followers') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 627deeaa6..15e722998 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -27,6 +27,17 @@ class TestGitHubIterators(UnitIteratorHelper): described_class = GitHub example_data = None + def test_all_events(self): + """Show that one can iterate over all public events.""" + i = self.instance.all_events() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('events'), + params={'per_page': 100}, + headers={} + ) + def test_all_repos(self): """Show that one can iterate over all repositories.""" i = self.instance.all_repos() @@ -114,6 +125,23 @@ def test_authorizations_requires_auth(self): with pytest.raises(GitHubError): self.instance.authorizations() + def test_emails(self): + """Show that an authenticated user can iterate over their emails.""" + i = self.instance.emails() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/emails'), + params={'per_page': 100}, + headers={} + ) + + def test_emails_require_auth(self): + """Show that one needs to authenticate to use #emails.""" + self.session.has_auth.return_value = False + with pytest.raises(GitHubError): + self.instance.emails() + def test_starred(self): """ Show that one can iterate over an authenticated user's stars. From 0498b47b7e9f9ee422a18dc76bf8a937b4138318 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 17:42:53 -0500 Subject: [PATCH 057/972] Document the split of iter_{followers,following} --- HISTORY.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index 59b6f264c..dc12e7f11 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -55,6 +55,22 @@ Old name New name - ``github3.enterprise_login`` allows GitHub Enterprise users to log into their service. +- ``GitHub#iter_followers`` was split into two functions: + + - ``GitHub#followers_of`` which iterates over all of the followers of a user + whose username you provide + + - ``GitHub#followers`` which iterates over all of the followers of the + authenticated user + +- ``GitHub#iter_following`` was split into two functions: + + - ``GitHub#followed_by`` which iterates over all of the users followed by + the username you provide + + - ``GitHub#following`` which iterates over all of the users followed by the + authenticated user + - ``GitHub#iter_gists`` was split into two functions: - ``GitHub#public_gists`` which iterates over all of the public gists on From 08e3c489a67642c93ea8a951382d901c010c7974 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 17:43:20 -0500 Subject: [PATCH 058/972] Update followers_of, followers, followed_by, following --- github3/github.py | 61 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/github3/github.py b/github3/github.py index 4bb960f31..6635c0776 100644 --- a/github3/github.py +++ b/github3/github.py @@ -67,11 +67,6 @@ def __enter__(self): def __exit__(self, *args): pass - @requires_auth - def _iter_follow(self, follow_path, number, etag): - url = self._build_url('user', follow_path) - return self._iter(number, url, User, etag=etag) - @requires_basic_auth def authorization(self, id_num): """Get information about authorization ``id``. @@ -470,40 +465,72 @@ def all_events(self, number=-1, etag=None): return self._iter(int(number), url, Event, etag=etag) def followers_of(self, login, number=-1, etag=None): - """If login is provided, iterate over a generator of followers of that - login name; otherwise return a generator of followers of the - authenticated user. + """Iterate over followers of ``login``. + + .. versionadded:: 1.0.0 - :param str login: (optional), login of the user to check + This replaces iter_followers('sigmavirus24'). + + :param str login: (required), login of the user to check :param int number: (optional), number of followers to return. Default: -1 returns all followers :param str etag: (optional), ETag from a previous request to the same endpoint :returns: generator of :class:`User `\ s """ - return self.user(login).iter_followers() + url = self._build_url('users', login, 'followers') + return self._iter(int(number), url, User, etag=etag) @requires_auth def followers(self, number=-1, etag=None): - return self._iter_follow('followers', int(number), etag=etag) + """Iterate over followers of the authenticated user. + + .. versionadded:: 1.0.0 + + This replaces iter_followers(). + + :param int number: (optional), number of followers to return. Default: + -1 returns all followers + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`User `\ s + """ + url = self._build_url('user', 'followers') + return self._iter(int(number), url, User, etag=etag) def followed_by(self, login, number=-1, etag=None): - """If login is provided, iterate over a generator of users being - followed by login; otherwise return a generator of people followed by - the authenticated user. + """Iterate over users being followed by ``login``. + + .. versionadded:: 1.0.0 + + This replaces iter_following('sigmavirus24'). - :param str login: (optional), login of the user to check + :param str login: (required), login of the user to check :param int number: (optional), number of people to return. Default: -1 returns all people you follow :param str etag: (optional), ETag from a previous request to the same endpoint :returns: generator of :class:`User `\ s """ - return self.user(login).iter_following() + url = self._build_url('users', login, 'following') + return self._iter(int(number), url, User, etag=etag) @requires_auth def following(self, number=-1, etag=None): - return self._iter_follow('following', int(number), etag=etag) + """Iterate over users the authenticated user is following. + + .. versionadded:: 1.0.0 + + This replaces iter_following(). + + :param int number: (optional), number of people to return. Default: -1 + returns all people you follow + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`User `\ s + """ + url = self._build_url('user', 'following') + return self._iter(int(number), url, User, etag=etag) def public_gists(self, number=-1, etag=None): """Retrieve all public gists and iterate over them. From 26aa5231decd123d2de1eb45763ccd50f5caa482 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 17:45:37 -0500 Subject: [PATCH 059/972] Make HISTORY more accurate --- HISTORY.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index dc12e7f11..e53c0a216 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -31,8 +31,8 @@ Old name New name ``GitHub#iter_authorizations`` ``GitHub#authorizations`` ``GitHub#iter_emails`` ``GitHub#emails`` ``GitHub#iter_events`` ``GitHub#events`` -``GitHub#iter_followers`` ``GitHub#followers`` -``GitHub#iter_following`` ``GitHub#following`` +``GitHub#iter_followers`` ``GitHub#{followers,followers_of}`` +``GitHub#iter_following`` ``GitHub#{following,followed_by}`` ``GitHub#iter_gists`` ``GitHub#gists`` ``GitHub#iter_notifications`` ``GitHub#notifications`` ``GitHub#iter_org_issues`` ``GitHub#organization_issues`` From ffde8067819f6ade6f432ad1f1e8f4e5b9b6b53d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 17:52:37 -0500 Subject: [PATCH 060/972] Migrate test for iter_followers --- tests/test_github.py | 21 --------------------- tests/unit/test_github.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 3038055ea..ff091c1a9 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,27 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_followers(self): - self.response('user', _iter=True) - self.get('https://api.github.com/users/sigmavirus24/followers') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_followers) - - with mock.patch.object(github3.github.GitHub, 'user') as ghuser: - ghuser.return_value = github3.users.User(load('user')) - u = next(self.g.iter_followers('sigmavirus24')) - assert isinstance(u, github3.users.User) - assert self.request.called is True - self.mock_assertions() - - self.login() - v = next(self.g.iter_followers()) - assert isinstance(v, github3.users.User) - self.get('https://api.github.com/user/followers') - assert self.request.called is True - self.mock_assertions() - def test_iter_following(self): self.response('user', _iter=True) self.get('https://api.github.com/users/sigmavirus24/following') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 15e722998..fc4d27f07 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -142,6 +142,36 @@ def test_emails_require_auth(self): with pytest.raises(GitHubError): self.instance.emails() + def test_followers(self): + """ + Show that an authenticated user can iterate over their followers. + """ + i = self.instance.followers() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/followers'), + params={'per_page': 100}, + headers={} + ) + + def test_followers_require_auth(self): + """Show that one needs to authenticate to use #followers.""" + self.session.has_auth.return_value = False + with pytest.raises(GitHubError): + self.instance.followers() + + def test_followers_of(self): + """Show that one can authenticate over the followers of a user.""" + i = self.instance.followers_of('sigmavirus24') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users/sigmavirus24/followers'), + params={'per_page': 100}, + headers={} + ) + def test_starred(self): """ Show that one can iterate over an authenticated user's stars. From 7c52e4e3b1b2ee3d295c737f7a804738b9db4887 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 17:55:15 -0500 Subject: [PATCH 061/972] Migrate test for iter_following --- tests/test_github.py | 20 -------------------- tests/unit/test_github.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index ff091c1a9..cad258814 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,26 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_following(self): - self.response('user', _iter=True) - self.get('https://api.github.com/users/sigmavirus24/following') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_following) - assert self.request.called is False - - with mock.patch.object(github3.github.GitHub, 'user') as ghuser: - ghuser.return_value = github3.users.User(load('user')) - u = next(self.g.iter_following('sigmavirus24')) - assert isinstance(u, github3.users.User) - self.mock_assertions() - - self.login() - v = next(self.g.iter_following()) - assert isinstance(v, github3.users.User) - self.get('https://api.github.com/user/following') - self.mock_assertions() - def test_iter_gists(self): self.response('gist', _iter=True) self.get('https://api.github.com/users/sigmavirus24/gists') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index fc4d27f07..123355af2 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -172,6 +172,39 @@ def test_followers_of(self): headers={} ) + def test_following(self): + """ + Show that an authenticated user can iterate the users they are + following. + """ + i = self.instance.following() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/following'), + params={'per_page': 100}, + headers={} + ) + + def test_following_require_auth(self): + """Show that one needs to authenticate to use #following.""" + self.session.has_auth.return_value = False + with pytest.raises(GitHubError): + self.instance.following() + + def test_followed_by(self): + """ + Show that one can authenticate over the users followed by another. + """ + i = self.instance.followed_by('sigmavirus24') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users/sigmavirus24/following'), + params={'per_page': 100}, + headers={} + ) + def test_starred(self): """ Show that one can iterate over an authenticated user's stars. From 4c28eb972cb6773e4cd2836bc8d1a88892073074 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 18:08:30 -0500 Subject: [PATCH 062/972] Clarify HISTORY of iter_gists --- HISTORY.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index e53c0a216..5107a0630 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,9 +13,9 @@ Breaking Changes - All methods and functions starting with ``iter_`` have been renamed. -============================== ============================== +============================== ======================================== Old name New name -============================== ============================== +============================== ======================================== ``github3.iter_all_repos`` ``github3.all_repos`` ``github3.iter_all_users`` ``github3.all_users`` ``github3.iter_events`` ``github3.all_events`` @@ -33,7 +33,7 @@ Old name New name ``GitHub#iter_events`` ``GitHub#events`` ``GitHub#iter_followers`` ``GitHub#{followers,followers_of}`` ``GitHub#iter_following`` ``GitHub#{following,followed_by}`` -``GitHub#iter_gists`` ``GitHub#gists`` +``GitHub#iter_gists`` ``GitHub#{gists,gists_by,public_gists}`` ``GitHub#iter_notifications`` ``GitHub#notifications`` ``GitHub#iter_org_issues`` ``GitHub#organization_issues`` ``GitHub#iter_issues`` ``GitHub#issues`` @@ -45,7 +45,7 @@ Old name New name ``GitHub#iter_user_repos`` ``GitHub#user_repos`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` -============================== ============================== +============================== ======================================== - ``github3.login`` has been simplified and split into two functions: @@ -71,7 +71,7 @@ Old name New name - ``GitHub#following`` which iterates over all of the users followed by the authenticated user -- ``GitHub#iter_gists`` was split into two functions: +- ``GitHub#iter_gists`` was split into three functions: - ``GitHub#public_gists`` which iterates over all of the public gists on GitHub From 96750f0d14b0b8f19e392ff10267d7b5a93481ea Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 18:08:48 -0500 Subject: [PATCH 063/972] Rename gists_for -> gists_by Migrate iter_gists tests --- github3/github.py | 2 +- tests/test_github.py | 15 --------------- tests/unit/test_github.py | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/github3/github.py b/github3/github.py index 6635c0776..195a60f80 100644 --- a/github3/github.py +++ b/github3/github.py @@ -561,7 +561,7 @@ def gists(self, number=-1, etag=None): url = self._build_url('gists') return self._iter(int(number), url, Gist, etag=etag) - def gists_for(self, username, number=-1, etag=None): + def gists_by(self, username, number=-1, etag=None): """Iterate over the gists owned by a user. .. versionadded:: 1.0 diff --git a/tests/test_github.py b/tests/test_github.py index cad258814..11459b9f9 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,21 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_gists(self): - self.response('gist', _iter=True) - self.get('https://api.github.com/users/sigmavirus24/gists') - self.conf.update(params={'per_page': 100}) - - g = next(self.g.iter_gists('sigmavirus24')) - assert isinstance(g, github3.gists.Gist) - self.mock_assertions() - - self.login() - h = next(self.g.iter_gists()) - assert isinstance(h, github3.gists.Gist) - self.get('https://api.github.com/gists') - self.mock_assertions() - def test_iter_notifications(self): self.response('notification', _iter=True) self.get('https://api.github.com/notifications') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 123355af2..28c045c91 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -205,6 +205,45 @@ def test_followed_by(self): headers={} ) + def test_gists(self): + """Show that an authenticated user can iterate over their gists.""" + i = self.instance.gists() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('gists'), + params={'per_page': 100}, + headers={} + ) + + def test_gists_requires_auth(self): + """Show that one needs to authenticate to use #gists.""" + self.session.has_auth.return_value = False + with pytest.raises(GitHubError): + self.instance.gists() + + def test_gists_by(self): + """Show that an user's gists can be iterated over.""" + i = self.instance.gists_by('sigmavirus24') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users/sigmavirus24/gists'), + params={'per_page': 100}, + headers={} + ) + + def test_public_gists(self): + """Show that all public gists can be iterated over.""" + i = self.instance.public_gists() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('gists/public'), + params={'per_page': 100}, + headers={} + ) + def test_starred(self): """ Show that one can iterate over an authenticated user's stars. From 81a06a848797343f0aa6de94993da3b627ec8f60 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 18:14:25 -0500 Subject: [PATCH 064/972] Rename functional API --- github3/api.py | 6 +++--- tests/unit/test_api.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/github3/api.py b/github3/api.py index 4c122e406..c28805de2 100644 --- a/github3/api.py +++ b/github3/api.py @@ -216,8 +216,8 @@ def public_gists(number=-1, etag=None): return gh.public_gists(number, etag) -def gists_for(username, number=-1, etag=None): - """Iterate over gists for the provided username. +def gists_by(username, number=-1, etag=None): + """Iterate over gists created by the provided username. :param str username: (required), if provided, get the gists for this user instead of the authenticated user. @@ -229,7 +229,7 @@ def gists_for(username, number=-1, etag=None): """ if username: - return gh.gists_for(username, number, etag) + return gh.gists_by(username, number, etag) return iter([]) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 42897223f..1da184710 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -55,9 +55,9 @@ def test_gist(self): github3.gist(gist_id) self.gh.gist.assert_called_once_with(gist_id) - def test_gists_for(self): - github3.gists_for('username') - self.gh.gists_for.assert_called_once_with('username', -1, None) + def test_gists_by(self): + github3.gists_by('username') + self.gh.gists_by.assert_called_once_with('username', -1, None) def test_gitignore_template(self): language = 'Python' From 0d1eb42a47064cd0b3c3c14f40e5385349946fc4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 19:58:17 -0500 Subject: [PATCH 065/972] Fix typo --- github3/github.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github3/github.py b/github3/github.py index 195a60f80..54a8ff48a 100644 --- a/github3/github.py +++ b/github3/github.py @@ -603,7 +603,7 @@ def notifications(self, all=False, participating=False, number=-1, def organization_issues(self, name, filter='', state='', labels='', sort='', direction='', since=None, number=-1, etag=None): - """Iterate over the organnization's issues if the authenticated user + """Iterate over the organization's issues if the authenticated user belongs to it. :param str name: (required), name of the organization From 9958a3944753aa174fa18aee9b6979e44977aba6 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 19:59:04 -0500 Subject: [PATCH 066/972] Migrate test for iter_notifications, iter_org_issues --- tests/test_github.py | 43 ---------------------- tests/unit/test_github.py | 76 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 43 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 11459b9f9..e92466d9f 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,49 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_notifications(self): - self.response('notification', _iter=True) - self.get('https://api.github.com/notifications') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_notifications) - - self.not_called() - self.login() - thread = next(self.g.iter_notifications()) - assert isinstance(thread, github3.notifications.Thread) - self.mock_assertions() - - self.conf.update(params={'all': True, 'per_page': 100}) - next(self.g.iter_notifications(True)) - self.mock_assertions() - - self.conf.update(params={'participating': True, 'per_page': 100}) - next(self.g.iter_notifications(participating=True)) - self.mock_assertions() - - def test_iter_org_issues(self): - self.response('issue', _iter=True) - self.get('https://api.github.com/orgs/github3py/issues') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_org_issues, - 'github3py') - - self.login() - i = next(self.g.iter_org_issues('github3py')) - assert isinstance(i, github3.issues.Issue) - self.mock_assertions() - - params = {'filter': 'assigned', 'state': 'closed', 'labels': 'bug', - 'sort': 'created', 'direction': 'asc', - 'since': '2012-05-20T23:10:27Z'} - request_params = merge(params, per_page=100) - self.conf.update(params=request_params) - j = next(self.g.iter_org_issues('github3py', **params)) - assert isinstance(j, github3.issues.Issue) - self.mock_assertions() - def test_iter_issues(self): self.response('issue', _iter=True) self.get('https://api.github.com/issues') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 28c045c91..f13c20f20 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -233,6 +233,82 @@ def test_gists_by(self): headers={} ) + def test_notifications(self): + """ + Show that an authenticated user can iterate over their notifications. + """ + i = self.instance.notifications() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('notifications'), + params={'per_page': 100}, + headers={}, + ) + + def test_notifications_participating_in(self): + """Show that the user can filter by pariticpating.""" + i = self.instance.notifications(participating=True) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('notifications'), + params={'per_page': 100, 'participating': True}, + headers={} + ) + + def test_notifications_all(self): + """Show that the user can iterate over all of their notifications.""" + i = self.instance.notifications(all=True) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('notifications'), + params={'per_page': 100, 'all': True}, + headers={} + ) + + def test_notifications_requires_auth(self): + """Show that one needs to authenticate to use #gists.""" + self.session.has_auth.return_value = False + with pytest.raises(GitHubError): + self.instance.notifications() + + def test_organization_issues(self): + """Show that one can iterate over an organization's issues.""" + i = self.instance.organization_issues('org') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('orgs/org/issues'), + params={'per_page': 100}, + headers={} + ) + + def test_organization_issues_with_params(self): + """Show that one can pass parameters to #organization_issues.""" + params = {'filter': 'assigned', 'state': 'closed', 'labels': 'bug', + 'sort': 'created', 'direction': 'asc', + 'since': '2012-05-20T23:10:27Z'} + i = self.instance.organization_issues('org', **params) + self.get_next(i) + + p = {'per_page': 100} + p.update(params) + + self.session.get.assert_called_once_with( + url_for('orgs/org/issues'), + params=p, + headers={} + ) + + def test_organization_issues_requires_auth(self): + """Show that one needs to authenticate to use #organization_issues.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.organization_issues('org') + def test_public_gists(self): """Show that all public gists can be iterated over.""" i = self.instance.public_gists() From 4725eb1dbc0ae683715d3f4fc8414e878640070c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 20:36:20 -0500 Subject: [PATCH 067/972] Migrate iter_issues test --- tests/test_github.py | 20 -------------------- tests/unit/test_github.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index e92466d9f..c1022c6ff 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,26 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_issues(self): - self.response('issue', _iter=True) - self.get('https://api.github.com/issues') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_issues) - - self.login() - assert isinstance(next(self.g.iter_issues()), github3.issues.Issue) - self.mock_assertions() - - params = {'filter': 'assigned', 'state': 'closed', 'labels': 'bug', - 'sort': 'created', 'direction': 'asc', - 'since': '2012-05-20T23:10:27Z'} - request_params = merge(params, per_page=100) - self.conf.update(params=request_params) - assert isinstance(next(self.g.iter_issues(**params)), - github3.issues.Issue) - self.mock_assertions() - def test_iter_repo_issues(self): self.response('issue', _iter=True) self.get('https://api.github.com/repos/sigmavirus24/github3.py/' diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index f13c20f20..cc917f74e 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -233,6 +233,40 @@ def test_gists_by(self): headers={} ) + def test_issues(self): + """Show that an authenticated user can iterate over their issues.""" + i = self.instance.issues() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('issues'), + params={'per_page': 100}, + headers={} + ) + + def test_issues_with_params(self): + """Show that issues can be filtered.""" + params = {'filter': 'assigned', 'state': 'closed', 'labels': 'bug', + 'sort': 'created', 'direction': 'asc', + 'since': '2012-05-20T23:10:27Z'} + p = {'per_page': 100} + p.update(params) + + i = self.instance.issues(**params) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('issues'), + params=p, + headers={} + ) + + def test_issues_requires_auth(self): + """Show that one needs to authenticate to use #issues.""" + self.session.has_auth.return_value = False + with pytest.raises(GitHubError): + self.instance.issues() + def test_notifications(self): """ Show that an authenticated user can iterate over their notifications. From e3bb74af3f670d6fe4be0aa7957c00341f862a54 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 21:30:28 -0500 Subject: [PATCH 068/972] Some refactoring for GitHub#repository_issues - Rename repo_issues -> repository_issues - Make parameter filtering in Repository#iter_issues a standalone function. - Reduce the number of API calls in GitHub#repository_issues --- HISTORY.rst | 4 ++-- github3/api.py | 12 +++++------ github3/github.py | 46 ++++++++++++++++++++++-------------------- github3/models.py | 3 ++- github3/repos/repo.py | 31 ++++++++++++++++++++-------- tests/unit/test_api.py | 6 +++--- 6 files changed, 60 insertions(+), 42 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 5107a0630..1acf2e5eb 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -21,7 +21,7 @@ Old name New name ``github3.iter_events`` ``github3.all_events`` ``github3.iter_followers`` ``github3.followers_of`` ``github3.iter_following`` ``github3.followed_by`` -``github3.iter_repo_issues`` ``github3.repo_issues`` +``github3.iter_repo_issues`` ``github3.repository_issues`` ``github3.iter_orgs`` ``github3.organizations`` ``github3.iter_user_repos`` ``github3.user_repos`` ``github3.iter_starred`` ``github3.starred_by`` @@ -38,7 +38,7 @@ Old name New name ``GitHub#iter_org_issues`` ``GitHub#organization_issues`` ``GitHub#iter_issues`` ``GitHub#issues`` ``GitHub#iter_user_issues`` ``GitHub#user_issues`` -``GitHub#iter_repo_issues`` ``GitHub#repo_issues`` +``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` ``GitHub#iter_keys`` ``GitHub#keys`` ``GitHub#iter_orgs`` ``GitHub#organizations`` ``GitHub#iter_repos`` ``GitHub#repos`` diff --git a/github3/api.py b/github3/api.py index c28805de2..6f8c12957 100644 --- a/github3/api.py +++ b/github3/api.py @@ -233,9 +233,9 @@ def gists_by(username, number=-1, etag=None): return iter([]) -def repo_issues(owner, repository, milestone=None, state=None, assignee=None, - mentioned=None, labels=None, sort=None, direction=None, - since=None, number=-1, etag=None): +def repository_issues(owner, repository, milestone=None, state=None, + assignee=None, mentioned=None, labels=None, sort=None, + direction=None, since=None, number=-1, etag=None): """Iterate over issues on owner/repository. :param str owner: login of the owner of the repository @@ -263,9 +263,9 @@ def repo_issues(owner, repository, milestone=None, state=None, assignee=None, """ if owner and repository: - return gh.repo_issues(owner, repository, milestone, state, - assignee, mentioned, labels, sort, - direction, since, number, etag) + return gh.repository_issues(owner, repository, milestone, state, + assignee, mentioned, labels, sort, + direction, since, number, etag) return iter([]) diff --git a/github3/github.py b/github3/github.py index 54a8ff48a..d5549dc64 100644 --- a/github3/github.py +++ b/github3/github.py @@ -8,20 +8,20 @@ """ from __future__ import unicode_literals -from .auths import Authorization -from .decorators import (requires_auth, requires_basic_auth, - requires_app_credentials) -from .events import Event -from .gists import Gist -from .issues import Issue, issue_params -from .models import GitHubCore -from .orgs import Membership, Organization, Team -from .repos import Repository -from .search import (CodeSearchResult, IssueSearchResult, - RepositorySearchResult, UserSearchResult) -from .structs import SearchIterator -from .users import User, Key -from .notifications import Thread +from github3.auths import Authorization +from github3.decorators import (requires_auth, requires_basic_auth, + requires_app_credentials) +from github3.events import Event +from github3.gists import Gist +from github3.issues import Issue, issue_params +from github3.models import GitHubCore +from github3.orgs import Organization, Team +from github3.repos import Repository, repo_issue_params +from github3.search import (CodeSearchResult, IssueSearchResult, + RepositorySearchResult, UserSearchResult) +from github3.structs import SearchIterator +from github3.users import User, Key +from github3.notifications import Thread from uritemplate import URITemplate @@ -707,10 +707,10 @@ def user_issues(self, filter='', state='', labels='', sort='', params.update(per_page=per_page) return self._iter(int(number), url, Issue, params, etag) - def repo_issues(self, owner, repository, milestone=None, - state=None, assignee=None, mentioned=None, - labels=None, sort=None, direction=None, since=None, - number=-1, etag=None): + def repository_issues(self, owner, repository, milestone=None, + state=None, assignee=None, mentioned=None, + labels=None, sort=None, direction=None, since=None, + number=-1, etag=None): """List issues on owner/repository. Only owner and repository are required. @@ -743,10 +743,12 @@ def repo_issues(self, owner, repository, milestone=None, :returns: generator of :class:`Issue `\ s """ if owner and repository: - repo = self.repository(owner, repository) - return repo.iter_issues(milestone, state, assignee, mentioned, - labels, sort, direction, since, number, - etag) + url = self._build_url('repos', owner, repository, 'issues') + + params = repo_issue_params(milestone, state, assignee, mentioned, + labels, sort, direction, since) + return self._iter(int(number), url, Issue, params=params, + etag=etag) return iter([]) @requires_auth diff --git a/github3/models.py b/github3/models.py index bd2daf132..8103a613a 100644 --- a/github3/models.py +++ b/github3/models.py @@ -88,7 +88,8 @@ def __init__(self, json, session=None): def _repr(self): return ''.format(id(self)) - def _remove_none(self, data): + @staticmethod + def _remove_none(data): if not data: return for (k, v) in list(data.items()): diff --git a/github3/repos/repo.py b/github3/repos/repo.py index dabbf9f9f..05622864d 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1370,14 +1370,8 @@ def iter_issues(self, """ url = self._build_url('issues', base_url=self._api) - params = {'assignee': assignee, 'mentioned': mentioned} - if milestone in ('*', 'none') or isinstance(milestone, int): - params['milestone'] = milestone - self._remove_none(params) - params.update( - issue_params(None, state, labels, sort, direction, - since) - ) + params = repo_issue_params(milestone, state, assignee, mentioned, + labels, sort, direction, since) return self._iter(int(number), url, Issue, params, etag) @@ -1901,3 +1895,24 @@ def weekly_commit_count(self): if json.get('Last-Modified'): del json['Last-Modified'] return json + + +def repo_issue_params(milestone=None, + state=None, + assignee=None, + mentioned=None, + labels=None, + sort=None, + direction=None, + since=None, + number=-1, + etag=None): + params = {'assignee': assignee, 'mentioned': mentioned} + if milestone in ('*', 'none') or isinstance(milestone, int): + params['milestone'] = milestone + Repository._remove_none(params) + params.update( + issue_params(None, state, labels, sort, direction, + since) + ) + return params diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 1da184710..f5a1aa254 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -81,11 +81,11 @@ def test_organizations(self): github3.organizations(*args) self.gh.organizations.assert_called_with(*args) - def test_repo_issues(self): + def test_repository_issues(self): args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) - github3.repo_issues(*args) - self.gh.repo_issues.assert_called_with(*args) + github3.repository_issues(*args) + self.gh.repository_issues.assert_called_with(*args) def test_starred(self): github3.starred_by('login') From 8e21a649aa8827d2fb22820286c4786fee07ebbf Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 21:40:07 -0500 Subject: [PATCH 069/972] Migrate tests for iter_repos_issues --- github3/github.py | 2 +- tests/test_github.py | 16 ---------------- tests/unit/test_github.py | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/github3/github.py b/github3/github.py index d5549dc64..337815a8c 100644 --- a/github3/github.py +++ b/github3/github.py @@ -16,7 +16,7 @@ from github3.issues import Issue, issue_params from github3.models import GitHubCore from github3.orgs import Organization, Team -from github3.repos import Repository, repo_issue_params +from github3.repos.repo import Repository, repo_issue_params from github3.search import (CodeSearchResult, IssueSearchResult, RepositorySearchResult, UserSearchResult) from github3.structs import SearchIterator diff --git a/tests/test_github.py b/tests/test_github.py index c1022c6ff..af3cfbed7 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,22 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_repo_issues(self): - self.response('issue', _iter=True) - self.get('https://api.github.com/repos/sigmavirus24/github3.py/' - 'issues') - - with mock.patch.object(github3.GitHub, 'repository') as repo: - repo.return_value = github3.repos.Repository(load('repo'), - self.g) - i = next(self.g.iter_repo_issues('sigmavirus24', 'github3.py')) - - assert isinstance(i, github3.issues.Issue) - self.mock_assertions() - - with self.assertRaises(StopIteration): - next(self.g.iter_repo_issues(None, None)) - def test_iter_keys(self): self.response('key', _iter=True) self.get('https://api.github.com/user/keys') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index cc917f74e..bc70450ae 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -354,6 +354,32 @@ def test_public_gists(self): headers={} ) + def test_repository_issues(self): + """Show that a user can iterate over a repository's issues.""" + i = self.instance.repository_issues('owner', 'repo') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('repos/owner/repo/issues'), + params={'per_page': 100}, + headers={} + ) + + def test_repository_issues_with_params(self): + """Show that #repository_issues accepts multiple parameters.""" + params = {'milestone': 1, 'state': 'all', 'assignee': 'owner', + 'mentioned': 'someone', 'labels': 'bug,high'} + i = self.instance.repository_issues('owner', 'repo', **params) + self.get_next(i) + + params.update(per_page=100) + + self.session.get.assert_called_once_with( + url_for('repos/owner/repo/issues'), + params=params, + headers={} + ) + def test_starred(self): """ Show that one can iterate over an authenticated user's stars. From f45896e607f70b7bf830b16f0646df30a2de8dd0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 4 Jul 2014 21:47:58 -0500 Subject: [PATCH 070/972] Migrate iter_keys test --- tests/test_github.py | 11 ----------- tests/unit/test_github.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index af3cfbed7..584ae09e7 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,17 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_keys(self): - self.response('key', _iter=True) - self.get('https://api.github.com/user/keys') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_keys) - - self.login() - assert isinstance(next(self.g.iter_keys()), github3.users.Key) - self.mock_assertions() - def test_iter_orgs(self): self.response('org', _iter=True) self.get('https://api.github.com/users/login/orgs') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index bc70450ae..d374d2ec9 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -267,6 +267,25 @@ def test_issues_requires_auth(self): with pytest.raises(GitHubError): self.instance.issues() + def test_keys(self): + """ + Show that an authenticated user can iterate over their public keys. + """ + i = self.instance.keys() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/keys'), + params={'per_page': 100}, + headers={} + ) + + def test_keys_requires_auth(self): + """Show that one needs to authenticate to use #keys.""" + self.session.has_auth.return_value = False + with pytest.raises(GitHubError): + self.instance.keys() + def test_notifications(self): """ Show that an authenticated user can iterate over their notifications. From ec5c852009d4435d9b5e4c3982c86e3c8762dd76 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 09:07:14 -0500 Subject: [PATCH 071/972] Split organizations into organizations and organizations_with --- github3/github.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/github3/github.py b/github3/github.py index 337815a8c..b70a7a398 100644 --- a/github3/github.py +++ b/github3/github.py @@ -764,12 +764,13 @@ def keys(self, number=-1, etag=None): url = self._build_url('user', 'keys') return self._iter(int(number), url, Key, etag=etag) + @requires_auth def organizations(self, login=None, number=-1, etag=None): - """Iterate over public organizations for login if provided; otherwise - iterate over public and private organizations for the authenticated - user. + """Iterate over all organizations the authenticated user belongs to. + + This will display both the private memberships and the publicized + memberships. - :param str login: (optional), user whose orgs you wish to list :param int number: (optional), number of organizations to return. Default: -1 returns all available organizations :param str etag: (optional), ETag from a previous request to the same @@ -777,11 +778,25 @@ def organizations(self, login=None, number=-1, etag=None): :returns: generator of :class:`Organization `\ s """ - if login: - url = self._build_url('users', login, 'orgs') - else: - url = self._build_url('user', 'orgs') + url = self._build_url('user', 'orgs') + return self._iter(int(number), url, Organization, etag=etag) + + def organizations_with(self, login, number=-1, etag=None): + """Iterate over organizations with ``login`` as a public member. + + .. versionadded:: 1.0.0 + Replaces ``iter_orgs('sigmavirus24')``. + + :param str login: (optional), user whose orgs you wish to list + :param int number: (optional), number of organizations to return. + Default: -1 returns all available organizations + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`Organization `\ s + """ + url = self._build_url('users', login, 'orgs') return self._iter(int(number), url, Organization, etag=etag) @requires_auth From 32fd039aa8a0480cc8cb956ca8428cf13dd9bf4f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 09:08:54 -0500 Subject: [PATCH 072/972] Update HISTORY with what happened to iter_orgs --- HISTORY.rst | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 1acf2e5eb..4141df8e1 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,3 +1,4 @@ +.. vim: set tw=100 History/Changelog ----------------- @@ -13,16 +14,16 @@ Breaking Changes - All methods and functions starting with ``iter_`` have been renamed. -============================== ======================================== +============================== ============================================== Old name New name -============================== ======================================== +============================== ============================================== ``github3.iter_all_repos`` ``github3.all_repos`` ``github3.iter_all_users`` ``github3.all_users`` ``github3.iter_events`` ``github3.all_events`` ``github3.iter_followers`` ``github3.followers_of`` ``github3.iter_following`` ``github3.followed_by`` ``github3.iter_repo_issues`` ``github3.repository_issues`` -``github3.iter_orgs`` ``github3.organizations`` +``github3.iter_orgs`` ``github3.{organizations,organizations_with}`` ``github3.iter_user_repos`` ``github3.user_repos`` ``github3.iter_starred`` ``github3.starred_by`` ``github3.iter_subscriptions`` ``github3.subscriptions_for`` @@ -45,7 +46,7 @@ Old name New name ``GitHub#iter_user_repos`` ``GitHub#user_repos`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` -============================== ======================================== +============================== ============================================== - ``github3.login`` has been simplified and split into two functions: @@ -81,6 +82,14 @@ Old name New name - ``GitHub#gists`` which iterates over the authenticated users gists +- ``GitHub#iter_orgs`` was split into two functions: + + - ``GitHub#organizations`` which iterates over the authenticated user's + organization memberships + + - ``GitHub#organizations_with`` which iterates over the given user's + organization memberships + - ``GitHub#iter_subscriptions`` was split into two functions: - ``GitHub#subscriptions_for`` which iterates over an arbitrary user's From 17f8ee3b1b6f9a91393bd0b0ce31cb131fee5827 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 09:10:14 -0500 Subject: [PATCH 073/972] Migrate iter_orgs tests --- tests/test_github.py | 13 ------------- tests/unit/test_github.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 584ae09e7..cc6d7e3c6 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,19 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_orgs(self): - self.response('org', _iter=True) - self.get('https://api.github.com/users/login/orgs') - - assert isinstance(next(self.g.iter_orgs('login')), - github3.orgs.Organization) - self.mock_assertions() - - self.get('https://api.github.com/user/orgs') - self.login() - assert isinstance(next(self.g.iter_orgs()), github3.orgs.Organization) - self.mock_assertions() - def test_iter_repos(self): self.response('repo', _iter=True) self.get('https://api.github.com/user/repos') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index d374d2ec9..6e1e233a7 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -362,6 +362,37 @@ def test_organization_issues_requires_auth(self): with pytest.raises(GitHubError): self.instance.organization_issues('org') + def test_organizations(self): + """ + Show that one can iterate over all of the authenticated user's orgs. + """ + i = self.instance.organizations() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/orgs'), + params={'per_page': 100}, + headers={} + ) + + def test_organizations_requires_auth(self): + """Show that one needs to authenticate to use #organizations.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.organizations() + + def test_organizations_with(self): + """Show that one can iterate over all of a user's orgs.""" + i = self.instance.organizations_with('sigmavirus24') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('users/sigmavirus24/orgs'), + params={'per_page': 100}, + headers={} + ) + def test_public_gists(self): """Show that all public gists can be iterated over.""" i = self.instance.public_gists() From 2f983bcc82feddb722bc2cf7045127c9cfee3ea0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 11:37:55 -0500 Subject: [PATCH 074/972] Rename github3.organizations -> organizations_with --- HISTORY.rst | 6 +++--- github3/api.py | 6 +++--- github3/github.py | 10 ++++++---- tests/unit/test_api.py | 6 +++--- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 4141df8e1..afe42649d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -23,7 +23,7 @@ Old name New name ``github3.iter_followers`` ``github3.followers_of`` ``github3.iter_following`` ``github3.followed_by`` ``github3.iter_repo_issues`` ``github3.repository_issues`` -``github3.iter_orgs`` ``github3.{organizations,organizations_with}`` +``github3.iter_orgs`` ``github3.organizations_with`` ``github3.iter_user_repos`` ``github3.user_repos`` ``github3.iter_starred`` ``github3.starred_by`` ``github3.iter_subscriptions`` ``github3.subscriptions_for`` @@ -41,8 +41,8 @@ Old name New name ``GitHub#iter_user_issues`` ``GitHub#user_issues`` ``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` ``GitHub#iter_keys`` ``GitHub#keys`` -``GitHub#iter_orgs`` ``GitHub#organizations`` -``GitHub#iter_repos`` ``GitHub#repos`` +``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` +``GitHub#iter_repos`` ``GitHub#reposistories`` ``GitHub#iter_user_repos`` ``GitHub#user_repos`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` diff --git a/github3/api.py b/github3/api.py index 6f8c12957..fc4c6b7dd 100644 --- a/github3/api.py +++ b/github3/api.py @@ -269,8 +269,8 @@ def repository_issues(owner, repository, milestone=None, state=None, return iter([]) -def organizations(username, number=-1, etag=None): - """List the organizations associated with ``username``. +def organizations_with(username, number=-1, etag=None): + """List the organizations with ``username`` as a member. :param str username: (required), login of the user :param int number: (optional), number of orgs to return. Default: -1, @@ -281,7 +281,7 @@ def organizations(username, number=-1, etag=None): :class:`Organization ` """ - return gh.organizations(username, number, etag) if username else [] + return gh.organizations_with(username, number, etag) def user_repos(login, type=None, sort=None, direction=None, number=-1, diff --git a/github3/github.py b/github3/github.py index b70a7a398..7f5d17039 100644 --- a/github3/github.py +++ b/github3/github.py @@ -781,14 +781,14 @@ def organizations(self, login=None, number=-1, etag=None): url = self._build_url('user', 'orgs') return self._iter(int(number), url, Organization, etag=etag) - def organizations_with(self, login, number=-1, etag=None): + def organizations_with(self, username, number=-1, etag=None): """Iterate over organizations with ``login`` as a public member. .. versionadded:: 1.0.0 Replaces ``iter_orgs('sigmavirus24')``. - :param str login: (optional), user whose orgs you wish to list + :param str username: (optional), user whose orgs you wish to list :param int number: (optional), number of organizations to return. Default: -1 returns all available organizations :param str etag: (optional), ETag from a previous request to the same @@ -796,8 +796,10 @@ def organizations_with(self, login, number=-1, etag=None): :returns: generator of :class:`Organization `\ s """ - url = self._build_url('users', login, 'orgs') - return self._iter(int(number), url, Organization, etag=etag) + if username: + url = self._build_url('users', username, 'orgs') + return self._iter(int(number), url, Organization, etag=etag) + return iter([]) @requires_auth def repos(self, type=None, sort=None, direction=None, number=-1, diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index f5a1aa254..92b60753a 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -76,10 +76,10 @@ def test_login(self): assert not isinstance(g, github3.GitHubEnterprise) login.assert_called_once_with(*args) - def test_organizations(self): + def test_organizations_with(self): args = ('login', -1, None) - github3.organizations(*args) - self.gh.organizations.assert_called_with(*args) + github3.organizations_with(*args) + self.gh.organizations_with.assert_called_with(*args) def test_repository_issues(self): args = ('owner', 'repository', None, None, None, None, None, None, From a56dcb9a176ab5bf8ff12d9e691908e417e44b76 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 11:38:08 -0500 Subject: [PATCH 075/972] Rename GitHub#repos -> repositories --- github3/github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github3/github.py b/github3/github.py index 7f5d17039..6fd127c9b 100644 --- a/github3/github.py +++ b/github3/github.py @@ -802,8 +802,8 @@ def organizations_with(self, username, number=-1, etag=None): return iter([]) @requires_auth - def repos(self, type=None, sort=None, direction=None, number=-1, - etag=None): + def repositories(self, type=None, sort=None, direction=None, number=-1, + etag=None): """List public repositories for the authenticated user. .. versionchanged:: 0.6 From f6ee49bd746cc475f05686cc3cbf498e60e2b7d7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 19:18:26 -0500 Subject: [PATCH 076/972] Migrate tests for iter_repos --- tests/test_github.py | 31 ------------------------------- tests/unit/test_github.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index cc6d7e3c6..c50f8c648 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -223,37 +223,6 @@ def test_key(self): assert isinstance(self.g.key(10), github3.users.Key) self.mock_assertions() - def test_iter_repos(self): - self.response('repo', _iter=True) - self.get('https://api.github.com/user/repos') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.g.iter_repos) - - self.login() - assert isinstance(next(self.g.iter_repos()), github3.repos.Repository) - self.mock_assertions() - - assert isinstance(next(self.g.iter_repos('sigmavirus24')), - github3.repos.Repository) - self.mock_assertions() - - self.conf.update(params={'type': 'all', 'direction': 'desc', - 'per_page': 100}) - - next(self.g.iter_repos('all', direction='desc')) - self.mock_assertions() - - def test_iter_repos_sort(self): - self.response('repo', _iter=True) - self.conf.update(params={'sort': 'created', 'per_page': 100}) - - self.login() - self.get('https://api.github.com/user/repos') - assert isinstance(next(self.g.iter_repos(sort="created")), - github3.repos.Repository) - self.mock_assertions() - def test_login(self): self.g.login('user', 'password') assert self.g._session.auth == ('user', 'password') diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 6e1e233a7..05e71dfe5 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -404,6 +404,40 @@ def test_public_gists(self): headers={} ) + def test_respositories(self): + """ + Show that an authenticated user can iterate over their repositories. + """ + i = self.instance.repositories() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/repos'), + params={'per_page': 100}, + headers={} + ) + + def test_respositories_accepts_params(self): + """Show that an #repositories accepts params.""" + i = self.instance.repositories(type='all', + direction='desc', + sort='created') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('user/repos'), + params={'per_page': 100, 'type': 'all', 'direction': 'desc', + 'sort': 'created'}, + headers={} + ) + + def test_repositories_requires_auth(self): + """Show that one needs to authenticate to use #repositories.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.repositories() + def test_repository_issues(self): """Show that a user can iterate over a repository's issues.""" i = self.instance.repository_issues('owner', 'repo') From bebba3f7dda8c71674de50ee528f6a266b2075f6 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 19:50:12 -0500 Subject: [PATCH 077/972] Fix usage of iter_all_repos in integration tests --- tests/integration/test_structs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_structs.py b/tests/integration/test_structs.py index c640f144e..237ed9088 100644 --- a/tests/integration/test_structs.py +++ b/tests/integration/test_structs.py @@ -5,7 +5,7 @@ class TestGitHubIterator(IntegrationHelper): def test_resets_etag(self): cassette_name = self.cassette_name('resets_etag') with self.recorder.use_cassette(cassette_name): - users_iter = self.gh.iter_all_users(number=10) + users_iter = self.gh.all_users(number=10) assert users_iter.etag is None next(users_iter) # Make the request assert users_iter.etag is not None From e13eb7c39e31aee64ae1ad026ecc9852a268ad2a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 19:59:11 -0500 Subject: [PATCH 078/972] Fix followers_of integration test --- tests/cassettes/GitHub_followers_of.json | 1 + tests/cassettes/GitHub_iter_followers.json | 1 - tests/integration/test_github.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 tests/cassettes/GitHub_followers_of.json delete mode 100644 tests/cassettes/GitHub_iter_followers.json diff --git a/tests/cassettes/GitHub_followers_of.json b/tests/cassettes/GitHub_followers_of.json new file mode 100644 index 000000000..ad5a709ec --- /dev/null +++ b/tests/cassettes/GitHub_followers_of.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.9.0"}, "method": "GET", "uri": "https://api.github.com/users/sigmavirus24/followers?per_page=25"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"b76d84b2efed104f73b426e2a6558592\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "42707356:023A:23F14DB:53B89F45", "cache-control": "public, max-age=60, s-maxage=60", "link": "; rel=\"next\", ; rel=\"last\"", "date": "Sun, 06 Jul 2014 00:58:45 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1404609513"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/users/sigmavirus24/followers?per_page=25"}, "recorded_at": "2014-07-06T00:58:46"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/cassettes/GitHub_iter_followers.json b/tests/cassettes/GitHub_iter_followers.json deleted file mode 100644 index b5f9cafec..000000000 --- a/tests/cassettes/GitHub_iter_followers.json +++ /dev/null @@ -1 +0,0 @@ -{"http_interactions": [{"request": {"body": "", "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate, compress", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0"}, "method": "GET", "uri": "https://api.github.com/users/sigmavirus24"}, "response": {"body": {"base64_string": "H4sIAAAAAAAAA51UTWvjMBD9K0XQnpzKX4kdQ9kvWOhhb10WegmyJDvDypKRZHuzofvbd+SkJc2lJGCwkee9eTOaN3uiTAuaVMRB27ER7ODSnEQEBKnSPC6zOCJsZJ7ZzWAVxm29711FaWsPx/fcdPTwSXmSl9lyJcp1s06XcrVOk6KspUzEOmO8KT6Jhxl+m325Tb/jA0JqD9xod9+C3w51YMPznBVJscrjLOeCybIo8jKvZZEWSVmzZbq673V7Zx/+oNBXHZugmHykAAHvy2A9nKSmg5PW0bNebH2nzqt/U3se3BilzIQsZ4gPE9E3JIo8fINur2RB5J4av5V4bVjSS2gUOH+5qBm1p+GFHQ48DmfBSnGxsCMOZU0aFe2plb2ZCYfacQu9B5yDy2lP0chmbMs0/GXXsSHaIUmQdrmUGYVoOeJUXw4/wPa0tzAyvgutsZJLGLHZV1Ke4ZHR73qJPvmJQxFaD15umOjCBmiYcjIimnUh4JHpm2/GCua4wUC0Zc/0Dn98lVrsJmN/h0pr3B7HnYArYZom9G+rYLYx/YfGngnoHBbhquHztSDiBxPgjI5ufj2GhnUMwm5BLzcN89woVNSa8TOuJFCBDIO2YCWrFYo7Kq3BkEoPSkWkH2oFfHO4gGqVvRoIbUiqVXLiJ9xqJZaDVB7byjxmTeMkXsT5Iomf4ryKiypLnzHf0It3MdkiSRdJ/hRnVbqssvUzefkP/iJouz4FAAA=", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "52", "x-github-media-type": "github.v3; param=full; 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-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "48A0D797:218E:2D362E0:52ABD804", "content-encoding": "gzip", "vary": "Accept, Accept-Encoding", "server": "GitHub.com", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 14 Dec 2013 03:25:39 GMT", "x-ratelimit-limit": "60", "etag": "\"70d50ea4539bcd86ce730509f4138530\"", "access-control-allow-credentials": "true", "date": "Sat, 14 Dec 2013 04:01:08 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1386997179"}, "url": "https://api.github.com/users/sigmavirus24", "status_code": 200}, "recorded_at": "2013-12-14T04:01:08"}, {"request": {"body": "", "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate, compress", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0"}, "method": "GET", "uri": "https://api.github.com/users/sigmavirus24/followers?per_page=100"}, "response": {"body": {"base64_string": "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", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "51", "x-github-media-type": "github.v3; param=full; 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-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "48A0D797:218E:2D36302:52ABD804", "content-encoding": "gzip", "vary": "Accept, Accept-Encoding", "server": "GitHub.com", "cache-control": "public, max-age=60, s-maxage=60", "x-ratelimit-limit": "60", "etag": "\"47efc319120dd38edd23902de1cb6a6c\"", "access-control-allow-credentials": "true", "date": "Sat, 14 Dec 2013 04:01:09 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1386997179"}, "url": "https://api.github.com/users/sigmavirus24/followers?per_page=100", "status_code": 200}, "recorded_at": "2013-12-14T04:01:09"}], "recorded_with": "betamax"} \ No newline at end of file diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index aabd96a1c..44322686f 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -151,7 +151,7 @@ def test_all_events(self): def test_followers_of(self): """Test the ability to iterate over a user's followers""" - cassette_name = self.cassette_name('iter_followers') + cassette_name = self.cassette_name('followers_of') with self.recorder.use_cassette(cassette_name): for u in self.gh.followers_of('sigmavirus24', number=25): assert isinstance(u, github3.users.User) From a632d55ad561094d532215ab356fceb3501629c8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 20:39:13 -0500 Subject: [PATCH 079/972] Fix TestAPI#test_authorize --- tests/unit/test_api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 92b60753a..4d93a02a1 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -32,8 +32,9 @@ def test_all_users(self): def test_authorize(self): args = ('login', 'password', ['scope'], 'note', 'url.com', '', '') - github3.authorize(*args) - self.gh.authorize.assert_called_once_with(*args) + with mock.patch('github3.api.GitHub') as gh: + github3.authorize(*args) + gh().authorize.assert_called_once_with(*args) def test_enterprise_login(self): args = ('login', 'password', None, 'https://url.com/', None) From 7b35b6120301080e7e8574b2b12d49c83de274d7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 20:50:09 -0500 Subject: [PATCH 080/972] Rename all_repos -> all_repositories --- HISTORY.rst | 4 ++-- github3/api.py | 4 ++-- github3/github.py | 3 ++- tests/integration/test_github.py | 4 ++-- tests/unit/test_api.py | 6 +++--- tests/unit/test_github.py | 12 ++++++------ 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index afe42649d..6983219a7 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -17,7 +17,7 @@ Breaking Changes ============================== ============================================== Old name New name ============================== ============================================== -``github3.iter_all_repos`` ``github3.all_repos`` +``github3.iter_all_repos`` ``github3.all_repositories`` ``github3.iter_all_users`` ``github3.all_users`` ``github3.iter_events`` ``github3.all_events`` ``github3.iter_followers`` ``github3.followers_of`` @@ -27,7 +27,7 @@ Old name New name ``github3.iter_user_repos`` ``github3.user_repos`` ``github3.iter_starred`` ``github3.starred_by`` ``github3.iter_subscriptions`` ``github3.subscriptions_for`` -``GitHub#iter_all_repos`` ``GitHub#all_repos`` +``GitHub#iter_all_repos`` ``GitHub#all_repositories`` ``GitHub#iter_all_users`` ``GitHub#all_users`` ``GitHub#iter_authorizations`` ``GitHub#authorizations`` ``GitHub#iter_emails`` ``GitHub#emails`` diff --git a/github3/api.py b/github3/api.py index fc4c6b7dd..af4194dd0 100644 --- a/github3/api.py +++ b/github3/api.py @@ -131,7 +131,7 @@ def gitignore_templates(): return gh.gitignore_templates() -def all_repos(number=-1, etag=None): +def all_repositories(number=-1, etag=None): """Iterate over every repository in the order they were created. :param int number: (optional), number of repositories to return. @@ -141,7 +141,7 @@ def all_repos(number=-1, etag=None): :returns: generator of :class:`Repository ` """ - return gh.all_repos(number, etag) + return gh.all_repositories(number, etag) def all_users(number=-1, etag=None): diff --git a/github3/github.py b/github3/github.py index 6fd127c9b..a2a46690d 100644 --- a/github3/github.py +++ b/github3/github.py @@ -388,7 +388,8 @@ def issue(self, owner, repository, number): return repo.issue(number) return None - def all_repos(self, number=-1, since=None, etag=None, per_page=None): + def all_repositories(self, number=-1, since=None, etag=None, + per_page=None): """Iterate over every repository in the order they were created. :param int number: (optional), number of repositories to return. diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 44322686f..52ad47e71 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -128,11 +128,11 @@ def test_issue(self): assert isinstance(i, github3.issues.Issue) - def test_all_repos(self): + def test_all_repositories(self): """Test the ability to iterate over all of the repositories""" cassette_name = self.cassette_name('iter_all_repos') with self.recorder.use_cassette(cassette_name): - for r in self.gh.all_repos(number=25): + for r in self.gh.all_repositories(number=25): assert isinstance(r, github3.repos.repo.Repository) def test_all_users(self): diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 4d93a02a1..238f48c6a 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -20,10 +20,10 @@ def test_public_gists(self): github3.public_gists() self.gh.public_gists.assert_called_once_with(-1, None) - def test_all_repos(self): - github3.all_repos() + def test_all_repositories(self): + github3.all_repositories() # TODO(Ian): When you fix GitHub, fix this test too - self.gh.all_repos.assert_called_once_with(-1, None) + self.gh.all_repositories.assert_called_once_with(-1, None) def test_all_users(self): github3.all_users() diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 05e71dfe5..b02faebed 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -38,9 +38,9 @@ def test_all_events(self): headers={} ) - def test_all_repos(self): + def test_all_repositories(self): """Show that one can iterate over all repositories.""" - i = self.instance.all_repos() + i = self.instance.all_repositories() self.get_next(i) self.session.get.assert_called_once_with( @@ -49,9 +49,9 @@ def test_all_repos(self): headers={} ) - def test_all_repos_per_page(self): + def test_all_repositories_per_page(self): """Show that one can iterate over all repositories with per_page.""" - i = self.instance.all_repos(per_page=25) + i = self.instance.all_repositories(per_page=25) self.get_next(i) self.session.get.assert_called_once_with( @@ -60,10 +60,10 @@ def test_all_repos_per_page(self): headers={} ) - def test_all_repos_since(self): + def test_all_repositories_since(self): """Show that one can limit the repositories returned.""" since = 100000 - i = self.instance.all_repos(since=since) + i = self.instance.all_repositories(since=since) self.get_next(i) self.session.get.assert_called_once_with( From d4a3858137e31f7b3d0a15b43ef32501aa6cc5e2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 20:57:43 -0500 Subject: [PATCH 081/972] Rename user_repos -> repositories_by --- HISTORY.rst | 4 ++-- github3/api.py | 6 +++--- github3/github.py | 7 ++++--- tests/unit/test_api.py | 6 +++--- tests/unit/test_github.py | 8 ++++---- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 6983219a7..8a5ba6661 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -24,7 +24,7 @@ Old name New name ``github3.iter_following`` ``github3.followed_by`` ``github3.iter_repo_issues`` ``github3.repository_issues`` ``github3.iter_orgs`` ``github3.organizations_with`` -``github3.iter_user_repos`` ``github3.user_repos`` +``github3.iter_user_repos`` ``github3.repositories_by`` ``github3.iter_starred`` ``github3.starred_by`` ``github3.iter_subscriptions`` ``github3.subscriptions_for`` ``GitHub#iter_all_repos`` ``GitHub#all_repositories`` @@ -43,7 +43,7 @@ Old name New name ``GitHub#iter_keys`` ``GitHub#keys`` ``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` ``GitHub#iter_repos`` ``GitHub#reposistories`` -``GitHub#iter_user_repos`` ``GitHub#user_repos`` +``GitHub#iter_user_repos`` ``GitHub#repositories_by`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` ============================== ============================================== diff --git a/github3/api.py b/github3/api.py index af4194dd0..f962a29c6 100644 --- a/github3/api.py +++ b/github3/api.py @@ -284,8 +284,8 @@ def organizations_with(username, number=-1, etag=None): return gh.organizations_with(username, number, etag) -def user_repos(login, type=None, sort=None, direction=None, number=-1, - etag=None): +def repositories_by(login, type=None, sort=None, direction=None, number=-1, + etag=None): """List public repositories for the specified ``login``. .. versionadded:: 0.6 @@ -311,7 +311,7 @@ def user_repos(login, type=None, sort=None, direction=None, number=-1, """ if login: - return gh.user_repos(login, type, sort, direction, number, etag) + return gh.repositories_by(login, type, sort, direction, number, etag) return iter([]) diff --git a/github3/github.py b/github3/github.py index a2a46690d..e4325eaa5 100644 --- a/github3/github.py +++ b/github3/github.py @@ -808,7 +808,8 @@ def repositories(self, type=None, sort=None, direction=None, number=-1, """List public repositories for the authenticated user. .. versionchanged:: 0.6 - Removed the login parameter for correctness. Use user_repos + + Removed the login parameter for correctness. Use repositories_by instead :param str type: (optional), accepted values: @@ -916,8 +917,8 @@ def subscriptions_for(self, login, number=-1, etag=None): url = self._build_url('users', str(login), 'subscriptions') return self._iter(int(number), url, Repository, etag=etag) - def user_repos(self, login, type=None, sort=None, direction=None, - number=-1, etag=None): + def repositories_by(self, login, type=None, sort=None, direction=None, + number=-1, etag=None): """List public repositories for the specified ``login``. .. versionadded:: 0.6 diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 238f48c6a..d320e9e4f 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -96,7 +96,7 @@ def test_subcriptions_for(self): github3.subscriptions_for('login') self.gh.subscriptions_for.assert_called_with('login', -1, None) - def test_user_repos(self): + def test_repositories_by(self): args = ('login', None, None, None, -1, None) - github3.user_repos('login') - self.gh.user_repos.assert_called_with(*args) + github3.repositories_by('login') + self.gh.repositories_by.assert_called_with(*args) diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index b02faebed..57a2d5aa7 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -555,9 +555,9 @@ def test_user_issues_with_parameters(self): headers={} ) - def test_user_repos(self): + def test_repositories_by(self): """Test that one can iterate over a user's repositories.""" - i = self.instance.user_repos('sigmavirus24') + i = self.instance.repositories_by('sigmavirus24') # Get the next item from the iterator self.get_next(i) @@ -568,11 +568,11 @@ def test_user_repos(self): headers={} ) - def test_user_repos_with_type(self): + def test_repositories_by_with_type(self): """ Test that one can iterate over a user's repositories with a type. """ - i = self.instance.user_repos('sigmavirus24', 'all') + i = self.instance.repositories_by('sigmavirus24', 'all') self.get_next(i) From 66e7cef3775d0eeacde1d7489f70225673e55aaf Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 21:04:23 -0500 Subject: [PATCH 082/972] Test GitHub#repositories with integration tests --- tests/cassettes/GitHub_repositories.json | 1 + tests/integration/test_github.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/GitHub_repositories.json diff --git a/tests/cassettes/GitHub_repositories.json b/tests/cassettes/GitHub_repositories.json new file mode 100644 index 000000000..4928896e6 --- /dev/null +++ b/tests/cassettes/GitHub_repositories.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.9.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/user/repos?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+2923LrSJam+SpoXUxlWm6KBHimTVtNdlhlRNZUVsdEqGqse3psN0RCEnLzVDxshUIWc9VP0o/WTzLLT4C7w0ES8N/DMkowi6rUluCfLxzoIj+ttfz/eb/LV3eLJB7H8WA0+nS3TTfZ3eLueMry7d2nu6fzev1Zfm91PJ2fnk599bPd6zY73C3e79a7Zzp4cScPoGGMGY/G8+n80136NT2lh8/nw5oOeTmd9sdFvy++ebx/zk8v58fzMTssd9tTtj3dL3eb/rkvBv89oZ4PEsCYd9njUzxMhpPkcZIko2SYrcaP6TJN5rPZPI4fZzTAmmify0kEmWY69stAX06btRWaCIkfXR73tFuvd6801j6PC/h+MYhdSA7It8/NATTovb87vWR0ESn8X9hFyY+nRqHwAe999j+f8xVDHOmmHLJVk3DkEAqG3flf3vuHbL/jrPPjcXnI96d8t20UljGQQLvDc7rNf04bg2jgkcazgBoFwAfQwOwrPXuNRooR7/39If+aLt/YZThkyyz/Ste0Oc0aSrDT2569EP+F7ji7wvkp+5yuNux19pSuj9kvn+74zCc6iH/jE722bniWi1fvKituGU3zI3u9R/kxSrdRenzbLl8Ou+3ufIy+e3j4PqIYvmYH+tkqes0eo6cDLRKvu8MXCuyJ/Y+K4OJLj19q9ZIqwmDjr1x3x0B6adEwmv5L9tZiNBv13qf/L18LS3pxpo+7Q3raXXuFu4Ixhr/39X+yx+KUpZsWQfJhNPxlt2tzhfgwGp4fj+fspifSdWp89LGvHvbtefMoVqBbHnEXUIyjuNLjMX/eZlmLK1MMfe+rBfHxkNIz2wamRr73xVf8jqXPLcJio2jw43r32GI0/drp86Hv/eNLKhb50+d2kTAWG2mgDtlTy7DYyAJ1OrS6ZzwkNrQA0W+TE92+FjGpkf13eaXW6fb5nD63YRVD6c6x32/P6c9Xf8u7nutyLIHYe5lD/nhuu5yUo1lU4pcrve7aXKpycIniv6cv/+J3nqL2W56f5GaTX/ud6eLIgcbD2RrGnisbyP59/dd5XWhs5Hu/XOnEAiqZza+aXEFVTP33kizf8ra4rWpk//0P+/T0wlYLmmCfHrLmAcqB/ffHlN5W3N/fv79kKX+LuMkOrV5TYhwB0sPyhd4QNY/pXY2k3/Ob9MTfaj6xkFb01nO9S1ctrlkxlDDipjSPS4zTn449fUBqEQwfpnM2+To7nnbbNmtYOVYnbnen/Clf3vJe2vVSMIa///0x3y6zT+l6/YmeslO+zOm5ow8m7J7QW6eszTUQ4yhkejcp3j6vM3oEW1zNQyZGvvfFZ5vlIaM3xqvP6Yne2iaDeNQbTHuD8cMgXiTJYjD9rxT1eb9yHpMMFoP5YjBix+zPxxcHJp4t4vki4YfQ+iMfI/qKPthWPz2Kt7rsQygdfjy+lIf/H+XBC+PDtTx4uabnwXpIr/G/2gt73QAK5mW3yfb0a5MuEgst/5m+Ghi/Bpe785au4fjT3Wt6ovdX9Cuo/Jb61UnDv387veyYL3hJj5/Fi+RucTqc2acS+k750tO++Zp/yYtPDuJjgGRTDJv8cNhJabCl1wp9NNxnW4lWMdBx4nMAi1r7OT8LFTCPfpU9pef16bN4i0cBb1KyGOyD1T47bChg9sGVqQz9I5a4/+o82CtWfP3LL5+ENZmOh6PZLC6kyfLpmYi6Msm3x322pLcB345Wzxn9puJHVMSJdRgdwgXKbD4djZK2BkWMriqU6XQ+eHwkWZKkk0k2iGdZ9hg/zZ8Gg+EqeZrPafaLn+PYW+5jvxry5Y+f1eMbKRX7QrZWK26Qj2KxiV6qxYbhlEuFrDsb9lA2VS82sKmCscfzX0IUyC2fLJ3PYPEp1U/JVOMyrA5FiFYz9oxilTAFzTfsI8VuHf2JLGL07SHdv0S09kV7tfA29TDuOW+2MY7hjZ2Mi+FtZlxQlJ9xsRtbGhekratxsQDGxoVt521cJE9740L6OBwXr6nJcTHYB9P2PqeO2Nrq1AHbuZ06WnvD4yL6eR4Xsb3tcdG8nI8LqHsj+j3T0Py4iBqiBN7sfy4QOYOQDcSNi2arG/ZxyhPJXng2VtmXWz7x14Xp7YVcYJAdcqH9HJGbyBWTlylycdv4IhcHY41c5HbuyEXyMEgunKdHciFBNsmFDuGUXPP4mCUX75pfGvYGcS8ePAzGlPWwiAcuvzTsxUkvnj8MJiSXFsnM4ZcIM+4lhBks4skiHl7xS45Ir1mm+iFXXFP9wOMl4+QYRr8zSu8k1I4wT+Nk6HJP5D9s90TfgrgnIagM9UQyp6F6ohH16okiDaOe4tEsHg7IbMncHPE5sPd8zlcZXWHdQX3Jttvs9HLI8tPPfeu4ionSDyYO11DxfDanW9Muj4cPrkqox0HymDwNksFqmT7Ok+Xjcryczid0TtOYJnyiuW+QUFa0lw2UdXAj/WRcw9buyUHxEU8Gzss6GSSccjKxvr7JoDWVTcbg5qbJGI7J/LEiCu2YjOmsVcA0TcLlR4/056hof0iX9Mee7BjxleWRcko+Ra+H/ESpetw/fXfepNvjfcTWnIaZQJciutlD1UIa26h6kreTqkejzFT9DI39VD2qraWqJwJcVT28nbGq53l6q3qwj72qpzZ1WPUkP5N1mdvaZ13GtrNal5nt3VY9189w1XPbe656ppftqsf6Oa96rp/5uspt4b/qmbauamjB6sG+LqyerIyaV6ZUPR7kxeon8LNjl7j+jqye3saU1dMwvqye386a1fM83Fk91NOg1YNBHq1+ghA2rX42H6dWT71m1uLegMQZZW4NKd9qkTjNmsruiqek1cicOcyaOGT4EI8XY5JryRWzVhvvNb92beAVy3Zt+EXXVjvYMG6UQbk83usfAO/pszT72xBP/xqO5+SstERole41Gk6rIm7MvxvMxU3msxt13JAOlKlgMR9lKDn2Uy0djAcdSMtRZdpoTtlnUssdsn+j8okTS2upVXLaMZ2Ou5bjLhJ/jEe903E3Ft0ZV8278s6gdTquYTWecfW0FcCp4ngN3g9yKdG02//6H//z3le86SvUraV4zuD9hJsKgxXl+ZXmuYMLItqKoP0kW4GBCLaChpZrBRgg1goWUqoVUJhQK29ww9I+90MIFGlFZIyJkWgGEiDQzBBbl/65LyVQnBVxgqRZwcMJswIJlGVlmF4lgjW3p3WpoJuHFGTGc2mDmySK1YfqnSrmRoeQYsajxeJuV1LoDpiupnfCmJvsLcKK8w4gwQo2QIAVLJT8KoBI8VVAQ0ivAh5ceBUzwWRXQbxBdFF6GBmq2WJIEutyiWKyGJMP4/lhzhJFwgxJ5SzGHMP+miCSaegrs0TR+eJqJLnUCd5WsnhxvkuJZM6BptiSTqsISNda8XA+oeZGVa8VD5LEIbbkt8OZLTbpTYlmE8ovK8wWG2WYLfbT0mzJqAOprfF4OJxOKALLbfVOu92aKoBZeasuuf7p/CU9plS4LRSYfljFc4ljCcATzoazZDyetM04E6MdKWfjNMuywTidPY3GyXJOJZDD1Tim1lGD7HGQjWj2G1LOikgvJ5sVhzVKM5OXrLXRMsb7pJZJkFdSmWTg0skU0DeRTHKaOis5rHnymByISRsrogidMFZMVH35mpLqj5FaAKLdU0SClhaBaLmmT/aUNsZaRj2dt5RERpKSDqS0MnYI9ZGixm+yerGnlojCZYnE3IuvRtGy4EKQN6eQ1TEaC61akLfTqiWjtFbtBI3NVi2prdyqBQL8Vi27neKqxXlarlquj+iqhTZNHKsF+emui9jWxusitZ30uohsnzRWi/VTX7XY9varFuklwGqpfg6sFuuXL3YN2yJdrBZpO6uG2WK1XN9ksVowJFeslg6yYrV8v0yxC1h/N1YLb6PHamEYQ1aLbyfJanEenqyW6anKarkgW1bLDyHMaifzcWa10GvajFdVDgdcm1Hjrrr8sJgfk7D8MHFMVZuJQ+LFkP67ps3qwr1mzq6Mu5IddmX0xeSwurGGQtOrMam7tsuXaY21tC5c1zyZalB8uRWYoxwT3AmMcIHkWDwazqfDsn/6Y3ZKN+lPlhKjjreb9Gt+OB+TUb88pKLD9OOkFEtGg9mQ4m9VhSkGV5XYkspIh+PJajZ/mifjbDJP4unsMcvi1XyYLp+mtykxK9rLYsw6uJEeMy5fa0nmoPioMgPnJcwMEk6bmVhfeWbQmio0Y3BzkWYMx+g0K6LQUs2YrlwAbKH2r9/8EOXUXJf37ozop6xT9irabddvWtevwpu1SQKrieRma+Ya39iYOSHetsxJRZkyJ7yxJXNS2hoyJwxgx5zcdmbMifK0Yk6mjxFzApvaMCfEz4TVIltbsFpiOwNWi2tvv5xIP/PlRLa3Xk6cl/FyEv1slxPpZ7ouIVtYLifO03A5mb52ywmFmC0nGWS1nGw/o1WD9LdZTnAbk+UEYSyWE93OYDlRHvbKyfM0V04myFo52SGMlXMiH1vlBF43VdSDPp7wSkb6j5cgOnrQT3i1IzWgjxejmgSvSW9AmHgxni3G8ysJXq5Qr1mqC2OuGKoLIy/aKdc4w0zxfeModU1+ZLo/nJ5WRt1iPJ5SwlA1v4ulEdntw9j3rhmr1r3rSQHdlNdFeVQyrYtGGDldWjoa9a6nWJsqKxE7M5wXetfPYto9b671rqdN+mixOO2fXy5JK9pOQjusE1e31Ssaz3cnrm6sVzSumne9okHrxFXDekXj6pmLgCmvNjvaALF5ItcFfjslpcXop6V0EFZN6eQgekqfwE9R6SSIptKBaFWlswG6SschlZXOhWkr45Y3LFqsew2yPY08WtlfxGIUln7WLFiAxrKRIJWlY4E6S8eClJYVqdwYkVZ23Ujd0k+99v4D1ZYRrFc9Y220+hsQfhVu3v2wFonUXPbzarOVqfK8Y2JjRa+mX7WXI4Ty0i8LUHuZWLD60uHe+kuHBVBgOh6gwXQcSoXpTKQOM25TsXuj1w6MtS+N4FpMPxmYGtOhN+gxqn+MH6iJF/W+F+rL1mPUH18dQ83ARtx9WYlc2iGMdC2Rq+6CN1Jk2mneVgV5bdZLhZB1Yw1dpidyxQPKGqqKsWuJXAKhb+f4G07iusmITWZzqjok3ybrG5cv6SGtdNM3r39xSGfCOhNGu2IaT0eXwsWWw5fz4z29+eyLzm3GBfrtp3CVa4Rpwf5ErbQoYesr7ZTKMrioLpIducpOn6gAkrINo/3uQBsUs4LI43nP/iFrIaOEl0yKWvZoyLO96mrfmRhThv+GWsmalaulXhMrn6dakxCwVpPUMEpNwj11mqRgVJqEwTWa5CIUmkRB9Zlk4tSZurVe2kxCkMpMQ4J0mUZEqDI9wNZ9vlzLE22dnp7oFwc1JTq+pGKv+e3zmbYsv2mTeCcSpcfkSeMyvuTvEtq7kHb6zR/PtGs46xvbcBNI5zkDM75UlCgdJi+jrasa1jQ6zxqa8VXeHbgCk5cgiP4qLu+Wduxp29zLeXXpjnn39nKC/ZWXPOkQukuiEarLuO26NuKSqrmnlTyo4pLMEBlf6gUVXm3Jk8BpLQm8prSYq+ols2u96ymda/QwoNrEKXX+ciottnEkb4FPFYxD3t6eLY81Lb1cr6lmOkucXhuVZYy8PeOr/BRV7gzJM76ON3Qr68t1cz6O2W9L3sU+iWdO6TXW2mWp8kX2vWDZYDE1078pHUzrX09DjHwws3k9RVvJB1vRW/T1bs9saHbY0PVgzXbuFu936WqTb8sksCsJYcmMOmKV+mudb+2WXuazJQ/o1Fenvjr1dVjfLYo1K93n//7Vl3z5OzvWf0N/HSeP1aNjsuiP+/06pz+SMBP2QL0C+W4YPu5KrUy39quvLlue3ooF4N+p3hFWGGfFw/U0VpyB8VUcBbdVnIpwVRwENVWciPNU4nZ6WSqOQDqqAggyVAUP4afK4EB2igORbooDUWZKRYdK2eI8pJUSAQLTtHSgbw3iUp4uT+9670vv6OWjiufPtlztk7KKIL1bzTt+CwUxUcVThPJQ6hKALRTH+jsojglhoDgY4Z84CJZkxWlQ9yRuRIjEKk4O7534NDjrxHHXnJPIfxo8JPGCFRE6qwy1Y+LBInHtl2gdcm2/xOoa0sw4sVNr45u0cQ1sExtlpEup6sL9G31uE396Z8WFffbvvvh9UKil2dBZZ3gtneru+7fTy27LpqUmWOJVd7e4LaVKHiX+UC/3Y/wVGmNBrBI1mEomSUzhqqwq8detHqWFsI+BpLo/y5+YD5FxWKeYOsXUKaaPp5iMRcAUTf95n22j4+58WGbRmmoOD8dP0Sb9wnKrsvSYZweWW/WUUy7VkpRTtD/s/potT7wF/Uu6/EK9tP5D9H+n220avWTrPWuN56WkzFWtnZgqGZ56SgOBU6s0chhVpU3gKaw0EkZbaUC4vNLYCIWl4aAiS+PidJZ+y72klgZCqi0LCxJcFhWhuexAQbJLwyKVl4ZFiS8zUpT+0qhICaYHC1RhVay3EDMuAFCLWc8rTo5ZAYMVmUYPIsqs5w2ly8yLApZmGtxfnWmwEAJNwyM0WuVxAKRyaUyoUtNvUwixpvHD6zVtMpxk06DXVRuld8nW85PFeOxq6MXb01N6V0wuburesVE/hAofm6m2Mtxmwq0yrkljL/lbkCkcNevtFYvlzE4FJ9myaKi0bswgNS9ivPtHapf+4/KQ77nwa2ze/iY70t9UzDidDeaDmVbMqO+xVivdtIM65dYpt065fTzlpi0BVlf69To6vWRUv5ieT2+spNHacJfXKn5TiDT5V4vGhYnWZpAtEuEVwdOiFRiwQyu4YQxagff0ZwUHY88KHNydFWSEOStgUG9WUHHWrLzNXs6swCCNmQEF+TKDibBlZpAgV1ZAkaasgKI8mR4lypIVTKQjKwMFGjIb6u3HtFMH2jHj+cS5MSNYsBkr2EG8mPGEoayYfjnATqxA+xuxAhXChxVwhA2zHgGACyuIUBNW3pwQHqygh7dgxVQ4B1YgrxuwARU4jh6SZDEeyWZbjp5dlWOqPbsqh9xc4KiCbea/rFGN7Jc94+3uS400zJfeq4t1e29uuaqtum7qXv/blVvUun4yHwypMFIllZ0Ph7fscDGhrDikM1ud2erM1sczW8UCYHqt79Ljl4zc1vH0ts6iJTuKJZExmSW7cC3TNf1yXWfH6HeqL9f98A98N8bfe+uucuVqlzQmxnuqLgkBiy5JDaO5JNxTckkKRnFJGFxwSS5Cb0kUVG5JJk5tqVvrJbYkBKm1NCRIamlEhNLSAwQJLYlE6iyJRMmsMkKUypJEpMhSQQI1lon0lljFSQMVlvY84gSWFihYX0lyEHmlPVModVVeCLC4kmB/bSVBIaSVRCOUlXHbAcJK8qC6St2SELJKssOrKjkRTlRJ4HVNRYla8YD12KIeWiLDytZUI8rSYr26WO95+s/VWp4OiXuDKdt5cTRbDAeN+nCJUJtJKmNMI0Vlzna7oBLjzMQs/okoO1S3XEwS2rmwaquofZW94SJ9C9Jhy2GsqB3WTf21KH2M10/eLWiE0V5Lq9ykxmGO7lqb9HjibsmjudZokkzi0bgUVp/X+SPvg1Obi6WO6HRVp6s6XfXxdJV6/VtZWFTOuF5TJaNsK3/ckJz6xBvNU4MtElise/wr+azeKaNlaxXROnNIDznJK0x6VrFwtdNVfLinrRIMsKwS0DCuSrA9VZWAYEyVYMFFlcAiPJUgQTWVQOIslbypXpJKMJCOqiSCFFUJRBgqLTyQoBJEpJ8SRJSeKuJD2SkBRMopGSLQTRlEbzWlzhhopsrnECemyjDBXkqAg2ip8mFCWaniKoCllOD6OynBCaGkBBlhpPQbDhBSAgf1UfJuhNBRAh3eRol5cDJK8K65KKoGnPBtDmn/wvFiWF80mCQPrNv7nP5z9oQfDHvJhO2WyKzWqJGL4pE2U1H6kEYmypjrdhHFh9WmScUzSv2pmifqXW6bJ/qWZp5YcYpeBPg3kiZFQVZauiOk0zSeTwaDaSGdVqvnS8ZJ/LjTTZ1u6nTTh9NN4sVvuqbo9fX1fnVefmH/97xjuzhGP2eHXY9aIlIHrXz7tIv++P2fuVh6o05cpKbKru9FYpRYZJuWAcq1qpVkorF+hokBsHqJEYO4JQb2E0uMALFKDIRWSowJ8EkMg5RJjAczSfwW+mgkBgA6JIXDCCRFA9ijIjCMOmI4oDdiOJA0kpGBjBGjAXURDw7nijScrygSJ4qzROp5gykiFSDWDzFqCDmknhuQGZInj9VCDOrthBgkgBBiWIANKm+vvwpiLKQH4pc/gARi3OAGiE0C0z8Mdt39sI38JqxcLo5r3Q8lGcVDLnYG7v0AiaEwQ2rf3qhhFIXZSPyUxzexPtosNysfGmPmHdG/xGZ+8bBd7yePjuuORCOKoWGiEY2oTzSiHwZxPqPReE7b+JXOR2wNSPlb9A6x7KpVm3Ykm77bx3dWqLNCnRX6eFbIvXqYmujb/PTd+ZGboNVued7Q+0W+15+vAXLPLXbBaKyTHDBPR+QigqWRa4owFsk1k6dWciExnslFhosn1yT0PdpDnZ7rwiU13qXb9fsVq6ZcgeNclYvuJ69cRKTNquOD9FYdHuG76tgnkABz8ZFGzMVHKTIXu/yTML1GdeWFeZkiJZozfKBVu8D31mwutu3IWP8W+T3MxWdLgj0J+zdbkTEzKJquWfivFX4iNA9mmiCqzn1LtieUu3PzN2CZ55rF3+65qCF0n2sehP9zccVDBBCCLjjUELomCKIMXROFd4iuWXFS0UW/bhkH415CZYrUkWte25SLFCI17oqHCyp4FK3rK0252CFDhhlSotqwSYaZ601uM+3oOHEJaOQh6zG3bxfpOhnTVL6cTvtFv19zoJCYk/GYagurOWtk6uycNfqWlrP2w/nxjU3XuHe9a9dIcLUk4YJIzPlgMpgOSJHK9l7ZOtu/pHzTzlpxqR3TycpOVnay8sPJSm0FsGsmqXL7mFM55Pb0KWIrCBVH/nSKjll6WL6wzl4Ribve13R9zqgN2O6Q3Uff716zA5VPPr5Ff1pTh7BP0T/Q/5zy5Y980CdeZ/m8260oDY5xyXce7z2Np77MtUp8UwA/s1lQsDazwAYxmAXdz1oWGIipLGhoO1mA6Q2Or5EsWMgEuQIKM4/lDfZJlSsoQMNoMDFW0UACTKIZIsYeFkygMSyYIEuoxwjKpiuQQBtYhokzgDbT1/pp543LsDOeS5jdM0Jl6yPO6BXoEBbPeLRA5k6/FlhbV5C9DV1BCmDlCjbAxFk339++FUCkcSvvS4DEvAIe3KwVM8FsWkG8ZtCGPVZcOX2IZ4tkTC3D3Bs7smNmrKcYS8Kb1dZoKsxo0sSgqVgbWTNrUBNTZs93c9qeGmgaMfqXzN2LqedV1XqR2rGtF33rWo8wabSYCitfzYuyiPM1/5LfyX+LNJHl7kzWaPEbyd2Lh5P5cDgok/ey85oS8V4u9gnTjum8V+e9Ou/18bxXuUqY3uv7w+6v1Cks+gd2AHmqSLa6LzRVyy0a9WWpnaeSEXt6KkUBeyqFDeOpFN3TUykMxlMpGtxTKTDCUykW1FMpKM5TFTfYy1MpCtJT6UyQp9KRCE9lhAjyVIqJ9FSKifJUWowoT6WQSE9VhAn0VBbT21OV5w30VPpzifNUeqhgT6XQQTyV/mihPJV2LcCeSpH9PZUihfBUio3wVObNB3gqBYR6quK+hPBUCh7eU6mZcJ5KEa97qnjQi+esIT1letV5Kv2YmLusaqaXjuEqi6Xvihob+opym+j/y+LB/jF/3qRf88P5mIz66qNAM08lT7BFRpc93+2eSs5peCp968WY5Ru1MFXlZ6q/wc5idEpBErTG8XSkt7PPftrTB83LGzBqx3SiqhNVnaj6eKKqXCVMUfUP8gfRt+nqOTstosfsRKtJJJYMXkxKey/S5/7swL/+PW85Jur7vZOutKWrncySAE+ZpShgmaWwYWSWonvKLIXByCxFg8ssBUbILMWCyiwFxcms4gZ7ySxFQcosnQmSWToSIbOMEEEySzGRMksxUTJLixElsxQSKbOKMIEyy2J6y6zyvIEyS38ucTJLDxUssxQ6iMzSHy2UzNKuBVhmKbK/zFKkEDJLsREyy7z5AJmlgFCZVdyXEDJLwcPLLDUTTmYp4jWZRY3xp71k/EA7NFJO1ZhbKHuTRkrMouZo8cNgvhjHizHvem/JLMLMegkdQk6MyhabJV3JWJvJLHNQo6Qra77bZZYcWJd0NXJuzHi11PBvumFaqFrDeDibDkcxbSggiw3po+UmPfWes91fj7vt/XL9V5YvUbdNo/Pozm91fqvzWx/ObznXAtN0+aZeOado1xKtivIzWA4e1mU5JghitRzz+PktBxBiuhxctPNyTAGwXw4q0oM58DAj5mB7tT9z8ICWrIaO8WU1cIA5qyGD2p456ECb5qCDvJqDjGt45oADXZuDDtxCoJ7u698cZFuYsUwJ+b3G/cEcePbit6dQjckQfMXClUQ6TiKEp3NMwx5QkLFz0sHtzRxzeFs8BzOAz3PMAjB7Dqp4cPwdnwONtH0OfIiWZo5pghtAx5wwF+hgX7OCwx6lr5EVZFsmTBfJwG0F2TG0rcKQlWIO+DGuFDdxSELusJEVrEbdyA/WDm9iCmsht7cxqyIupMI5/eHVos1v1ru/ng8Z42rdyv5GNtkMlQo3SSbJYEpbeEp9+PxyfNsuLynD4ohOE3aasNOEH04TFq//yjYKlGId/UirBxV9R7SYbrNjxPLc6G8Pxyhdr6NvxU4Lh2y/o3w4tnyseB8yUUu/+r1vLly5drXKhBPD/SyiZGDNoYQGsYWS7WcIJQRiBSULbQIlFmD/JAlp/CQSZvnUTfXJepMMoM3TiBiDpwEB1k4PD5PtJolAOyeJICNXxgfKc5NAoHlTIeJy3Eyir2ErzhiX36Y9hzCTpoWJzW2T4BDGTHuYQJasvArYrDbJ9bZhkhPAgEkywHoZN9zfdEkc0m6puxEgk02ig1ssOQ/MXEneNVtF23JSJSV1/BouRvPFiO/MWc1hi2PeOIwOGNS23ufSizYAZXuAxk0KMkWkjQyVMaSJlTLnujl7TQwzc9dkC/0v2XabnV4OWX76+Z4W7/7jesf3NqdPRj3mVbJDL9/29m+nl922Twi1Q+jcVbsZMuHN1V2fGvw33CKURtRvERoq420ymI/HI81Y5aceXd+Lyqo4pHNWnbPqnNXHc1bFAlCTzyYsf9NtOWllV0tPO+MkxnsqJwkBOydJDSOdJNzTOkkKRjtJGNw7SS5CPEkU1DxJJk49qVvr5Z4kBCmfNCTIPmlEhH7SAwT5J4lECiiJRBmoMkKUgpJEpINSQQIllIn0tlDFSQM1lPY84jyUFihYRElyEBOlPVMoFVVeCLCLkmB/GSVBIWyURCN0lHHbAT5K8qBCSt2SEEZKssMrKTkRzklJ4E1SajB+oBZhtJHjaOySUqPeYMI73ieLwWSRcONkpVDRIVRbGT9QVSUlWg2aSSkRajMrZYxppKXM2W73UmKcKaYKxzSattu/EVtU+RvZwHE8H08m40mRFPXtnx+y7WN2eL4kmfSDOs3UaaZOM304zaQvAZU9HGU3+9Mu2uTPh/SURarB/bdnqgNgy0tEP0yjr2y3x9024h9hduvo+EZbP27Y0kOSSW0Q0lRVGUtYK1lVEPx0VYnBCquSG0RZlXg/aVVyINqqxKHFVUkGqKsShpRXJRWmr7Tb7COwSgxQYZlQjMQymQCNZQWJEVklFKiySihIZhlRgnRWyQQKLS1QnNKqQH2lln7qOK1lPp8wsWUGi1VbJTuE3DKfMJDeMi4HVnCVaG/FVaICSK4SDtBc9iPgL7pKIlJ1aTcngOwq6cF1VzkVTHiVyOvKazDnVYPxYjClokCX8hK9xJKHeLCgdK3h3KG8RDrXnJuz4SLh6Vys3PuWxvhFsI2klz2qifayx95eGliMNNSX3hw/mYwTZ4rV1ZpArP6i6RpmWNGI+gyrUDWBo/lgNh2TL1Q1gSKBbbnOL/kvmeYmjuoEWCfAOgH24QSYsQaYBuyb3WZDxX69db7NonS5zI5Hpru+FTWBX/M0Or1k0R+//3P0u6/D3xe2q+Uej0YgzJsdG3cfKRF+wkvjYI2XBg6ivDS+n/PSQBDppfHQ1ktDA7SXRkN6Lw0LE1/6zfYxXxqHvmQJ8I/H9/7xJf1Fvvtk3srntcioGPdlhQqQXxYR1PBLowL1l0YF+S8zTpAA06BAA6aHilNgVaqvAzPOHifBrOcUZsGscLEaTIOH8GDWgwYSYeYVwZowje2twjRWABem0QEyrPIg+NswDYnUYfodCuDDNHxwIabNBTNiGvMGJTbtsSywEfXWX4ymbiUWk/KiFK8J5XfRlpIOJUbWbNyLhw+D0SKmQ5pmgbEyPvIbjZxYeZIt9ousDL7dipVDDS12J0sV9W0wWWBqe0xjmChPnE6c7iwef7oTnVtIdSx35+3pjvYs+HSn3k3cLe6c9qxtQy2q+LtJnpG34h/47hY0wpBn9BMVsAg1yOaSw2k8mMaU6WbYs+H9/u26PZNHdfass2edPfug9kyuAaY9EytptM7pA//hje8fmVP32MNTusy3z9ErLeDcn30rdBpptK9DjENTC5eHQ2MIhEPjnBAOjYMDOjTORzg0DgI6NM4L49A4GubQOA3v0DgW7NDEzfZ3aJxDb8ewDq2gIh1aAYU5tDJMTAaZeFvLqXCHxqlQh6bihDo0DoU7NBEq2qHpVIxDk2ePdmjFcwp2aEW4IRwah4dzaMWDBnVo6oqEcGicDXJonBXMoXE6zKFpDwLKoXEk3qGJOxTMoXH8r+TQ+Fxgh8aZNzg06kc/ZPlg5NDGQ5dDozJJ7tlYw/rRYsSPqVZS0iETtkXleCp3uqRfrzellZW/hls4NHaSrR2aNripQ2NDnQ5Nng1FdcjSFX38Wu2Wx/vd4bls7TVNxmShyn1uClE2mzrsGfsmRJ+52ntNqJ7xJoEW04HSoLExhkJjP9McGgu4ItFW9K5/vduzJyc7bOj3DBUzkY17v0tXm3yrCpjYU1V+vV6Lr3/55dP7Xb66W0zmg/FwpJVg5qfCJtbuZkmffouDOofWObTOoX04h6YvAZUG9dKi5dSOPhJNGAujdj5SM3rKR+NWLV2ehFIjWsTb1een3SHPjr4d6vXo2mWlFQQ/oVZisD6t5AbRaSXez6aVHIhMK3Fol1aSASqthCFNWkmFiTTtNvt4tBLzjNNoJhRj0UwmQKJZQWIcWgkFKrQSCjJoRpQggVYygf5MCxSnzypQX3umnzpOnpnPJ8ydmcFi1VnJDmHOzCcMJM6My4H1ZiXaW5uVqADWrIQDpJn9CPg7s5KIVGbazQlgzEp6cGFWTgXzZSXyui4Tne4pnSyhvRtruuEPYp5Pxtrly475li7jVZgJbzxGhZrxqFEVpvIZjWxZcYotZJk99nZXVow0VRn9S2SRjceTmcuEhSzBdGmwX6EGc3DPci885Nd0OIuTOe1iqVLIDtm/nbPj6Xgxg0w7qJNfnfzq5NeHk1/P2hJgyq8f5AIS/SH6lpuE6D9G/3uZIday/b2+LLXLD1MEP5tVnDc6O6wIL4jNKsP2s1klB2KzShzaZpVkgM0qYUibVVJhNku7zT42q8Q842yWCcXYLJMJsFlWkBibVUKBNquEgmyWESXIZpVMoM3SAsXZrArU12bpp46zWebzCbNZZrBYm1WyQ9gs8wkD2SzjcmBtVon2tlklKoDNKuEAm2U/Av42qyQibZZ2cwLYrJIe3GaVU8FsVom8wWYlveHggTW/p+LHepuVzNj+jwOyWVxVWTaLtx0bUNsxEl6jxXDSxGYVwTayWfaoJj3F7LG326xipGmzlqxv832+6+/T5Zf0OTv2yztQmK544Gy13050ta2WvLXTPh0nc73oKzPVS8/0CtVqbDyYjmYzzXSdvvS+5l8u7+ZYHtN5rs5zdZ7r43mucgUwNdfXPKJ8psd8u6KqyCMvk3w+fUmih+yn07/m2Wv0v0X/QE31eSW2RzN9YharVDvvJQGe2ktRsDlc6uwCVUSqoD2dl8JglJeiwY2XAiOEl2JBfZeC4nRXcYO9bJeiIGWXzgS5Lh2JUF1GiCDTpZhI0aWYKM+lxYjSXAqJtFxFmEDJZTG9HVd53kDFpT+XOMOlhwoWXAodxG/pjxZKb2nXAmy3FNlfbilSCLel2Ai1Zd58gNlSQKjYKu5LCK+l4OG1lpoJZ7UU8brUomrFeMKkVjyj5lOuikbRKD9+oI0hBzPK5HJILdoYUmGGg8W4UYqWerPczGnJE2yRoGXPd/v2kHJOQ2jpTfLnVGznKFR0lCkaRYrfMGB6/CzW2buFzLli3ypfyYtSY73mX/LiKFEDI5uHgTOzyGdVShM3KW2ldvBMzpoOJtOk7I7/kh12X869x3O+XjEt2BOVRZdSteqHdEKrE1qd0PpwQqt+QXC2ASvWGk+PVT9tu+LEGp6f5aqDYqVX3SxBEr/qJvNTYnVUiCGrg6OFWd08AH9Wh0bqtLo5YHatbgKms2g14P32G7fXr4MC3dulKTAq7tIMADN3CQ9q9F83BdDb1U0B0nh1+PJzBT2juo+DPapAyVd7Ejjnd2UKXwVYh7fFHb2+qSENt4SwG8HWDHse9m+myWCTKKBudvhvIn46NBVsphD6sP72UPMJukz99z/s09ML2zGFTofJQNjpSF7//TE9Zr/c39+/v1DrIjaTkIOwibxdY91FCqAe66YCmMg6tHis/MVkHR/pKevm2ATQlnVzBbeYdRPDpGbdBNccp/CXtIvnbEFVpkOn46SubZNeMn2IE5bcJ45xJe7FHEM7H4z5nqJs+b9lM9Ca0Bspz8uMJkl9l0m3p/jVcOi6vOw22Z6y+2gHA/qXKF+N4znb3KCFIHVugnCbJRXW1JCkt+b1kUytyevT8hBpF4RAkjSOqXvbbEJzyRJWtu0E5eUwYXFerz/L7+q7UPTLQzoL2lnQzoJ+PAtarBGm9fzu4eH7SFawUgbfD9lxTx0ls+jH7PA1X2afotdDfqJ3ztS8LZIt3v4Q/WmdHr/49mvTVq1WeX5yvKcAFZcFXNuqQgsjOGXInkJTUjACU8LgwlJyEYJSoqBCUjJxAlLdWi/hKCFIwaghQUJRIyIEoh4gJrNPvYaRglBGiRKCEgcUgJKIFH4qSKDgM5HeQq84aVxKn3p4sMJOCxSb0KfCDSLktGcKJeDKC4HN5lPXwV+wyQhDCDWJRgg0iYIJM8mDCjLJDCLEJDu8AJMT4YSXBN4guCj7jpup8XAx5GbqvF9RoeXqc0p7St4lg1gXXFPK43Mk8ZEnm/HKVOqzNqD/GgkuEWozoWWMaSSwzNluzuArP4xogkp+k+06ULiqhO0++euaKlentd+KqpoOkkk8pp0MlKp6o9ZtF0WVPKDTVJ2m6jTVx9NU8uVflVT9+D6O0u0qYsaqn9wPovTxeGLbCdAWKGxF8ag5fVGrUjsRxUZ7aiiOAGfdcWYYBcXRngKKMzD6iaPg8olTEeqJg6DiiRNx2kncTi/pxBFI5VQAQcKp4CF0UxkcSDZxIFI1cSBKNKnoQNWjfLlFbpcpgEegYhJnLIDegkmeLlAvFc8fLhusCBKsljg3iFgqniKUVlKXACyVONZfKXFMCKHEwQidpN1qQPYVp0FVkrgRITKrODm8RuLT4CQSx11TSKSHkl4yeKBW/axxGddDDoUkjplRgpTsXFbd2VIcQttaUsf/ZgqJBdpMIGkjGukjfabb5REbZeQ26bWfyXTi3KZSyxVSO1fSt65tUdk6uYnYN+1QWSY30VdG0zIt4LsF/SNIBehwPJpOY9rNQAoj8ZtD7BJam92kH9SJo04cdeLow4kjfQlw1nUel4d8T1tPvuTLl2iz27JdJ4/Rt/npu/NjJEbznmbHfbbMn3LasZK2rTz87vj7/v6w+2u2PNGXhWaSq7BI8GV/Jjgu+v10n7NfUi/nx3t6W06/WGlvy76RhWksZq1cU0Hw800lBuucSm4Q71Ti/dxTyYH4pxInvpLSSH8PLDRS4wqQkgzwUCUM6aJKKsxHabfZx0mVGKCXMqEYN2UyAX7KChLjqEoo0FOVUJCrMqIE+aqSCUyM0gLFeasK1Ndd6aeO81fm8wlzWGawWI9VssVXvA5TiKftefOYHURFoSgy9Fjn2RMG8lnG5cA6rRLt7bVKVAC3VcIBfst+BPwdV0lEei7t5gRwXSU9uO8qp4I5rxJ5zXtR4zISVuOHJF4Mk8UwrvFeqjZwPKfaP0fqFO9/Nhg/DIaLMdUG8hZpt9YGFsE2cl/2qCb+yx57e8VfMdLwYHfssxF9NNI/BemfkcrbUSZYTahjfTXBihTaa3paUmHhUdky+tY1Wxa6w38py+wO/4Yso0grsmxF7+jXuz2dN8nDDV0ISmM43i3e79LVhmr5ZFc3ZlHLr9dr8fUvv3x6v8tXd4v5fDibzuaFLfunjHfn/mZ9fvzj+bT78/Yr7Wy5u5hwVT+kM2mdSetM2oczafULgunV/hgd881+nUXsnTBLzFrn2yw67Xbr6PSSkmnL1+sopVVok57yZbpev1ENIVuPIvo6WqbHF3HcY0aA7BilX9Ocfs+vM89krvr42zVeq+H5Cbg6KFbH1c0SRM7VTean6uqoEHFXBxdvS3Aar24egNSrQyMVX90cMOFXN4FX47U6KFAGXpoCowYvzQAQhZfwoMZrdVMAJWLdFCClWIfH1V3WzQDUjXVTAJPmrkzhqyLr8LY+ZJ+u5fcae7i6OaB1nHWTKKOIa7xWN5P8/QZVmHVzAYVm/RS8kRuu8VrdRN6ysw4cQH3WTQUQoXVo8Vj5a9E6PlKS1s0Ros60bq7gArVuYphOrZvgmlylgtIx1ZQ+xKPFeLIYDl1ytThmuhhNFklNXarAiEP4xqu3ytWa0Bup1suMJuL1Mul2DVvDqU1OjOdO26rZyy43sbCt8Wg2Gk7ZXh4yOXGdP76lmzUTFnWN18pDOp3a6dROp344nVouAKY+/Ut+OFC64e4pUn8j+7qlNGe2nrCGA305ru9pQ7UlqlXCoQpDNLz8dMcEZeOPVQqCtZuKGsRmKrifvVQUiK1UMLSdVFyAjVQopH1UTJhtLG6tT3KhggBtoo7E2EOdCLCFRoCYpEKFBNpAhQTZPy1CUDqhIgLtXhEkLpXQQvrau/KkcWmE+vNoW0Dltlr/rsLbOBVuCPumP1Og9EHtjmHtmgJ72zQFCmDPFBpgy8zb7m/HFA9pw4pbEiBhULGD2y41EcxuKeB1mxVTml/Muqwl00XMc/zsEtlhjx0zZNsIDCfUjM2RKmge0qzLmgy1kb0yxzSxVdZsNxfKynGGjSpSBGs//ohNAoaxcw/Vq6bK3kO1bUogTRS6fpZ99uvF94lfTmAcT2eDWVKW0K7f0penZ9bCrt5SFYd0lqqzVJ2l+niWqlgATEv1T1l62Eb/ZXeO0ug7avqfraM/kbX69pBRht+3u93qP0T/8BMlMOesFoby/Hbb6E/sPURhrVpWymprVjttJc7HL0lPBgHuy6aoYbSVPG9PbSUpGG0lYXBtJbkIbSVRUG0lmThtpW6tl7aSEKS20pAgbaUREdpKDxCkrSQSqa0kEqWtyghR2koSkdpKBQnUVibSW1sVJw3UVtrziNNWWqDYylf1+yqIttKeKZS2Ki8EWFtJsL+2kqAQ2kqiEdpKolBJXeoxgmordUtCaCvJDq+t5EQ4bSWB17UVlaYO4wfW1m0qu7Y5tFXMtdWYJWoNeIZVdffLWS+eskJZls7VqLObfCiaaStxenJMI21ljLw9qar8MFJuDqB3eIsTkkPVktWrakp8oGLpQy/p8bN4oaliT/ad8lUsq0HZN1/zL7k6yNi98lcQVJv0eOKd7jxKVmOqWI3H81JPbdJVftxtPz9nu7/S/17SVNVDO13V6apOV304XVVdCExt9W22+8cf//M/R7TTTUr1qVR2eqAtb6Knw24TfZOf3lja1V/EuvN3R36Ur7CqRtSu2tTi+AksG4bNv7LpQYSWPYmf2LJpEMFlQ9Giy+YDhJeNRIovmw0TYDbYqzrUhgGFmAuNEWMuMkCQubCg6k8bDRRmNhokzmwsrsrTJgNFmo0GVnXWoH3Fmo21RZhPFafNhlZv2nB8npg9QwjxZs8BrNKsosHVmfYE3kLOBgYQc/YUAEFnI1GizuYihZ3NDlFtac8RXODZE8JEng2+LvTiAW9ZN1iM6D9nyzpKMiuOSeqEnnFII6FnhdxI7LnHNhF8bsLtos8az8QctSbap8/Z3cIQfpP5rFXdpIB8JNs3myfxdFSWTG6Wy/SRt3iqq5gsjujcXuf2Orf38dyeWiGsesnlN7RwsGZz1HPuJ+bwqBno8kt24Ls2fP92evHeBrRcm1rlnInhnsaOnzw440wGFsbPiYA9tZyAYGycYMElnMAi3JsgQZWbQOJMm7ypPplm8qFDejURFSOCdFoJRFg0LTxMlpm8hEhnJmJEqTJBAxoyAUSKMRkiLsFM3RTM3qDF0oxLL9NeeLZUa10UqYWJTS6T4CCKq3yYQKll5VXAZpZJrr/HEmccQl8JMsJaCRJMVgkc1FEJZBA1JdDhjZSYByeiBO+af6KtQke9mLp60Tagg0UycdVBqmPYtgqzRTx2JJRph1Da2ahRVy/xUmqmnfjJtUgnM+e6uQhSDDPc0t3+jfaO2/PPMLz5C/t3vzhQFEDGo6RVllnx0UjXTrdtIyqP+i2mmY1mw9k4oY0XZKuuTf7Tk8peq1dP2kGdfersU2efPp590pYAU0AVGWKigrzp3p/GAtTOL6nQPBVTgQGngxXcMKKpwHu6poKD0U0FDm6cCjJCOhUwqHcqqDj1VN5mL/tUYJACyoCCHJTBRGgoM0iQiSqgSBlVQFE+So8SVPVYLNu04eP2dMgfaUObAytv11KsGveYKqHIRK3y7EFuqgDaHskrOct4Pm1ye0NlBAuWVAU7iKfSIoft/ak/tuj0qyJef2FVoEI4qwKO0FbWI+Dfxqu8Q1B5Vd6cADWRZczhFVZxIjiLVSCviSzq1DXpDQcPg8EiHi4SZyIVWSq192ccu9vTi70/eV+w4ZTqJ5u0py8udTOXpU6xjc6yxjZIm1Ij6xOmRlTvV62QJKFlb+pJ37q2qedt7kp8SjPUFe3R2bCF18VdPSnUyq6eiArJZDgcjWdEL9UV7QhKrXUuZk3lPxUHdeqqU1eduvqI6qpYAkx1Rb9MxE+i/EibbmbRJs23Ed+9s+zbRSWR7EcPb/ss+vOf/xz97r/d/UWN+293v48OGY1aU77V/rA77cjx3PsbsXJda2vEBMHbiEkM3IhJbigjJvHeRkxyUEZM4gIYMUnGGDEJAxsxSUUaMXWbPY2YxGCNmAaFGTGNiTFiepAwIyahWCMmoTgjVkaJM2KSiTViKlBgqpb69dWXms27aLEA2t7K04hpz6dN9jFixX3asF/zR9zGksUbin4gI6Y9YajkLf3egfO3CjTCiMlTD2PEJBxjxCQMlstVXEawEZNxBsnoKmL+NYyYPBGkEZPIa0aMmoDNSXg9kA4bjmTalt0rTDNigzmJM0dql8BQr7DhYkypXTz7iy2d4o/p9NWi36f//3J+vKd1r3/Mnzfp1/xwPiajfrHmNDVi4hTbGTFjbCMjJkaaaV7lKWyzE/sbUv4zVRZOk6Ezs6uzY9Rqbr0Wzc6KTRinyWwwiuelHdstv3wWz8zndJ9fdGSVQztT1pmyzpR9PFNWWQhMX/bHaENHRN/mp+/Oj9Efv/9z9HrIT6dsG5120Sk7niKx4AwpZzdKn0mmHdlyzv7YcLdo2fGezWitY+2cmMnxNGMWDOzHLHoYS2ZN4unKLBrGmFlQuDez+Ah7ZiGhDs1i40ya/Sh4+TQLhrRqDjTIrTnICMPmwKIaiFlopG2z0CjnVo0YZd4sMtK/2UEDLZwb7e3iKhcDWELpeJ5xXs4RONjOWTMEcXSVs8DlrlXQ6Aw2awJ/a2cBQ7g7awqEwXM+JoDMNosLtXn2rQuR5WbNEd7sWRPi/J4Fvmb5ErZJZRIzPUet/Aez2gJOajI2GNMBiwHvDlbdESDuxXQIWT7aFIDvh3mz5TNDbub6nGMbNRBzEhp4P3O8af9eTqf9kQnOF/JU9y/ZYfflnO73zHQWLpC647sS5SgPzU6Uo29dS5Rru9XlrXlydBzPr7tb2HlyWrz8h0Hy5Kaz+XSqbSRAr1MSx5cEYHFE5/0679d5vw/n/YrXv6n7/kt2ilL2M0pue80eaU1mnu+4O5yit92ZdrsUHlC8jY4ocy6NNm+HPF2xbQS2u22PPpRuV+lhFb2mb95bX5bLWCv/J4b7aT/JwNo+CQ0i+STbz+1JCETpSRba5EksQOBJEtLbSSRM16mb6mPpJAMo5zQixslpQICK08PDZLpJIlC8SSLIt5XxgTSbBALtmgoRJ9VMoq9LK84Yp9C05xBmzrQwscJMgkN4Mu1hAiWylVcBm8Umud4yTHICODBJBqgv44b7Gy+JQ4oudTcC+C2Jpv/Jn/Il37T9+P73x3y7zD6l6/UneqxO+TLf00+2z7/Q52nhoxpXuct5YDZL8q5JrGFvEPeSOau6ZPWbPMfMTlWjLvisOJNJrJHKQ3NJrBLTqHhTRNrIXRlDmigrc66bu5CJYYagMjrcx86UtGtbWn68/vaD8TAeltlo/7z7/MfnjD4Mfv5P6enzj/nzJR3lOrgzU52Z6szUhzNTrqXAlFT/lG/PP0WP6SmirOhtuuZt71nB5j/vIrHkRD++7F6j372+vt7/8058i32H/X3h92wZ8slOc8XXboPLCslPVVVxWGtV5QcRWNVp/FxWlQfRWlUs2nBVZwDIrioU6b2qdJgCq6K9Nr2s4oBizA3HODI3G6DL3GBQ7loVDpRoVTjIp1XBuAb/VTbQslXhwO5qtXBf91YF276MpU7I7zX+DF6ls1e8PQP7N7NTALxC4WpNq6cQwtNVZwFuiemCg3PaqlN4i7wqMoDTq04C0HtVKKpGtUpGSr8qPUTNanWW4CqwOiXMClbR1wThoBdTHSpPTyNHGPMMNlsQUi0recSEZcJR67YBT2GzBCExZizLLaFtNGeLcaNtCipBN3KFdaObaMM6xu25bhWCIRPvXB9D6QhR8jqaJk6/SJtq2nlu9C0tz+0bNkl6/Cxez6I0VHynXDYWZd7ba/4lVweFbAVHQQZJcYvHcUL/UU6g7AW3W552X/LT/eFinptxVGcUO6PYGcUPZxSNNcBUiT+cH98ow223ppWk0IgyyY2KXQtX2G6jA3OJapXDViL85KDGwVpBDRxEB2p8Pw+ogSACUOOhzZ+GBig/jYZ0fRoWJvn0m+2T66ZxgFrPomJ8ngUFiDw7TEzum0YFqjuNCnJ2ZpygPDgNCrR0eqi4fLgq1dfLGWePy4uznlOYibPCxebHafAQ7s160EB5cuYVwebKaWxvzaaxAvg1jQ4Qa5UHwT93TkMiVZp+hwLk0Gn44PJMmwtmzTTmNV3Gc+Xi5GGQLIb0n1OX8WMS2jCBlBq1fuMurJJPxzBk3ZJFQodwzK1FoWW0jTxZZVgTQVYZfLsZK4eaSowVgFL9p/oxnT1rdJfviu8cHvuFIpvHMWXbVfdMuJaCd8c+3VmW7LYdE37Du33Gg2k8GAzL7T53h1W+TQ/sQtTu9qkd0zmyzpF1juzjObJylTAN2cMh3R6faNOVUxal1PrtZZNRSjwr/ZSrq0imaynItLWpnR6TAE85pihgNaawYcSYontqMYXBSDFFgysxBUYIMcWC6jAFxcmw4gZ7qTBFQYownQnSYDoSIcGMEEEKTDGRAkwxUfpLixElvxQSqb6KMIHiy2J6a6/yvIHSS38uccpLDxUsvBQ6iO7SHy2U7NKuBVh1KbK/6FKkEJpLsRGSy7z5AMWlgFDBVdyXEHpLwcPLLTUTTm0p4nWxRTt4kpFihaLzxcjZ7YySwCrHVMQWO2TE8sBoI9Axx9wstmSszbSWOaiR1LLmu7lcVHMlL7tNtk+faeMCvWB0Mvl1ZZVje08yYw2396QRu322LbLJNLd2t6B/BMnpmswmk8FwXKR0UZ318qVHbzO+ZodTdrhkrKqHduKqE1eduPpw4qq6ENgbGByXh3x/Yn3M5MrCa0V359P+fGJty+g3VMQpGe0Iuou+e2aJYJv05LupZzWydmWiFsdPddkwrPGy6UHElz2Jn/+yaRANZkPRNszmA6SYjUS6MZsNU2Q22Ksk1IYBhZkLjfFmLjJAn7mwoFJQGw2UaTYa5NRsLK4I1CYDDZuNBhaA1qB9fZuNte0Y+yTZtvjTZrPXts1vXfppw/GFn/YMIVycPQew6LOKBpd82hN4CzobGMDT2VMAdJ2NRJV62lykvLPZIco87TmCqzx7QpjRs8HXxB7lmVEHOL5Z6ThZjHnxpqPAk3eAiycLqvFMXAWeBYY2PCVMow5wVsiN/J57bBPN5ybcnsBmjTez2IoMtXjgrOFst1fBbSlq4a1fqM0KRpPJKBnRBZOFnPtsTb0XtxdtX3FIZ/k6y9dZvo9n+YoFwLR7P56oNesyelzvniNqNpkd0hP1gqPktP3b6WW3/RSdqZnrc7ShHQlo5egf2Ialx7ftKf2JLTe8DVy7zDVt0WqVuCbHe8o8cVX6YIknqWHknYR7SjtJwcg6CYNLOslFyDmJgko5ycTJOHVrfdLV1OsCKd9kXAwJkm4aESHb9AAxqWrqMiLlmowSJdUkDijTJBEp0VSQuCy14s4IpLc0K04al6OmvwZxkkwLFJuhpsINIsW0ZwqUn6bCpSuLTU9TYH/5JU86hPSSaITskiiY5JI8qNySzCBSS7LDyyw5EU5iSeB1eSXSyWgDzkRtTWDLK77FwYC2OJgsxrTFgVteDeZ0FK/IHC4GfBeEW7PS5GuqmbQSpyfHNJJVxsgGkkqMM+WULLFUZ0CPyeYtX2Xp/e7AWvGL7mPJeESVgtXSys5cUdHuei0+Hf7yy6f3u3x1tyBzNZyxdm2muepRPskm47vd0ZjP8ofUm3yTfs0P52My6su7UB7ZeazOY3Ue66N6rHIdsIot+ULCG5HJFQOjqbQVysdWSQxEWilWEHel4CEVlpoDYrIUDCm0FDOQ11J4nN5SxACWS6HRsqt4CADOS7Hw6ksnQw2YDsaJMCNcqA9TZLwWU2SsHdPiBRVzmm9EKQdqezrkj2f6qwl7/6oliTVugG+Rkflm4uNNcTGg5kxRbdHllW1mBoxNNjPZAXLNzAkCWrXy0m9PWLmm3dQgjk3xUapN8cIZNzUDTrwpIti/KWwADVfctQBlotbq92tJOXVKaDenuDcrOsovixfDmh1GC0U3mi8GQ0dHNMo/m/QSqj8lBqWgxS0UnYy4jakzh7YQdtbcN5eSVqxQWVB6J/Xdarc83hvurp+us5/yo1JKZZu00XBI3fFbuLx/TL+mP/IiKWYQtS0F/r1noo2ng2EyKLcs3Wf72WWLx3/eubvO3XXu7gO6O/7qtxLQ8s1+nUXf83Sz6Hh6o39QJenyS8bT0Hbb4mdP9K7D2+aJ9amlw9vPfM0dEdC+jpCBLB2Rfd0cIUBGjkh4D0dQiH0jDta5ERBo2tiN9PNrRIBaNclDuTSJgxg0FRrKmxEPasuIB3NkIjaYGSMc1Iex8JCJYyXPP2uMnysyZUw+dza0fVElvRfnIaKTxQgbxmnJxwdmssT5o/0VUQHWiihBXBVxIYaquMn+LcvYh8I+1kaxexDEQRH4VzBPNAvQNxHtBstEGVxUxUjlh5TENaqpYhz1ktFDPOWJYHOHZWLbWPZias1PP6fdLjnm9kSw/ayhWyoGNDNK5TwNPBL/XKDZI/a3nPxnakw2SaatnJD4QPPBfFBMQmgynmlCKN9f9EH8x50O6nRQp4M+ng7iL3672RjbS5Lnb+Vb+ti0XrPqw3S7ogrEbfrM/iFN0T5dfqHOkTxp1KcMUSxQ7YRQvvf0QQQA6yAihrFBBPaUQUTAuCACwVUQMREmiDBQEUQ8nAdit9BLAxEAaYEkDiSBJA3hgFRgIAVEOKQBIhxKAInIUP6HaEj9w4ID2p8S5y1/+IkC3Y983mxme/UjAwSbH6IGET/yuUF5H3HyYO1DUH/rQ5AQ0oewCOdT3F6A8iEW1Piwyx9C+BA3vO+hSXC6h2DXbM+Il/RRPyoq+5sukjrbE1Nrq4fBiBKKqNm8w/ZwjHXIzbYn3zeTPcXxjVxPOcvtqoe/4bfyhI60leKeYIcsXVEtGs8Z0qv84mQ+cTao0rq8U2vF8/bEe72rX893izsPDfQb3kNxPhxOByNq46/q/Hbrt+1uk6fr4/3+4kaKe/vITg51cqiTQx9PDtnrgJU1tCE1FO0Pu79myxPXRU9n1qxqv0pPVP+XHqM/R6/pljetX+1Yv/pNIYrkunq+dE0P2X537JsVyHZELZvRGxhPf2SywCrJhIexSuYcnoLJhGFck8mEaycTjzBQJhEqo0w0zktZD4GXojJZSFtVJYPEVRWMcFhVKqr9vElGmi2TjJJclXhRvssEI9WXFTLQgjnJ3kLMvhJAN1Z9jnGarBo22JiZEwSRZ/Y54CoBbTK625bJ97drJi+EaDNnQDg31wMC0G8mFmrirLsWQsqZU4T3c+Z8OFVncq9ZO0quGvHkKtJxyWLAW8TbzbpIydF/Q57HlVCzeYe10zGNKwGNiJsJPNfQRi7PBWjQwcsYbhg+fWvJeNCuws+p8UTjY1bvVy4Fshsy++Zr/iVX3ZHFZ8XSECI3lwzVZn4+G8TxqMzl+v7tT73ll0vpXMURnbTrpF0n7S4JpvMxsy+Q+PT/3t8f8q/p8u0XeqUdsmWWf81Wn8XPLrcUcSCt8UQ8ve0pqfXuX2h6+tcxP2Wf09Um394tuBb75dMdn/5EB6ni5dNmbU1MH6tfzo/39EbcVGTF699O6pI5W7zUj9UjUM95KvajrSPZRpLZcUd71VITetJ5z4eUPjtQlpf68Bf93X86pPn2T+fll78rDF67jvPl+tUq20sM9xN2koEVdRIaRNBJtp+YkxCIkJMstIiTWICAkySkeJNImHBTN9VHtEkGULBpRIxY04AAoaaHh8kLk0SgQJNEkDgr4wMJMwkEijIVIk6QmURfMVacMU6Iac8hTIRpYWIFmASHEF/awwRKHCuvAjZ3THK9BZfkBBBbkgwQWsYN9xdZEocUWOpuBBBXEh1cWMl5YKJK8m4QVGPWBj5JqPRPpozZgors07gXJ6wP1WC8GPPUs/35SClVn1PKjbpLBrE4ZPAQzxfJYDHidYa3ppWJSBuJKWNIEyFlznVzfpkYdkFA/ep5ZOE3OqSUt1X2lJ7Xp8/iTSrd6U16pE917PZnhw39AqAPfMe7xfud/LQpgmKPhlJkjnbx09lkMNTbS709rdMvVxrFl8d0FqqzULZkYd3dDtnqvc8fjl/eKZl2v2OqRZYa8Hd8x8aixRhNNEoeTbf5z9xzNKfRaFbXxpOQGofCR9Holsrot2+h9uUKYHuoo2g2JUVT9PqSL19Et6lj0YFqdz4ss4g1mxJ95LPDgXr73ke/2z095UtKYY2EvP89XWOvykNtMWslpNR5+impgoKVUgU2iJYq6H5iqsBA1FRBQ8upAgzQUwULKagKKExRlTfYR1IVFKCmMpgYUWUgAarKDBEjqwomUFcVTJCw0mMEKasCCZRWZZg4bWUzfcWVdt44dWU8lzB5ZYSK1VcFOoTAMh4tkMLSrwVWYhVkb41VkAKIrIINUFnWzfeXWQUQqbPK+xJAaBXw4EqrmAkmtQriDVor7iUz1tSKNklM+AaIDq017CW0SeJwMZothjW9sSqH3Kq1VKyNxJY1qInasue7WW6pgYbe4p3WWQXlOj1vly/7dHW/zU597Vi5VWJXQikyLW5yX6PJdDYcUm6XKqHkDZJ7z2fagpJ98qzdKNE8rnNgnQPrHNiHy8Tam6uA6cFkNtZjdjxRzlW6POVLcl18ZXnc7b58il4P+Yk2FOJ1ld+dqfMW6S9v22UuXy2NVwnxtV4aCW2+NHQg+6XN4GvANBTIgmlEvAnT4BAbpvGwRkwDA62YfuP9zJhGgtoxi4syZBYWYsnsUFGmTONCbZnGhRkzM1aYNdOwUHOmh4u0Z1Wuv0EzrgHSolnPLdCkWSGjbZqGD2PUrMcOZtXM64I2axodYNc0WhDDpvEhlq3yUCBMmwbF2jb9XgUxbtoEv4J102YDmjeNes2+8Y0LY9q4cLYgASf2NrTtGyt5ZMckVBnJ/nMklbkOud2+lfE2NHCVgc0sXGV4g3pH8wOe1s+MNy/TP/+ZncwGo2HXz57KnW6ScPFoNhrOhpTfVli4t3Szvuzf5BGdeevMW2fePqB5k69/07n9JWdpZKzkUe5LS0s9rdLsWLY+019L2JdsL1q/nDK1PLX0azwIXqxOkTAvdjn90NUmTZwI2qnxwALZNM729WgcAjJonIV3ZxwLsWachPVlHAk0ZeKm+jkyzoDasYKI8mIFEGLEyvBQLowToRaME2H+S8UHM18cCHVeIkSk7dKJ/p5LnjHScBXPIdBtFWGirRYHh/FZxcMEM1nqKqAdFucC7BXnBPFWnAwxVtoNR7gqjsNaKnE3gvgpjv4VzBSfB+ikOO+ajSLNREIqZjYqmS8GiTsXjB0zZJ3zqQfXkOeLVUocjUM45nYbxSJt6KG0Ic0MlD5XgywwNqyaA0YpYLWfakQK2Hg6cskn8iuv6Yl2fSdjcHsX/b+R9luu4kd2fXrxfcIeDZ/yx3g4iemKSflE3Xzy/eXqx/KQTj91+qnTTx9OP5ULgDPnS1tC+KaJLXvhm5jmkkiO9zNNCoJVTYoaxDUpuJ9sUhSIbVIwtG5SXIBvUiikcFJMmHEqbq2PclIQoHPSkRjppBMB1skIEKOdFBLonRQSJJ60CEHmSRGB6qkIEueeLKSvfCpPGmef9OcRpp/0QLH+SZFDCCj9mQIZKO1CYBWUAns7KAUKIKEUGmChzNvur6EUD+mhilsSQEQpdnATpSaCqSgFvO6iaPvFZMw80zBejJy7OJKvoi0aaadHaqSVLMauzChqt8XLG6nXVjxdjPght7ooGWojGWWOaWKjrNlu1lFynNNHKebh9LQy86CGThNF9Xa2iaJvXdvPsa2JInTDRvA0YrfPtp/Fas83m1Tx3i2CNYKP4+l4Wu7mSH/1X3+m/dZYskJdGaJ2TGeiOhPVmagPaKKKVaLShquye+N+nb6xtu/pgTbRXUWv1GA+SiO2iPAixMP5ke8a6+esylWrVXaUWtJ8rZUIo4/WVhIbyFtJuq+4khiQuZI0vLqSYIi7kiysvJJQoL1SN9hPX0kK1F9pTJTA0pAQg6WHiFJYkgl1WJIJk1hljDCLJZFQjaXCRHosk+kvsorzRpos7bkEqiwtVLTLkugwMkt7tGA2q7wWaJ0lyQCfJUlBhJZkQ4yWcfMRSksCsU5L3ZcgUkvCfwWrJWcCai1JvMFrDXtD6v8+ZtV8I2eOVbHPIRmrZDEaO3OsqChQYiaLuFEbefVOvqHYEicoBzUzW8bQ26v8NItSVviZ+xk6NdbVhKofxAcqtk2hUkltJRbN1VBi0Yh6ieVKp0L0kqd+WuOJ1k/rkP3bmRrgsDqXCxKrOKaTWJ3E6iTWB5RYxQrgzKf67uHh++gHuZRo/bL+1//4n/eFsGq3XaG+QLX0VSJ2X18lKWhfJbGBfJWk+/oqiQH5KknD+yoJhvgqycL6KgkF+ip1g/18laRAfZXGRPkqDQnxVXqIKF8lmVBfJZkwX1XGCPNVEgn1VSpMpK8ymf6+qjhvpK/Snkugr9JCRfsqiQ7jq7RHC+arymuB9lWSDPBVkhTEV0k2xFcZNx/hqyQQ66vUfQniqyT8V/BVciagr5LEa76q6FBFsmq6GExcNYHkq8ZMRg0Svu1h7PBVdMi0N6CdESe056E85PY8LBFrQ19lDGrmq8z5GqRiiYFmLpbekUp9qjGSsSbT6dxVF0huy87Gom9dy8ZS+9aT2ypf5rLfExNer/mXXPV/4q1OVM0h7czY0GTRiHqTRaGG2RVxNJ0O4qlWFiguem+VntLekcooN9eKBN0DOsfVOa7OcX1Yx2WvH6bw8k+/ci86YgU+X7rqji5T6teIETNGdJnIMNbLnCOoAjOnwvgwkwmVYyY6lCkzZwFqMxMcwqGZM8CFmvW4IOyaiQyg2qoTYL1blQ+UcFX4CWvkzAkC6DlzArCrq0QPFncmP4DFs04Ar/ScE6D8nn158LKv+vzDzV/1JMJoQHOekE7QPqMt7dZzOvbf/7BPTy9sN3O6hszvNe7e6X5fJWn998f0mP1yf3///pKlKzaPsH2gaWDq0Lw8AT2iORFQKroeJZxhNOkhdKM5wyagezRn+tVEpDkt3Eqa+GuKktd4DqasVJS5xYFLUfLWZvGE1YGybS65xqy0LZOY8WIwXcTcYjZVlEbgrXyli9BGXro4TTLv3B9X69LwqDqS3lrJNydKKP5tVpNSVKLDMysYNfSlFm+4atJ4PI7H8YzmKtqayUt92u3Wj9n6dEtKXk87uPOWnbfsvOUlg3Y+UmvF/jF/3qRf88P5mIxkH/D3/v6Qf02Xb+zNHBXLZ/nXbPVZCJHL7+ocSGs8EU9v++xucfcvND3965ifss+p2AOX/5HmF/oVxKY/0UHqrzanzdqamH4FvZwf7+lNqHkGxXtVbSmwK03Vj1jjfYqYMn2j5Zq0DO13mVKdKRWx0+6Xu+0xOu2ix4wdIotP5QYqVhKeR8M0xxrnldVXLIAg66muFLwu1TrxME38K8+CZz//Kg9rOYurHcxwFjMg7WYBDWI2CzreahZoZgZpKXpc7x7btC20H+YQNrOIlcHBJtNgIy2mGTTYYBbwEPaygKPNpR412loW7BDGsgw8gK204TBTqV2SAJbSeL7xhtIIPpCdLOYIaiaNJxNtJfXLFCZ/sXxbhbORRdQhTWQxCdJCWo8M0EAW5CD2saAHNY/FLL+edSymxBvHAn3dNpJJTOYPSUxlt4vBzGUbRbYjbaRA+3WScOTVuZZtpEMmvWT0QNt+jmaLIReSjW2jCrqdabRGt7KMdgSNcyV1k6Vt41lwq63r4oTyDh22cTiu5kvG7JvXMibblv7GxL4pY5KOU8qRvjScoxYzOUcWbZikyfl4MJ5WpeP94fEW3SgO60RjJxptj8Zeh4ds9d7nD8cv77THzH7HbNpRvHnm72+vfNR0uDRjNNFoj8h0m/+ctqPRaPaplyfStdB6NIpGt7SCYti/B9EoFgFbMe53hxPTi/9ntt1m1Lbuhyw//fx3R2peJ2QBU4uy3YJn/zrBkyuWlzwkBkYbMlCYFElGDpoYySbApEMyElQPMmAoMcjYQCXIcCFkIOPCNSC/5QgByEAB1J/CYqWfogJ1XxEoVvQxbADFx7BguScjBWs9Rg0g9HiweJWnYVEST1wAvL5Tzytc3KmAwyg7Rg8p69TzBtZ08qKEEXQMDlNzDBZQyjE8UMeVjwNOxDFmCAXHb1PAtD/G/9W0G5sMLtwY9LpqG/D9SKmueJwsEqdqE3tAjNmepSNSbXyfiEpiH20TwTAx7WlKuX1tVBuF20qylePa6DVt1sZijcbSpdCUGvtQnv9MuSbJkLrMVQXasKrP6FuaPAN2zSMTdZM5o0BrkvXoJ+XWDxRnEG2WxMlgPB9TdbZK1ntaDuezyUVnVhzS+bLOl3W+7OMl5hULgO3Kvn87vey20Z83+zU1KdieuM5k8uyHP33DlpUo3y7X5xXbCeJrus6poQGTp2yx8dr5oVyz2lkzMd7TmEkI2JZJahhTJuGelkxSMIZMwuB2THIRZkyioFZMMnFGTN1aLxsmIUgTpiFBFkwjIgyYHiDIfkkk0nxJJMp6lRGijJckIm2XChJoukykt+UqThpouLTnEWe3tEDBZkuSg1gt7ZlCGa3yQoBtlgT7mywJCmGxJBphsIzbDrBXkgc1V+qWhLBWkh3eWMmJcLZKAq+ZKpHNRRZqxMpLRe3oeU9v4KmcKD1RDVAyiFVSWEIOirZscO1WKg4ZMcyI+u3xStabk8JEqM0slTGmkaEyZ7vdTolxhpnSd3RIps7kLkdqV8DELnJLN9mpspSURtSXkoZK6ooHSTIbxOXOpMeXfJ9frB8tjujcVOemOjf14dxU8fq31dTyfGBVoTm1Ujk8pcuMpW19m5++O/P8UK6f2u3jUK5JreSTGO7nniQDq54kNIh5kmw/8SQhEO8kWWjtJLEA6yRJSOkkkTDnpG6qj3KSDKBx0ogY4aQBAb5JDw+jmyQRaJskESSbyvhArkkCgapJhYgzTSbRVzQVZ4zzTNpzCNNMWphYyyTBISST9jCBHFN5FbCKSXK9DZPkBBBMkgzwS8YN99dLEoe0S+puBJBLEh3cLcl5YGpJ8q6ZJWpuNu4ltHHCfDFMFrEzB4q0UdyLyT4li+FsMeYJTpUcKIYZsv0XBrPFoNF+oSLSRmLJGNLEK5lz3ayVxLCafKfZ0LlLaLv2ZK23V7hVKpUpT7ZUMlKeKPogKU9TyncaDkhZyYyn426dHihtbNXbvz2zpIVLuU+ugzvT1JmmzjR9PNPkWDfsPUT5enKMVAnh6SWLflTDIvrXJoteTqf9cdFn5UaqC1q6Jke15LlR/WLB8bVUjmjbbc1QWQI93ZUdGLjesBpuGKNVOQ1PuVXhYTxXBQtXXpUZEParAoWKsAod58QqaK/6xOrDjDRllVgZHCTNnGyEP3OCQVssVC830qpVIkcJtgq4LIWg3yK6J7vcK8CxL0/1iiC1WzVwoIGrg3vLuArYFmgswUF+D3DB2YvSnoH9m73TAOAVSrcs/HcEPwWaBDBHEHHnuA2wbRNcjz3fgAG3ZUJ1Cn+zV7kkISRfZRKE76tAxSMDUH8VMtQCVughaiSrj0p4N1g5MZwmrKBvMIZkA4cPyZDaii3GvCLSzkXjWybE1H2MG8OBu2qSHSIwJBUb5aJVbkEzeWifshzdyCPWMG7fAqFyDjV2MR44Nz/QZJ3aD4G+da0V2d+KXaRQg9jF0WQwnU5Ixyq7uD+ct8/Z/f7tolbUj+p8YucTO5/48XyivgbY2WvHTbpeR2LTgui4POT7E0tgo8Ztp+iJ/c2R/YupRDKJRwk6exdWKpJYvNqltxVn5akJSw44za0EhxGDJd/TCJYgjAoseXAHWKIR8q+kQa1ficXpPu1me6XBlRyk4DOpILNnQhFKzwoTlBZXUpESr6Si7J0RJypFroQifZ0WKlDUVajehk4/e2DKnPmc4pycGS44da6EB7Fw5oOGSqEzrgjYu5Vsf+FWskKYtpKOUGz2gwBwayUSKtW0OxQiva7Eh9do5Vw4f1Yyr4kz6jU26Q3mrPqSsu3EHqG2OBOFnlOWasey7Vz7iBJm2htQqh3tRTpeDBvtI1p+pGhmzIqTbKPK7MENHFkx1JRj8qPW6+sr7Vv3vM7F9nX/X77cHVbpcdmn/aee+1QSm/QHE/WB7Hy8f6Hd7wgkupTNnVqN1JFq+6W0Gn3rmla7qcO/dG8i7WO5O1OqG9si9KZK0DJpj0YYlaBG0h6FGkSrTeLBnHtIpdXU+43VRa2mH9VptU6rdVrt42k1fQ0wtdpDvn2Lnmi70C9Rut9TPl56YjuEkkujPD1RGxr98fs/M7W2yo/7dfrGf6KWZ9bXLKVtAEjC5afd4e2+SNGTC+350sV2JVcYi1o73VYgPHVbyQHrthIcRreVfE/dVoIwuq3kwXVbiUbotpIG1W0lFqfbtJvtpdtKDlK3mVSQbjOhCN1mhQnSbSUVqdtKKkq3GXGidFsJReo2LVT15YH9jUffS6h5dlaF6q3b9LMH6rYSi02BM8MF67YSHkS3mQ8aSrcZVwSs20q2v24rWSF0W0lH6Db7QQDothIJ1W3aHQqh20p8eN1WzoXTbSXzum6LB6TKHgas05n0ZA7dlvTiGdNt1FdtzF1atbKVuvuPHhLaSHMiNwlgKcXi4wV9ZVYPHfPnTfo1P5yPyajcFmbVTLcVJ9lGt9mDG+i2YmhVt7EiqWKXm9X9S3bYfTnT5zYScJvCqcWTmavz/68s1UiJ3STVbmyvFkqqjWfDZDgvK2Efdqvd/emnExXCsjbel8xa9dBOr3V6rdNrl4yPYxfQ3/7emdWFwK6B5TsCqArYb/NtGj0c0j1tdkp7aO539M4lPZBhkyvPcp1H+8Pur9mSl+H77ApQjaxdvavF8fNqNgwr12x6EMNmT+Kn2WwaxLXZULRws/kA62YjkerNZsP8mw32qm21YUAT50JjdJyLDHByLiyoptVGA+2cjQYpOhuLq2a1yUBZZ6OB+3PWoH21nY2189nYR862Vaw2GyrwbDi+gtWeIYTKs+dgzyLI51XR4NpVewJvs2cDA+g9ewqA47ORqJpVm4u0fTY7RL2qPUdw72dPCJN/Nvi6ARzMe/GE97aLF+O63naTXiIS7oa1ve0o544MIEnCKaXuNdk1wQq5kQZ0j21Speom3C4ErfGGFdR3VZgkzmS6hGygnU3HvgdJpxM5d0Y2He2jeZP4o+085a6fNMLIptP2KKV9TCnUIOl0o+lgNopL8yes9OennN677n66JP4qR3ber/N+nff7cN6vsg6Y2u/HnG0BGj2mxxetXFUMooJVvsxEtARGb7tzRH7wx3W6/PJKDVWieHjPFyAf9VcJrp35MzF+4s9iYb2fBQ+i/aw5/KyfBYNIP4uJdn4WHqD8LCLS+FlomPCzHwKfpDuLBdR9DjLG9jnAANnnoIJcn0UGqj6LDDJ91XhBCXkWGOj57JBVAoN/Yp6b7Gv5KlcCl6DneI5th6jUXOMsRUfY2EQ9a4IQhq9yDjDBVyGD/Z7F99Z7Fi+A3bNmAMg95wPin8RnYZFqz75rAZL5rCmCiz1rPpjXs7g3aL1JL54/DMjp0XYTiasBndiyImFZe8P5YsSPsRL7eDkuw9B+qbQfaqMGdGbEjayec2gTqecE3O70zOHVRD/K86utq30+5JsdfXy837/s/37/H0thJUpqZ87sv6v7YPz4kq1ZXe5LevwsVn61GSD7Trl4yB0C2Tdf8y+5OshQgLfm/pUFtfRVfUFtqF0w4sFgMhgMSDfKitrzIT9l9KGddvS96P+Mwzr518m/Tv59PPlnLAKm+fuXH6hgVi4kEdWOHPPtMzd935036da7JZ21TLUqktUYnlKvvA7gXSv0EMPoPC10T5enkTAiTwPCLZ7GRig8DQf1dxoXJ+/0W+5l7jQQUttZWJCzs6gIYWcHiimZ1V/zSFWnRYvydBoSl41nrnnb0yF/PFNfBa3C9TG79nbL0VXBuKxAPadfA4H1dnMa0jZnPtl3+hWAZt6Zd0xsQYHbN0KnB/FxxuXGyTjzLmLLZ/Vr4q/htEhDODgNjxBwGg6VWadfTqh602INkVGnxx1eumkngzNuGvSabuM7xNJeDrS165hUWV0WHR1DdbQx2/51NHToNjJy1LaONpEdLuioZvs9aBe8mWsrT7NFJa1j1ps3jNXGOhWbzj6cnlb3u8Nzn44UIm04c+4oOyJXZefTse+FyqejIBrm09GI+nw6FmqQfLp4NI+T2ZwmL2zampoCDi+bNHVIZ9Guva1zlE4+7dbr3Su9IeTJQuxrEg2X/65YS6GR7/0d9fY6fGbH/ELI5/x4bTstB46Peqe9PI+nz/mKcdjb40O2ahyYHEdhvW4povc+e2fLgdp7zSv7fTkCNEYTjV70VIn5M99rtDmNRrPLz990Nz5DPopGi4/hjYf/9ktnqX+DXCOcJbPfPTx8H9EBh/TwFr3S7rDUfO6QpaveMX3KIkph2FKRLN02KqLdrekJ/sQ3ghBbQhzPe1Zx+yk60t09UZO7Q55tV+u3T1G6XUWbHf0Bhb9sDl/U3zCa9qorg2+ZWydO3te/8SsId2+CGsi7CbivcxMUkG8TMLxrE1yIZxMorGMTTKBfk7fWz60JCNSrlUiUUyuJEJ+mBYhyaQIJ9WgCCXNoRYSoJDe5pCKz2yQSWL0qf3GoVj7+zkxcRqwvK59Hm9s+g624O3hPJsIN48jU5QX6seKOod2YAAO8mAAFcWICDfFh+m0HZKLJBxTrweQtCZF7JuP9FfyXOAmg+xLA694r5mWf1D+O8sNi7rRE8tTqc0q9++9ogwG+XQNtYkqpaHRYMq71Xrx6dERqrNF2DXK1bui8+Om18l36yAYZZcUnqZfdJtunzxldHLlFgzoD9tGJPuGvdsujqbri2ZC0UPlnLG0zU1t13WC6/r3vbxonZLrmU7oS0nR9XR7YR8nzev1Z7c2gNyAUP+4MV2e4ujyxD5cnJl78pt36IWN75LC6T2r7ltH2pcczJZ5SLzjuu3J6m3lIudc6cldFllDuu7CJVvQ3C5ZMdj6dqVCUD6bNlY88u+wpPZLuWmU0fJNvyb/mS5Jdy+X5QAmt/Nijr/KSK12rlDMa66e6GABbNMqIQRQXA/vpLUaAqC0GQmstxgQoLYZB6izGg6ksfgt9NBYDABWWwmH0laIB1FURGEZbMRxQWTEcSFfJyECqitGAmooHh0vt0nC+ekqcKK7GUj1vMC2lAsRWUzJqCB2lnhtQYzR58lgNxaDeCopBAugnhgWop/L2+msnxkIqJ375A+gmxg2umtgkMM3EYNcVE2tQNmOKKR7LKkVbMQ17cdxL5g8Jaaj5IuZlipUtCvRDBtxCsYzVW7YooDAb6aXy+CY1i9osN6dQ0Rg6j6pSoouaH1/k1gN9dpnFkSJ1ajRIqGivhU/64fz4xubTihD//duk8WQ0SjSblG96x9NuT5tYXNx/4Kt5XOeXOr/U+aWP55fMVcAUTf/wE20ysIr+++rx+b+zLTzZ1p2kng6UNUWe6PH8/JwdIvZhK9vQ20kukfghZzqE/ZveQ3gbI2s1a6eONIinQ9JJYJmko8NYJX0GT72kozCeSSfChZMOR5gnnQdVUDoY56KMG+8lpXQS0k7ZXJCmsrEIX2UzQZ3G9PdjUIOlx4tSWToTV75oXAKk3DLCBVouB9dbd+lM21H5lDAaFxdaw2jdNnRyloEPosTMSw5L07KvC1iS6VH72zKdFkKb6XyEP9N5qFpG44ZBjZpxr0KoNX2C8I5Nnw0n23TqTdZtMGSViAn1D3MmdlHR47wnjhlT8hcveqxYt+IQti3AtJF10+Jtpt+qAxt5uOrw2/O8LOtTmjl9KwB35SIppsvZXP+ab/7pg9m36WQ0ns/KFmCs6xr9bj3lak/V2qyuypGdgOsEXCfgPpyAq6wDpoL7li8mUU6pXBHrLEiObcNF2/FMn7toK9BHKlhcHnavq97Tebui5C5f41YJqF11oonxs24WC+vdLHgQ82bN4efeLBjEvllMtH+z8AADZxGRDs5Cwyyc/RD4eDiLBTRxDjLGxTnAABvnoIJ8nEUG5pRZZJCTq8YLyjSzwEAvZ4eMM3Nusq+bq1wJXFaa4zm25V/ruklH2NhcNWuCEI6ucg4wS1chgzv/W3xvU2fxArg6awaArXM+IP6JbxYWaezsuxbA2VlTBLd21nwwb2dxbzB3Md/Qk+fLDZ2tyMjcUUkmbejJii0XA67lquaODiHMlDb8XIwblWSaETdyd86hTeydE3C7vzOHV3PrjrL1fymhyo5kyWwQO7v7XzV737+dXnYsm+wjZdYlQ2pJNqVNUWVR5k+UoHk8vvTS45c9fd6gq1Er96qHdnavs3ud3ftwdq+6EJh67y/54UAyb/fEE+d2h/yZlN462h92f2VJdq8vu2MWHam6M1rlR0qXzmh/zxX3fyn9kDUrYy33Ml7nSWszZedt2Jahyy+lBZQJ0E27k1Ujb+cBLY6fCLRhWBNo04OoQHsSPxdo0yAy0IaibaDNB+hAG4n0gTYbJgRtsFe5qA0DKkEXGuMEXWSAFHRhQVbQRgO1oI0GeUEbi0vXs8lAM2ijgaWpNWhfN2hjbXvnk7pns6HZezZcaUbcLgT2DCH8oD0HexZBJa5VNNgQ2hN4K0IbGMAR2lMAJKGNRGX12VykJrTZIcpm7TmCi0J7QpgptMHXVGHME/hoR4IxtWVbiJpYu7SWd29LSBUmVFfr3iRUwwwHtP9BkyQ/K+RGrtA9toksdBNut4XW+KouJFv4182X7Y6ySO632al/3D2dXukzZt++VTRU1ObGiXNbg6SaHEjf0jY1+KaVPZQfXsVHz+XuvKWefVQafNOOBmQ1+Tg+on57UAozzIYGyWw4T0bjwh/+nB12l6Sh/HlnCjtT2JnCD2cK5avf1IP/lZaM6C//V7RJV1mUpUe5i0EaPWWv0euBCcEDZQYeaGFcRfu3nzf/xhYYjz0J1BrVqsyWDfbze5yAlXocGcTkcbKfvuMIiLPjJLSo41CAneMcpJLjQJiHEzfSJx2PE4DGreBhNFuBA7i1MjRMvzbOA1o0zgOpMxUbKJGO44CSTISHS5rTeb46TJ4rLkGueO5ssdY6La4IEZsMx7EhFFfx+IC8ljp/bFkqp3obLE4JoK04F+CqtJvsn8bGYUgrJe5BgJQ1Dg7un/gsMOnEaddMEy8VjccPA7JI08WQN2izTZPrmGpSmsDEixElpTUyTSzORnpJG9DEKenz3NzHjQ0y7VEphAYx5Ui1aNb2sZLK/t//H+yZ7+7gcwUA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"213504bc8fd938c5ea366bbc0281da98\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4929", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "42707356:0240:620619F:53B8AE5F", "cache-control": "private, max-age=60, s-maxage=60", "date": "Sun, 06 Jul 2014 02:03:11 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1404612248"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/user/repos?per_page=100"}, "recorded_at": "2014-07-06T02:03:12"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 52ad47e71..3621dadce 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -224,6 +224,14 @@ def test_repository(self): assert isinstance(r, github3.repos.repo.Repository) + def test_repositories(self): + """Test the ability to retrieve an authenticated users repos.""" + cassette_name = self.cassette_name('repositories') + self.basic_login() + with self.recorder.use_cassette(cassette_name): + for r in self.gh.repositories(): + assert isinstance(r, github3.repos.Repository) + def test_search_code(self): """Test the ability to use the code search endpoint""" cassette_name = self.cassette_name('search_code') From 2ed8128c012c9efb949b9771032ebfd86a8f1514 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 5 Jul 2014 21:05:47 -0500 Subject: [PATCH 083/972] Test GitHub#repositories_by with integration tests --- tests/cassettes/GitHub_repositories_by.json | 1 + tests/integration/test_github.py | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/cassettes/GitHub_repositories_by.json diff --git a/tests/cassettes/GitHub_repositories_by.json b/tests/cassettes/GitHub_repositories_by.json new file mode 100644 index 000000000..3a5269529 --- /dev/null +++ b/tests/cassettes/GitHub_repositories_by.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.9.0"}, "method": "GET", "uri": "https://api.github.com/users/dstufft/repos?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"4bacc2b54aebc0dd2574e33d70378dea\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "42707356:485B:6140499:53B8AED2", "cache-control": "public, max-age=60, s-maxage=60", "link": "; rel=\"next\", ; rel=\"last\"", "date": "Sun, 06 Jul 2014 02:05:06 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1404613771"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/users/dstufft/repos?per_page=100"}, "recorded_at": "2014-07-06T02:05:07"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.9.0"}, "method": "GET", "uri": "https://api.github.com/user/145979/repos?per_page=100&page=2"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"eeb430e4daaa9960535ec389d30fe2b0\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "42707356:485B:6140538:53B8AED2", "cache-control": "public, max-age=60, s-maxage=60", "link": "; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 06 Jul 2014 02:05:07 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1404613771"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/user/145979/repos?per_page=100&page=2"}, "recorded_at": "2014-07-06T02:05:07"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 3621dadce..766f0e486 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -225,13 +225,20 @@ def test_repository(self): assert isinstance(r, github3.repos.repo.Repository) def test_repositories(self): - """Test the ability to retrieve an authenticated users repos.""" + """Test the ability to retrieve an authenticated user's repos.""" cassette_name = self.cassette_name('repositories') self.basic_login() with self.recorder.use_cassette(cassette_name): for r in self.gh.repositories(): assert isinstance(r, github3.repos.Repository) + def test_repositories_by(self): + """Test the ability to retrieve a user's repositories.""" + cassette_name = self.cassette_name('repositories_by') + with self.recorder.use_cassette(cassette_name): + for r in self.gh.repositories_by('dstufft'): + assert isinstance(r, github3.repos.Repository) + def test_search_code(self): """Test the ability to use the code search endpoint""" cassette_name = self.cassette_name('search_code') From 00785982062ad998e35f3dbbd7ef666a68d06185 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 06:53:29 -0500 Subject: [PATCH 084/972] Fix tests on Python 3.4 --- tests/unit/test_api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index d320e9e4f..0ed65a27c 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -1,7 +1,8 @@ import github3 -import mock import unittest +from .helper import mock + class TestAPI(unittest.TestCase): def setUp(self): From eb89cc9dd6c9a5895c24f490fa414eba9370fc46 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 18:24:54 -0500 Subject: [PATCH 085/972] Update docstring for github3.public_gists --- github3/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github3/api.py b/github3/api.py index f962a29c6..97ea5770c 100644 --- a/github3/api.py +++ b/github3/api.py @@ -200,7 +200,7 @@ def followed_by(username, number=-1, etag=None): def public_gists(number=-1, etag=None): - """Iterate over public gists. + """Iterate over all public gists. .. versionadded:: 1.0 From a49580e00ff3bee76cf74dac0f267e4bee6ddbbf Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 18:26:50 -0500 Subject: [PATCH 086/972] Use a better parameter name for github3.organization --- github3/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github3/api.py b/github3/api.py index 97ea5770c..471c64f65 100644 --- a/github3/api.py +++ b/github3/api.py @@ -393,8 +393,8 @@ def octocat(say=None): return gh.octocat(say) -def organization(login): - return gh.organization(login) +def organization(name): + return gh.organization(name) organization.__doc__ = gh.organization.__doc__ From d4911c4dd0587bbd59af1afaad6e0df945999413 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 18:39:42 -0500 Subject: [PATCH 087/972] Bump version and remove need for flake8: noqa in __init__.py --- github3/__init__.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/github3/__init__.py b/github3/__init__.py index df6bfc136..35147696d 100644 --- a/github3/__init__.py +++ b/github3/__init__.py @@ -14,11 +14,28 @@ __author__ = 'Ian Cordasco' __license__ = 'Modified BSD' __copyright__ = 'Copyright 2012-2014 Ian Cordasco' -__version__ = '0.9.3' +__version__ = '1.0.0' __version_info__ = tuple(int(i) for i in __version__.split('.')) -from .api import * -from .github import GitHub, GitHubEnterprise, GitHubStatus -from .models import GitHubError +from github3.api import ( + authorize, login, enterprise_login, emojis, gist, gitignore_template, + create_gist, issue, markdown, octocat, organization, pull_request, + followers_of, followed_by, public_gists, gists_by, repository_issues, + gitignore_templates, all_repositories, all_users, all_events, + organizations_with, repositories_by, starred_by, subscriptions_for, + rate_limit, repository, search_code, search_repositories, search_users, + user, zen +) +from github3.github import GitHub, GitHubEnterprise, GitHubStatus +from github3.models import GitHubError -# flake8: noqa +__all__ = ( + 'GitHub', 'GitHubEnterprise', 'GitHubError', 'GitHubStatus', 'authorize', + 'login', 'enterprise_login', 'emojis', 'gist', 'gitignore_template', + 'create_gist', 'issue', 'markdown', 'octocat', 'organization', + 'pull_request', 'followers_of', 'followed_by', 'public_gists', 'gists_by', + 'repository_issues', 'gitignore_templates', 'all_repositories', + 'all_users', 'all_events', 'organizations_with', 'repositories_by', + 'starred_by', 'subscriptions_for', 'rate_limit', 'repository', + 'search_code', 'search_repositories', 'search_users', 'user', 'zen', +) From d2f380ab82a003a25d744c83bf8eae012fe8a514 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 18:39:52 -0500 Subject: [PATCH 088/972] Dump a useless function --- HISTORY.rst | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ github3/api.py | 9 -------- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 8a5ba6661..e544fb361 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -120,6 +120,66 @@ Old name New name - ``Repository#ignore`` ignores notifications from the repository for the authenticated user +- ``github3.ratelimit_remaining`` was removed + +0.9.0: 2014-05-04 +~~~~~~~~~~~~~~~~~ + +- Add Deployments API + +- Add Pages API + +- Add support so applications can revoke a `single authorization`_ or `all + authorizations`_ created by the application + +- Add the ability for users to ping_ hooks + +- Allow users to list a `Repository's collaborators`_ + +- Allow users to create an empty blob on a Repository + +- Update how users can list issues and pull requests. See: + http://developer.github.com/changes/2014-02-28-issue-and-pull-query-enhancements/ + This includes breaking changes to ``Repository#iter_pulls``. + +- Update methods to handle the `pagination changes`_. + +- Fix typo `stargarzers_url`_ + +- Add ``assets`` attribute to ``Release`` object. + +- Fix wrong argument to ``Organization#create_team`` (``permissions`` versus + ``permission``) + +- Fix Issue Search Result's representation and initialization + +- Fix Repository Search Result's initialization + +- Allow users to pass a two-factor authentication callback to + ``GitHub#authorize``. + +.. _single authorization: https://github3py.readthedocs.org/en/latest/github.html#github3.github.GitHub.revoke_authorization +.. _all authorizations: https://github3py.readthedocs.org/en/latest/github.html#github3.github.GitHub.revoke_authorizations +.. _ping: https://github3py.readthedocs.org/en/latest/repos.html?highlight=ping#github3.repos.hook.Hook.ping +.. _Repository's collaborators: https://github3py.readthedocs.org/en/latest/repos.html#github3.repos.repo.Repository.iter_collaborators +.. _pagination changes: https://developer.github.com/changes/2014-03-18-paginating-method-changes/ +.. _stargarzers_url: https://github.com/sigmavirus24/github3.py/pull/240 + +0.8.2: 2014-02-11 +~~~~~~~~~~~~~~~~~ + +- Fix bug in ``GitHub#search_users`` (and ``github3.search_users``). Thanks + @abesto + +- Expose the stargazers count for repositories. Thanks @seveas + +0.8.1: 2014-01-26 +~~~~~~~~~~~~~~~~~ + +- Add documentation for using Two Factor Authentication + +- Fix oversight where ``github3.login`` could not be used for 2FA + 0.8.0: 2014-01-03 ~~~~~~~~~~~~~~~~~ diff --git a/github3/api.py b/github3/api.py index 471c64f65..c6ac1b163 100644 --- a/github3/api.py +++ b/github3/api.py @@ -420,15 +420,6 @@ def repository(owner, repository): repository.__doc__ = gh.repository.__doc__ -def ratelimit_remaining(): - """Get the remaining number of requests allowed. - - :returns: int - - """ - return gh.ratelimit_remaining - - def search_code(query, sort=None, order=None, per_page=None, text_match=False, number=-1, etag=None): """Find code via the code search API. From 30d90d7102cfe62e054635b5b9f2f480e102d9cd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 18:42:35 -0500 Subject: [PATCH 089/972] Fix tests --- tests/integration/test_api.py | 2 +- tests/test_api.py | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/integration/test_api.py b/tests/integration/test_api.py index 0bdcbfd85..29bda0d2c 100644 --- a/tests/integration/test_api.py +++ b/tests/integration/test_api.py @@ -5,7 +5,7 @@ class TestAPI(IntegrationHelper): def get_client(self): - return github3.gh + return github3.api.gh def test_emojis(self): """Test the ability to use the /emojis endpoint""" diff --git a/tests/test_api.py b/tests/test_api.py index 6d13cb088..82277cd09 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -53,12 +53,6 @@ def test_rate_limit(self): github3.rate_limit() self.gh.rate_limit.assert_called_once_with() - def test_ratelimit_remaining(self): - # This prevents a regression in the API - # See 81c800658db43f86419b9c0764fc16aad3d60007 - self.gh.ratelimit_remaining = mock.NonCallableMock() - github3.ratelimit_remaining() - def test_zen(self): github3.zen() assert self.gh.zen.called is True From 50c79dd8038bdcfc6f024b768989d3751aed4d55 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 18:44:05 -0500 Subject: [PATCH 090/972] Migrate test for github3.create_gist --- tests/test_api.py | 5 ----- tests/unit/test_api.py | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 82277cd09..55b0ef88a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -12,11 +12,6 @@ def setUp(self): def tearDown(self): self.mock.stop() - def test_create_gist(self): - args = ('description', {'files': ['files']}) - github3.create_gist(*args) - self.gh.create_gist.assert_called_with(*args) - def test_issue(self): args = ('owner', 'repo', 1) github3.issue(*args) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 0ed65a27c..3c89f1ce5 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -37,6 +37,11 @@ def test_authorize(self): github3.authorize(*args) gh().authorize.assert_called_once_with(*args) + def test_create_gist(self): + args = ('description', {'files': ['file']}) + github3.create_gist(*args) + self.gh.create_gist.assert_called_once_with(*args) + def test_enterprise_login(self): args = ('login', 'password', None, 'https://url.com/', None) with mock.patch.object(github3.GitHubEnterprise, 'login') as login: From 7dd4a230a22d352eeebdc18c9c88fa80ed0ba33c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 18:55:57 -0500 Subject: [PATCH 091/972] Migrate github3.api tests --- tests/test_api.py | 18 ------------------ tests/unit/test_api.py | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 55b0ef88a..ce59ee1b4 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -12,24 +12,6 @@ def setUp(self): def tearDown(self): self.mock.stop() - def test_issue(self): - args = ('owner', 'repo', 1) - github3.issue(*args) - self.gh.issue.assert_called_with(*args) - - def test_markdown(self): - args = ('text', '', '', False) - github3.markdown(*args) - self.gh.markdown.assert_called_with(*args) - - def test_octocat(self): - github3.octocat() - assert self.gh.octocat.called is True - - def test_organization(self): - github3.organization('login') - self.gh.organization.assert_called_with('login') - def test_pull_request(self): args = ('owner', 'repo', 1) github3.pull_request(*args) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 3c89f1ce5..40a2b0fa9 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -75,6 +75,10 @@ def test_gitignore_templates(self): github3.gitignore_templates() assert self.gh.gitignore_templates.called is True + def test_issue(self): + github3.issue('sigmavirus24', 'github3.py', 100) + self.gh.issue.assert_called_with('sigmavirus24', 'github3.py', 100) + def test_login(self): args = ('login', 'password', None, None) with mock.patch.object(github3.GitHub, 'login') as login: @@ -83,6 +87,18 @@ def test_login(self): assert not isinstance(g, github3.GitHubEnterprise) login.assert_called_once_with(*args) + def test_markdown(self): + github3.markdown('text', '', '', False) + self.gh.markdown.assert_called_once_with('text', '', '', False) + + def test_octocat(self): + github3.octocat() + self.gh.octocat.assert_called_once_with() + + def test_organization(self): + github3.organization('orgname') + self.gh.organization.assert_called_once_with('orgname') + def test_organizations_with(self): args = ('login', -1, None) github3.organizations_with(*args) From 7ccfdde994d047c67478248d40527e3b5e9180e2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 19:02:00 -0500 Subject: [PATCH 092/972] Fix octocat api unit test --- tests/unit/test_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 40a2b0fa9..b132ba9c0 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -93,7 +93,7 @@ def test_markdown(self): def test_octocat(self): github3.octocat() - self.gh.octocat.assert_called_once_with() + self.gh.octocat.assert_called_once_with(None) def test_organization(self): github3.organization('orgname') From 8d98f4a635d2276eaab2e4daabc026b1e7ca625d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 19:02:14 -0500 Subject: [PATCH 093/972] Migrate test for github3.pull_request --- tests/test_api.py | 5 ----- tests/unit/test_api.py | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index ce59ee1b4..51f8e4608 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -12,11 +12,6 @@ def setUp(self): def tearDown(self): self.mock.stop() - def test_pull_request(self): - args = ('owner', 'repo', 1) - github3.pull_request(*args) - self.gh.pull_request.assert_called_with(*args) - def test_repository(self): args = ('owner', 'repo') github3.repository(*args) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index b132ba9c0..fbd4dffa6 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -104,6 +104,12 @@ def test_organizations_with(self): github3.organizations_with(*args) self.gh.organizations_with.assert_called_with(*args) + def test_pull_request(self): + github3.pull_request('sigmavirus24', 'github3.py', 24) + self.gh.pull_request.assert_called_once_with('sigmavirus24', + 'github3.py', + 24) + def test_repository_issues(self): args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) From aa12dd4d0c64c1cad119f9b8a490d4b01d56142c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 19:05:20 -0500 Subject: [PATCH 094/972] Migrate github3.api.repository unit test --- tests/test_api.py | 5 ----- tests/unit/test_api.py | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 51f8e4608..8c6c8d282 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -12,11 +12,6 @@ def setUp(self): def tearDown(self): self.mock.stop() - def test_repository(self): - args = ('owner', 'repo') - github3.repository(*args) - self.gh.repository.assert_called_with(*args) - def test_user(self): github3.user('login') self.gh.user.assert_called_with('login') diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index fbd4dffa6..5cf4e2344 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -110,6 +110,11 @@ def test_pull_request(self): 'github3.py', 24) + def test_repository(self): + github3.repository('sigmavirus24', 'github3.py') + self.gh.repository.assert_called_once_with('sigmavirus24', + 'github3.py') + def test_repository_issues(self): args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) From 68e982cb53e23bb40773e4e16baf1bc017a753cd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 19:13:34 -0500 Subject: [PATCH 095/972] Re-alphabetize --- tests/unit/test_api.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 5cf4e2344..04332c9d9 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -121,6 +121,11 @@ def test_repository_issues(self): github3.repository_issues(*args) self.gh.repository_issues.assert_called_with(*args) + def test_repositories_by(self): + args = ('login', None, None, None, -1, None) + github3.repositories_by('login') + self.gh.repositories_by.assert_called_with(*args) + def test_starred(self): github3.starred_by('login') self.gh.starred_by.assert_called_with('login', -1, None) @@ -128,8 +133,3 @@ def test_starred(self): def test_subcriptions_for(self): github3.subscriptions_for('login') self.gh.subscriptions_for.assert_called_with('login', -1, None) - - def test_repositories_by(self): - args = ('login', None, None, None, -1, None) - github3.repositories_by('login') - self.gh.repositories_by.assert_called_with(*args) From ff235e378619847f4174fb6ca2fe3cc840569e45 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 19:14:49 -0500 Subject: [PATCH 096/972] Migrate github3.api.user test --- tests/test_api.py | 4 ---- tests/unit/test_api.py | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 8c6c8d282..fe4d5b058 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -12,10 +12,6 @@ def setUp(self): def tearDown(self): self.mock.stop() - def test_user(self): - github3.user('login') - self.gh.user.assert_called_with('login') - def test_rate_limit(self): github3.rate_limit() self.gh.rate_limit.assert_called_once_with() diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 04332c9d9..a66dba3a9 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -133,3 +133,7 @@ def test_starred(self): def test_subcriptions_for(self): github3.subscriptions_for('login') self.gh.subscriptions_for.assert_called_with('login', -1, None) + + def test_user(self): + github3.user('sigmavirus24') + self.gh.user.assert_called_once_with('sigmavirus24') From 7d0ac260c6335432e135b1d04265f09f4d1e3223 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 19:17:09 -0500 Subject: [PATCH 097/972] Migrate github3.api.rate_limit test --- tests/test_api.py | 4 ---- tests/unit/test_api.py | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index fe4d5b058..163c9d6e8 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -12,10 +12,6 @@ def setUp(self): def tearDown(self): self.mock.stop() - def test_rate_limit(self): - github3.rate_limit() - self.gh.rate_limit.assert_called_once_with() - def test_zen(self): github3.zen() assert self.gh.zen.called is True diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index a66dba3a9..ecdfcb123 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -110,6 +110,10 @@ def test_pull_request(self): 'github3.py', 24) + def test_rate_limit(self): + github3.rate_limit() + self.gh.rate_limit.assert_called_once_with() + def test_repository(self): github3.repository('sigmavirus24', 'github3.py') self.gh.repository.assert_called_once_with('sigmavirus24', From d87b2470abe6ccdb2097fc19f8c30aa0b64a7ded Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 19:17:32 -0500 Subject: [PATCH 098/972] Migrate github3.api.zen test --- tests/test_api.py | 4 ---- tests/unit/test_api.py | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 163c9d6e8..3de6b27bd 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -11,7 +11,3 @@ def setUp(self): def tearDown(self): self.mock.stop() - - def test_zen(self): - github3.zen() - assert self.gh.zen.called is True diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index ecdfcb123..89e2b63c7 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -141,3 +141,7 @@ def test_subcriptions_for(self): def test_user(self): github3.user('sigmavirus24') self.gh.user.assert_called_once_with('sigmavirus24') + + def test_zen(self): + github3.zen() + assert self.gh.zen.called is True From 3f63a1b6e167004b3bb58af66b46cf06cd85bd14 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 6 Jul 2014 19:18:07 -0500 Subject: [PATCH 099/972] Delete tests/test_api.py --- tests/test_api.py | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 tests/test_api.py diff --git a/tests/test_api.py b/tests/test_api.py deleted file mode 100644 index 3de6b27bd..000000000 --- a/tests/test_api.py +++ /dev/null @@ -1,13 +0,0 @@ -import github3 -from unittest import TestCase -#from .utils.mock import patch, NonCallableMock -from .utils import mock - - -class TestAPI(TestCase): - def setUp(self): - self.mock = mock.patch('github3.api.gh', autospec=github3.GitHub) - self.gh = self.mock.start() - - def tearDown(self): - self.mock.stop() From 8f6a54d3ee5fb66dd8c0508c6f563401df416cd6 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 15:05:59 -0500 Subject: [PATCH 100/972] Add docstrings to tests/unit/test_api.py --- tests/unit/test_api.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 89e2b63c7..1bc297530 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -1,3 +1,4 @@ +"""Unit tests for github3.api.""" import github3 import unittest @@ -5,6 +6,7 @@ class TestAPI(unittest.TestCase): + """All tests for the github3.api module.""" def setUp(self): self.mocked_github = mock.patch('github3.api.gh', autospec=github3.GitHub) From be34f5fd7d60a58d337d39724fb4c35d8455b127 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 15:09:03 -0500 Subject: [PATCH 101/972] Add docstrings for all test_* methods in test_api --- tests/unit/test_api.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 1bc297530..5d816e401 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -16,35 +16,42 @@ def tearDown(self): self.mocked_github.stop() def test_all_events(self): + """Show that github3.all_events proxies to GitHub#all_events.""" github3.all_events() self.gh.all_events.assert_called_once_with(-1, None) def test_public_gists(self): + """Show that github3.public_gists proxies to GitHub#public_gists.""" github3.public_gists() self.gh.public_gists.assert_called_once_with(-1, None) def test_all_repositories(self): + """Show that github3.all_repositories proxies to GitHub#all_repositories.""" github3.all_repositories() # TODO(Ian): When you fix GitHub, fix this test too self.gh.all_repositories.assert_called_once_with(-1, None) def test_all_users(self): + """Show that github3.all_users proxies to GitHub#all_users.""" github3.all_users() # TODO(Ian): Fix this when GitHub changes self.gh.all_users.assert_called_once_with(-1, None) def test_authorize(self): + """Show that github3.authorize proxies to GitHub#authorize.""" args = ('login', 'password', ['scope'], 'note', 'url.com', '', '') with mock.patch('github3.api.GitHub') as gh: github3.authorize(*args) gh().authorize.assert_called_once_with(*args) def test_create_gist(self): + """Show that github3.create_gist proxies to GitHub#create_gist.""" args = ('description', {'files': ['file']}) github3.create_gist(*args) self.gh.create_gist.assert_called_once_with(*args) def test_enterprise_login(self): + """Show that github3.enterprise_login proxies to GitHub#enterprise_login.""" args = ('login', 'password', None, 'https://url.com/', None) with mock.patch.object(github3.GitHubEnterprise, 'login') as login: g = github3.enterprise_login(*args) @@ -52,36 +59,44 @@ def test_enterprise_login(self): login.assert_called_once_with('login', 'password', None, None) def test_followers_of(self): + """Show that github3.followers_of proxies to GitHub#followers_of.""" github3.followers_of('login') self.gh.followers_of.assert_called_with('login', -1, None) def test_followed_by(self): + """Show that github3.followed_by proxies to GitHub#followed_by.""" github3.followed_by('login') self.gh.followed_by.assert_called_with('login', -1, None) def test_gist(self): + """Show that github3.gist proxies to GitHub#gist.""" gist_id = 123 github3.gist(gist_id) self.gh.gist.assert_called_once_with(gist_id) def test_gists_by(self): + """Show that github3.gists_by proxies to GitHub#gists_by.""" github3.gists_by('username') self.gh.gists_by.assert_called_once_with('username', -1, None) def test_gitignore_template(self): + """Show that github3.gitignore_template proxies to GitHub#gitignore_template.""" language = 'Python' github3.gitignore_template(language) self.gh.gitignore_template.assert_called_once_with(language) def test_gitignore_templates(self): + """Show that github3.gitignore_templates proxies to GitHub#gitignore_templates.""" github3.gitignore_templates() assert self.gh.gitignore_templates.called is True def test_issue(self): + """Show that github3.issue proxies to GitHub#issue.""" github3.issue('sigmavirus24', 'github3.py', 100) self.gh.issue.assert_called_with('sigmavirus24', 'github3.py', 100) def test_login(self): + """Show that github3.login proxies to GitHub#login.""" args = ('login', 'password', None, None) with mock.patch.object(github3.GitHub, 'login') as login: g = github3.login(*args) @@ -90,60 +105,73 @@ def test_login(self): login.assert_called_once_with(*args) def test_markdown(self): + """Show that github3.markdown proxies to GitHub#markdown.""" github3.markdown('text', '', '', False) self.gh.markdown.assert_called_once_with('text', '', '', False) def test_octocat(self): + """Show that github3.octocat proxies to GitHub#octocat.""" github3.octocat() self.gh.octocat.assert_called_once_with(None) def test_organization(self): + """Show that github3.organization proxies to GitHub#organization.""" github3.organization('orgname') self.gh.organization.assert_called_once_with('orgname') def test_organizations_with(self): + """Show that github3.organizations_with proxies to GitHub#organizations_with.""" args = ('login', -1, None) github3.organizations_with(*args) self.gh.organizations_with.assert_called_with(*args) def test_pull_request(self): + """Show that github3.pull_request proxies to GitHub#pull_request.""" github3.pull_request('sigmavirus24', 'github3.py', 24) self.gh.pull_request.assert_called_once_with('sigmavirus24', 'github3.py', 24) def test_rate_limit(self): + """Show that github3.rate_limit proxies to GitHub#rate_limit.""" github3.rate_limit() self.gh.rate_limit.assert_called_once_with() def test_repository(self): + """Show that github3.repository proxies to GitHub#repository.""" github3.repository('sigmavirus24', 'github3.py') self.gh.repository.assert_called_once_with('sigmavirus24', 'github3.py') def test_repository_issues(self): + """Show that github3.repository_issues proxies to GitHub#repository_issues.""" args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) github3.repository_issues(*args) self.gh.repository_issues.assert_called_with(*args) def test_repositories_by(self): + """Show that github3.repositories_by proxies to GitHub#repositories_by.""" args = ('login', None, None, None, -1, None) github3.repositories_by('login') self.gh.repositories_by.assert_called_with(*args) def test_starred(self): + """Show that github3.starred proxies to GitHub#starred.""" github3.starred_by('login') self.gh.starred_by.assert_called_with('login', -1, None) def test_subcriptions_for(self): + """Show that github3.subscriptions_for proxies to GitHub#subscriptions_for.""" github3.subscriptions_for('login') self.gh.subscriptions_for.assert_called_with('login', -1, None) def test_user(self): + """Show that github3.user proxies to GitHub#user.""" github3.user('sigmavirus24') self.gh.user.assert_called_once_with('sigmavirus24') def test_zen(self): + """Show that github3.zen proxies to GitHub#zen.""" github3.zen() assert self.gh.zen.called is True From 0c0fd0003c194e156d694a23a86755305dc618a5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 15:29:34 -0500 Subject: [PATCH 102/972] Fix docstrings in test_api --- tests/unit/test_api.py | 58 ++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 5d816e401..850c518d0 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -6,7 +6,9 @@ class TestAPI(unittest.TestCase): + """All tests for the github3.api module.""" + def setUp(self): self.mocked_github = mock.patch('github3.api.gh', autospec=github3.GitHub) @@ -16,42 +18,42 @@ def tearDown(self): self.mocked_github.stop() def test_all_events(self): - """Show that github3.all_events proxies to GitHub#all_events.""" + """Show that github3.all_events proxies to GitHub.""" github3.all_events() self.gh.all_events.assert_called_once_with(-1, None) def test_public_gists(self): - """Show that github3.public_gists proxies to GitHub#public_gists.""" + """Show that github3.public_gists proxies to GitHub.""" github3.public_gists() self.gh.public_gists.assert_called_once_with(-1, None) def test_all_repositories(self): - """Show that github3.all_repositories proxies to GitHub#all_repositories.""" + """Show that github3.all_repositories proxies to GitHub.""" github3.all_repositories() # TODO(Ian): When you fix GitHub, fix this test too self.gh.all_repositories.assert_called_once_with(-1, None) def test_all_users(self): - """Show that github3.all_users proxies to GitHub#all_users.""" + """Show that github3.all_users proxies to GitHub.""" github3.all_users() # TODO(Ian): Fix this when GitHub changes self.gh.all_users.assert_called_once_with(-1, None) def test_authorize(self): - """Show that github3.authorize proxies to GitHub#authorize.""" + """Show that github3.authorize proxies to GitHub.""" args = ('login', 'password', ['scope'], 'note', 'url.com', '', '') with mock.patch('github3.api.GitHub') as gh: github3.authorize(*args) gh().authorize.assert_called_once_with(*args) def test_create_gist(self): - """Show that github3.create_gist proxies to GitHub#create_gist.""" + """Show that github3.create_gist proxies to GitHub.""" args = ('description', {'files': ['file']}) github3.create_gist(*args) self.gh.create_gist.assert_called_once_with(*args) def test_enterprise_login(self): - """Show that github3.enterprise_login proxies to GitHub#enterprise_login.""" + """Show that github3.enterprise_login returns GitHubEnterprise.""" args = ('login', 'password', None, 'https://url.com/', None) with mock.patch.object(github3.GitHubEnterprise, 'login') as login: g = github3.enterprise_login(*args) @@ -59,44 +61,44 @@ def test_enterprise_login(self): login.assert_called_once_with('login', 'password', None, None) def test_followers_of(self): - """Show that github3.followers_of proxies to GitHub#followers_of.""" + """Show that github3.followers_of proxies to GitHub.""" github3.followers_of('login') self.gh.followers_of.assert_called_with('login', -1, None) def test_followed_by(self): - """Show that github3.followed_by proxies to GitHub#followed_by.""" + """Show that github3.followed_by proxies to GitHub.""" github3.followed_by('login') self.gh.followed_by.assert_called_with('login', -1, None) def test_gist(self): - """Show that github3.gist proxies to GitHub#gist.""" + """Show that github3.gist proxies to GitHub.""" gist_id = 123 github3.gist(gist_id) self.gh.gist.assert_called_once_with(gist_id) def test_gists_by(self): - """Show that github3.gists_by proxies to GitHub#gists_by.""" + """Show that github3.gists_by proxies to GitHub.""" github3.gists_by('username') self.gh.gists_by.assert_called_once_with('username', -1, None) def test_gitignore_template(self): - """Show that github3.gitignore_template proxies to GitHub#gitignore_template.""" + """Show that github3.gitignore_template proxies to GitHub.""" language = 'Python' github3.gitignore_template(language) self.gh.gitignore_template.assert_called_once_with(language) def test_gitignore_templates(self): - """Show that github3.gitignore_templates proxies to GitHub#gitignore_templates.""" + """Show that github3.gitignore_templates proxies to GitHub.""" github3.gitignore_templates() assert self.gh.gitignore_templates.called is True def test_issue(self): - """Show that github3.issue proxies to GitHub#issue.""" + """Show that github3.issue proxies to GitHub.""" github3.issue('sigmavirus24', 'github3.py', 100) self.gh.issue.assert_called_with('sigmavirus24', 'github3.py', 100) def test_login(self): - """Show that github3.login proxies to GitHub#login.""" + """Show that github3.login proxies to GitHub.""" args = ('login', 'password', None, None) with mock.patch.object(github3.GitHub, 'login') as login: g = github3.login(*args) @@ -105,73 +107,73 @@ def test_login(self): login.assert_called_once_with(*args) def test_markdown(self): - """Show that github3.markdown proxies to GitHub#markdown.""" + """Show that github3.markdown proxies to GitHub.""" github3.markdown('text', '', '', False) self.gh.markdown.assert_called_once_with('text', '', '', False) def test_octocat(self): - """Show that github3.octocat proxies to GitHub#octocat.""" + """Show that github3.octocat proxies to GitHub.""" github3.octocat() self.gh.octocat.assert_called_once_with(None) def test_organization(self): - """Show that github3.organization proxies to GitHub#organization.""" + """Show that github3.organization proxies to GitHub.""" github3.organization('orgname') self.gh.organization.assert_called_once_with('orgname') def test_organizations_with(self): - """Show that github3.organizations_with proxies to GitHub#organizations_with.""" + """Show that github3.organizations_with proxies to GitHub.""" args = ('login', -1, None) github3.organizations_with(*args) self.gh.organizations_with.assert_called_with(*args) def test_pull_request(self): - """Show that github3.pull_request proxies to GitHub#pull_request.""" + """Show that github3.pull_request proxies to GitHub.""" github3.pull_request('sigmavirus24', 'github3.py', 24) self.gh.pull_request.assert_called_once_with('sigmavirus24', 'github3.py', 24) def test_rate_limit(self): - """Show that github3.rate_limit proxies to GitHub#rate_limit.""" + """Show that github3.rate_limit proxies to GitHub.""" github3.rate_limit() self.gh.rate_limit.assert_called_once_with() def test_repository(self): - """Show that github3.repository proxies to GitHub#repository.""" + """Show that github3.repository proxies to GitHub.""" github3.repository('sigmavirus24', 'github3.py') self.gh.repository.assert_called_once_with('sigmavirus24', 'github3.py') def test_repository_issues(self): - """Show that github3.repository_issues proxies to GitHub#repository_issues.""" + """Show that github3.repository_issues proxies to GitHub.""" args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) github3.repository_issues(*args) self.gh.repository_issues.assert_called_with(*args) def test_repositories_by(self): - """Show that github3.repositories_by proxies to GitHub#repositories_by.""" + """Show that github3.repositories_by proxies to GitHub.""" args = ('login', None, None, None, -1, None) github3.repositories_by('login') self.gh.repositories_by.assert_called_with(*args) def test_starred(self): - """Show that github3.starred proxies to GitHub#starred.""" + """Show that github3.starred proxies to GitHub.""" github3.starred_by('login') self.gh.starred_by.assert_called_with('login', -1, None) def test_subcriptions_for(self): - """Show that github3.subscriptions_for proxies to GitHub#subscriptions_for.""" + """Show that github3.subscriptions_for proxies to GitHub.""" github3.subscriptions_for('login') self.gh.subscriptions_for.assert_called_with('login', -1, None) def test_user(self): - """Show that github3.user proxies to GitHub#user.""" + """Show that github3.user proxies to GitHub.""" github3.user('sigmavirus24') self.gh.user.assert_called_once_with('sigmavirus24') def test_zen(self): - """Show that github3.zen proxies to GitHub#zen.""" + """Show that github3.zen proxies to GitHub.""" github3.zen() assert self.gh.zen.called is True From 669c7dbbd7c52ef7d98ebc91cc8145d574c668c1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 18:20:02 -0500 Subject: [PATCH 103/972] Discontinue GitHub instances as context managers --- HISTORY.rst | 7 ++++--- github3/github.py | 8 ++------ tests/test_github.py | 7 ------- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index e544fb361..61e783e06 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -5,9 +5,8 @@ History/Changelog 1.0.0: 2014-xx-xx ~~~~~~~~~~~~~~~~~ -1.0.0 is a huge release. It includes a great deal of changes to -``github3.py``. It is suggested you read the following release notes *very* -carefully. +1.0.0 is a huge release. It includes a great deal of changes to ``github3.py``. +It is suggested you read the following release notes *very* carefully. Breaking Changes ```````````````` @@ -122,6 +121,8 @@ Old name New name - ``github3.ratelimit_remaining`` was removed +- ``GitHub`` instances can no longer be used as context managers + 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ diff --git a/github3/github.py b/github3/github.py index e4325eaa5..196620e4f 100644 --- a/github3/github.py +++ b/github3/github.py @@ -26,6 +26,7 @@ class GitHub(GitHubCore): + """Stores all the session information. There are two ways to log into the GitHub API @@ -49,6 +50,7 @@ class GitHub(GitHubCore): This is simple backward compatibility since originally there was no way to call the GitHub object with authentication parameters. """ + def __init__(self, login='', password='', token=''): super(GitHub, self).__init__({}) if token: @@ -61,12 +63,6 @@ def _repr(self): return ''.format(self._session.auth) return ''.format(id(self)) - def __enter__(self): - return self - - def __exit__(self, *args): - pass - @requires_basic_auth def authorization(self, id_num): """Get information about authorization ``id``. diff --git a/tests/test_github.py b/tests/test_github.py index c50f8c648..9faa352ad 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -18,13 +18,6 @@ def test_init(self): g = github3.GitHub(token='foo') assert repr(g).endswith('{0:x}>'.format(id(g))) - def test_context_manager(self): - with github3.GitHub() as gh: - gh.__exit__ = mock.Mock() - assert isinstance(gh, github3.GitHub) - - gh.__exit__.assert_called() - def test_authorization(self): self.response('authorization') self.get('https://api.github.com/authorizations/10') From 5cf4fec83b4adcfee5b1d44be4888c1cfd8007cd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 19:29:15 -0500 Subject: [PATCH 104/972] Update the integration tests with a docstring --- tests/integration/test_github.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 766f0e486..ff05b83b5 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +"""Integration tests for methods implemented on GitHub.""" import github3 import uritemplate From 64bc2e2be718c149241409779b59cccf84c83188 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 19:39:31 -0500 Subject: [PATCH 105/972] PEP257 compliance --- tests/integration/test_github.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index ff05b83b5..2080bd5f8 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -19,10 +19,13 @@ class TestGitHub(IntegrationHelper): + + """GitHub integration tests.""" + match_on = ['method', 'uri', 'gh3-headers'] def test_create_gist(self): - """Test the ability of a GitHub instance to create a new gist""" + """Test the ability of a GitHub instance to create a new gist.""" self.token_login() cassette_name = self.cassette_name('create_gist') with self.recorder.use_cassette(cassette_name): @@ -35,7 +38,7 @@ def test_create_gist(self): assert g.is_public() is True def test_create_issue(self): - """Test the ability of a GitHub instance to create a new issue""" + """Test the ability of a GitHub instance to create a new issue.""" self.token_login() cassette_name = self.cassette_name('create_issue') with self.recorder.use_cassette(cassette_name): From e1f68374b512d35f0a1112bc434a4816f0794c23 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 19:39:50 -0500 Subject: [PATCH 106/972] More PEP257 compliance. --- tests/integration/test_github.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 2080bd5f8..a597d634a 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -64,7 +64,7 @@ def test_create_key(self): assert k.key == SSH_KEY def test_emojis(self): - """Test the ability to retrieve from /emojis""" + """Test the ability to retrieve from /emojis.""" cassette_name = self.cassette_name('emojis') with self.recorder.use_cassette(cassette_name): emojis = self.gh.emojis() @@ -74,7 +74,7 @@ def test_emojis(self): assert emojis['+1'].startswith('https://github') def test_feeds(self): - """Test the ability to retrieve a user's timelime URLs""" + """Test the ability to retrieve a user's timelime URLs.""" self.basic_login() cassette_name = self.cassette_name('feeds') with self.recorder.use_cassette(cassette_name): @@ -91,7 +91,7 @@ def test_feeds(self): assert isinstance(v, uritemplate.URITemplate) def test_gist(self): - """Test the ability to retrieve a single gist""" + """Test the ability to retrieve a single gist.""" cassette_name = self.cassette_name('gist') with self.recorder.use_cassette(cassette_name): g = self.gh.gist(7160899) @@ -99,7 +99,7 @@ def test_gist(self): assert isinstance(g, github3.gists.Gist) def test_gitignore_template(self): - """Test the ability to retrieve a single gitignore template""" + """Test the ability to retrieve a single gitignore template.""" cassette_name = self.cassette_name('gitignore_template') with self.recorder.use_cassette(cassette_name): t = self.gh.gitignore_template('Python') From fd568fea4185ad01697e74bd2ae04fa34367c1e2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 19:40:10 -0500 Subject: [PATCH 107/972] More PEP257 compliance --- tests/integration/test_github.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index a597d634a..639659797 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -108,7 +108,7 @@ def test_gitignore_template(self): assert t != '' def test_non_existent_gitignore_template(self): - """Test the ability to retrieve a single gitignore template""" + """Test the ability to retrieve a single gitignore template.""" cassette_name = self.cassette_name('non_existent_gitignore_template') with self.recorder.use_cassette(cassette_name): t = self.gh.gitignore_template('i_donut_exist') @@ -117,7 +117,7 @@ def test_non_existent_gitignore_template(self): assert t == '' def test_gitignore_templates(self): - """Test the ability to retrieve a list of gitignore templates""" + """Test the ability to retrieve a list of gitignore templates.""" cassette_name = self.cassette_name('gitignore_templates') with self.recorder.use_cassette(cassette_name): l = self.gh.gitignore_templates() @@ -126,7 +126,7 @@ def test_gitignore_templates(self): assert isinstance(l, list) def test_issue(self): - """Test the ability to retrieve a single issue""" + """Test the ability to retrieve a single issue.""" cassette_name = self.cassette_name('issue') with self.recorder.use_cassette(cassette_name): i = self.gh.issue('sigmavirus24', 'github3.py', 1) @@ -134,28 +134,28 @@ def test_issue(self): assert isinstance(i, github3.issues.Issue) def test_all_repositories(self): - """Test the ability to iterate over all of the repositories""" + """Test the ability to iterate over all of the repositories.""" cassette_name = self.cassette_name('iter_all_repos') with self.recorder.use_cassette(cassette_name): for r in self.gh.all_repositories(number=25): assert isinstance(r, github3.repos.repo.Repository) def test_all_users(self): - """Test the ability to iterate over all of the users""" + """Test the ability to iterate over all of the users.""" cassette_name = self.cassette_name('iter_all_users') with self.recorder.use_cassette(cassette_name): for u in self.gh.all_users(number=25): assert isinstance(u, github3.users.User) def test_all_events(self): - """Test the ability to iterate over all public events""" + """Test the ability to iterate over all public events.""" cassette_name = self.cassette_name('iter_events') with self.recorder.use_cassette(cassette_name): for e in self.gh.all_events(number=25): assert isinstance(e, github3.events.Event) def test_followers_of(self): - """Test the ability to iterate over a user's followers""" + """Test the ability to iterate over a user's followers.""" cassette_name = self.cassette_name('followers_of') with self.recorder.use_cassette(cassette_name): for u in self.gh.followers_of('sigmavirus24', number=25): From 75feb304dda919209e3badb398b68c9817525290 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 19:41:57 -0500 Subject: [PATCH 108/972] Add an extra line to describe the test and satisfy pep257 --- tests/integration/test_github.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 639659797..bcc6eb9ee 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -164,6 +164,8 @@ def test_followers_of(self): def test_followers(self): """ Test the ability to iterate over an authenticated user's followers. + + Show the difference between GitHub#followers_of and GitHub#followers. """ self.basic_login() cassette_name = self.cassette_name('followers_auth') From cbef4c461dc2740c5f3a57a0efb54efdc1abd910 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 19:42:14 -0500 Subject: [PATCH 109/972] More PEP257 compliance --- tests/integration/test_github.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index bcc6eb9ee..0c7f0826a 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -174,7 +174,7 @@ def test_followers(self): assert isinstance(u, github3.users.User) def test_user_teams(self): - """Test the ability to iterate over a user's teams""" + """Test the ability to iterate over a user's teams.""" self.basic_login() cassette_name = self.cassette_name('iter_user_teams') with self.recorder.use_cassette(cassette_name): @@ -182,14 +182,14 @@ def test_user_teams(self): assert isinstance(t, github3.orgs.Team) def test_meta(self): - """Test the ability to get the CIDR formatted addresses""" + """Test the ability to get the CIDR formatted addresses.""" cassette_name = self.cassette_name('meta') with self.recorder.use_cassette(cassette_name): m = self.gh.meta() assert isinstance(m, dict) def test_octocat(self): - """Test the ability to use the octocat endpoint""" + """Test the ability to use the octocat endpoint.""" cassette_name = self.cassette_name('octocat') say = 'github3.py is awesome' with self.recorder.use_cassette(cassette_name): @@ -200,7 +200,7 @@ def test_octocat(self): assert say in o.decode() def test_organization(self): - """Test the ability to retrieve an Organization""" + """Test the ability to retrieve an Organization.""" cassette_name = self.cassette_name('organization') with self.recorder.use_cassette(cassette_name): o = self.gh.organization('github3py') @@ -208,7 +208,7 @@ def test_organization(self): assert isinstance(o, github3.orgs.Organization) def test_pull_request(self): - """Test the ability to retrieve a Pull Request""" + """Test the ability to retrieve a Pull Request.""" cassette_name = self.cassette_name('pull_request') with self.recorder.use_cassette(cassette_name): p = self.gh.pull_request('sigmavirus24', 'github3.py', 119) @@ -224,7 +224,7 @@ def test_rate_limit(self): assert 'resources' in r def test_repository(self): - """Test the ability to retrieve a Repository""" + """Test the ability to retrieve a Repository.""" cassette_name = self.cassette_name('repository') with self.recorder.use_cassette(cassette_name): r = self.gh.repository('sigmavirus24', 'github3.py') From e83984d83228863d42883cad4de59a70ff2eca37 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 19:43:09 -0500 Subject: [PATCH 110/972] PEP257 compliance --- tests/integration/test_github.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 0c7f0826a..c0d86acb6 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -247,7 +247,7 @@ def test_repositories_by(self): assert isinstance(r, github3.repos.Repository) def test_search_code(self): - """Test the ability to use the code search endpoint""" + """Test the ability to use the code search endpoint.""" cassette_name = self.cassette_name('search_code') with self.recorder.use_cassette(cassette_name): result_iterator = self.gh.search_code( @@ -259,7 +259,7 @@ def test_search_code(self): assert isinstance(code_result, github3.search.CodeSearchResult) def test_search_code_with_text_match(self): - """Test the ability to use the code search endpoint""" + """Test the ability to use the code search endpoint.""" cassette_name = self.cassette_name('search_code_with_text_match') with self.recorder.use_cassette(cassette_name, match_requests_on=self.match_on): @@ -274,7 +274,7 @@ def test_search_code_with_text_match(self): assert len(code_result.text_matches) > 0 def test_search_users(self): - """Test the ability to use the user search endpoint""" + """Test the ability to use the user search endpoint.""" cassette_name = self.cassette_name('search_users') with self.recorder.use_cassette(cassette_name): users = self.gh.search_users('tom followers:>1000') @@ -284,7 +284,7 @@ def test_search_users(self): assert isinstance(users, github3.structs.SearchIterator) def test_search_users_with_text_match(self): - """Test the ability to use the user search endpoint""" + """Test the ability to use the user search endpoint.""" cassette_name = self.cassette_name('search_users_with_text_match') with self.recorder.use_cassette(cassette_name, match_requests_on=self.match_on): @@ -298,7 +298,7 @@ def test_search_users_with_text_match(self): assert len(user_result.text_matches) > 0 def test_search_issues(self): - """Test the ability to use the issues search endpoint""" + """Test the ability to use the issues search endpoint.""" cassette_name = self.cassette_name('search_issues') with self.recorder.use_cassette(cassette_name): issues = self.gh.search_issues('github3 labels:bugs') @@ -307,7 +307,7 @@ def test_search_issues(self): assert isinstance(issues, github3.structs.SearchIterator) def test_search_repositories(self): - """Test the ability to use the repository search endpoint""" + """Test the ability to use the repository search endpoint.""" cassette_name = self.cassette_name('search_repositories') with self.recorder.use_cassette(cassette_name): repos = self.gh.search_repositories('github3 language:python') @@ -317,7 +317,7 @@ def test_search_repositories(self): assert isinstance(repos, github3.structs.SearchIterator) def test_search_repositories_with_text_match(self): - """Test the ability to use the repository search endpoint""" + """Test the ability to use the repository search endpoint.""" self.token_login() cassette_name = self.cassette_name('search_repositories_text_match') with self.recorder.use_cassette(cassette_name, @@ -332,7 +332,7 @@ def test_search_repositories_with_text_match(self): assert len(repo_result.text_matches) > 0 def test_user(self): - """Test the ability to retrieve a User""" + """Test the ability to retrieve a User.""" self.token_login() cassette_name = self.cassette_name('user') with self.recorder.use_cassette(cassette_name): @@ -344,7 +344,7 @@ def test_user(self): assert isinstance(u, github3.users.User) def test_zen(self): - """Test the ability to retrieve tidbits of Zen""" + """Test the ability to retrieve tidbits of Zen.""" cassette_name = self.cassette_name('zen') with self.recorder.use_cassette(cassette_name): z = self.gh.zen() From fa24123b8f27f9af993ba63c373fffb432d4d626 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 12 Jul 2014 19:43:42 -0500 Subject: [PATCH 111/972] Add a docstring for TestGitHub#test_rate_limit --- tests/integration/test_github.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index c0d86acb6..41e067ef4 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -216,6 +216,7 @@ def test_pull_request(self): assert isinstance(p, github3.pulls.PullRequest) def test_rate_limit(self): + """Test the ability to retrieve rate information.""" cassette_name = self.cassette_name('rate_limit') with self.recorder.use_cassette(cassette_name): r = self.gh.rate_limit() From 615d75254c12c3ab406881f2e24b17c52c3edae2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 18:22:46 -0500 Subject: [PATCH 112/972] Add GitHub#authorization unit tests --- tests/unit/test_github.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 57a2d5aa7..feb048de6 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -14,6 +14,21 @@ class TestGitHub(UnitHelper): described_class = GitHub example_data = None + def test_authorization(self): + """Show that a user can retrieve a specific authorization by id.""" + self.instance.authorization(10) + + self.session.get.assert_called_once_with( + url_for('authorizations/10'), + ) + + def test_authorization_requires_auth(self): + """A user must be authenticated to retrieve an authorization.""" + self.session.auth = None + + with pytest.raises(GitHubError): + self.instance.authorization(1) + def test_two_factor_login(self): self.instance.login('username', 'password', two_factor_callback=lambda *args: 'foo') From dcd5bc402baf58f0e600a16bde4b668759e52491 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 18:23:08 -0500 Subject: [PATCH 113/972] Remove old GitHub#authorization test --- tests/test_github.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 9faa352ad..257b0f914 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -18,17 +18,6 @@ def test_init(self): g = github3.GitHub(token='foo') assert repr(g).endswith('{0:x}>'.format(id(g))) - def test_authorization(self): - self.response('authorization') - self.get('https://api.github.com/authorizations/10') - self.assertRaises(github3.GitHubError, self.g.authorization, 10) - assert self.request.called is False - - self.login() - a = self.g.authorization(10) - assert isinstance(a, github3.auths.Authorization) - self.mock_assertions() - def test_authorize(self): self.response('authorization', 201) scopes = ['scope1', 'scope2'] From c3e4379042651c0df33e7940169c2a07a41ddf63 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 18:23:28 -0500 Subject: [PATCH 114/972] Add missing docstrings to test methods --- tests/unit/test_github.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index feb048de6..30bba653b 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -30,10 +30,12 @@ def test_authorization_requires_auth(self): self.instance.authorization(1) def test_two_factor_login(self): + """Test the ability to pass two_factor_callback.""" self.instance.login('username', 'password', two_factor_callback=lambda *args: 'foo') def test_can_login_without_two_factor_callback(self): + """Test that two_factor_callback is not required.""" self.instance.login('username', 'password') self.instance.login(token='token') From 665cbf27be78e70ae1f308ce85b9e3eddf90b103 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 18:27:53 -0500 Subject: [PATCH 115/972] Update GitHub#authorize --- github3/github.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/github3/github.py b/github3/github.py index 196620e4f..f526ce2d0 100644 --- a/github3/github.py +++ b/github3/github.py @@ -78,8 +78,10 @@ def authorization(self, id_num): def authorize(self, login, password, scopes=None, note='', note_url='', client_id='', client_secret=''): - """Obtain an authorization token from the GitHub API for the GitHub - API. + """Obtain an authorization token. + + The retrieved token will allow future consumers to use the API without + a login and password. :param str login: (required) :param str password: (required) @@ -94,21 +96,15 @@ def authorize(self, login, password, scopes=None, note='', note_url='', :returns: :class:`Authorization ` """ json = None - # TODO: Break this behaviour in 1.0 (Don't rely on self._session.auth) - auth = None - if self._session.auth: - auth = self._session.auth - elif login and password: - auth = (login, password) - if auth: + if login and password: url = self._build_url('authorizations') data = {'note': note, 'note_url': note_url, 'client_id': client_id, 'client_secret': client_secret} if scopes: data['scopes'] = scopes - with self._session.temporary_basic_auth(*auth): + with self._session.temporary_basic_auth(login, password): json = self._json(self._post(url, data=data), 201) return Authorization(json, self) if json else None From 2c4afea59757fbad03d35fbe744ceb4aba2e9ce8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 19:19:38 -0500 Subject: [PATCH 116/972] Add unit test for GitHub#authorize --- tests/unit/helper.py | 18 ++++++++++++++++++ tests/unit/test_github.py | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index 71bfe0644..5a0e759ac 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -3,6 +3,7 @@ except ImportError: import mock import github3 +import json import unittest @@ -47,6 +48,23 @@ def create_instance_of_described_class(self): return instance + def post_called_with(self, *args, **kwargs): + assert self.session.post.called is True + call_args, call_kwargs = self.session.post.call_args + + # Data passed to assertion + data = kwargs.pop('data', None) + # Data passed by the call to post positionally + # URL, 'json string' + call_args, call_data = call_args[:1], call_args[1] + # If data is a dictionary (or list) and call_data exists + if not isinstance(data, str) and call_data: + call_data = json.loads(call_data) + + assert args == call_args + assert data == call_data + assert kwargs == call_kwargs + def setUp(self): self.session = self.create_session_mock() self.instance = self.create_instance_of_described_class() diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 30bba653b..0d2b9c716 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -29,6 +29,19 @@ def test_authorization_requires_auth(self): with pytest.raises(GitHubError): self.instance.authorization(1) + def test_authorize(self): + """Show an authorization can be created for a user.""" + self.instance.authorize('username', 'password', ['user', 'repo']) + + self.session.temporary_basic_auth.assert_called_once_with( + 'username', 'password' + ) + self.post_called_with( + url_for('authorizations'), + data={'note': '', 'note_url': '', 'client_id': '', + 'client_secret': '', 'scopes': ['user', 'repo']} + ) + def test_two_factor_login(self): """Test the ability to pass two_factor_callback.""" self.instance.login('username', 'password', From 6f7afa10b9b92b6fa6ad5a644becafe6a8fdfaea Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 19:20:23 -0500 Subject: [PATCH 117/972] Add docstring to helper function --- tests/unit/test_github.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 0d2b9c716..6589d5157 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -7,6 +7,7 @@ def url_for(path=''): + """Simple function to generate URLs with the base GitHub URL.""" return 'https://api.github.com/' + path.strip('/') From 3e50ab7af8402369d6023b35750fe277b75f2e81 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 19:21:10 -0500 Subject: [PATCH 118/972] Remove old test --- tests/test_github.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 257b0f914..2e7983164 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -18,22 +18,6 @@ def test_init(self): g = github3.GitHub(token='foo') assert repr(g).endswith('{0:x}>'.format(id(g))) - def test_authorize(self): - self.response('authorization', 201) - scopes = ['scope1', 'scope2'] - - self.g.authorize(None, None, scopes) - self.not_called() - - a = self.g.authorize('user', 'password', scopes) - assert isinstance(a, github3.auths.Authorization) - assert self.request.called is True - - self.request.reset_mock() - - self.login() - a = self.g.authorize(None, None, scopes=scopes) - def test_check_authorization(self): self.response('', 200) self.get('https://api.github.com/applications/fake_id/tokens/' From e29f64a7d282aaa2bcf5d95dd7fdc7ecd8ee648f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 21:32:27 -0500 Subject: [PATCH 119/972] Test GitHub#check_authorization --- tests/unit/test_github.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 6589d5157..7c59e59d9 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -43,6 +43,17 @@ def test_authorize(self): 'client_secret': '', 'scopes': ['user', 'repo']} ) + def test_check_authorization(self): + """Test an app's ability to check a authorization token.""" + self.instance.set_client_id('client-id', 'client-secret') + self.instance.check_authorization('super-fake-access-token') + + self.session.get.assert_called_once_with( + url_for('applications/client-id/tokens/super-fake-access-token'), + params={'client_id': None, 'client_secret': None}, + auth=('client-id', 'client-secret') + ) + def test_two_factor_login(self): """Test the ability to pass two_factor_callback.""" self.instance.login('username', 'password', From 2fc92046eda208b8c204455fd58d26c97da1c86a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 15 Jul 2014 21:47:31 -0500 Subject: [PATCH 120/972] Remove old test --- tests/test_github.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/test_github.py b/tests/test_github.py index 2e7983164..701ba1cd6 100644 --- a/tests/test_github.py +++ b/tests/test_github.py @@ -18,22 +18,6 @@ def test_init(self): g = github3.GitHub(token='foo') assert repr(g).endswith('{0:x}>'.format(id(g))) - def test_check_authorization(self): - self.response('', 200) - self.get('https://api.github.com/applications/fake_id/tokens/' - 'access_token') - self.conf = { - 'params': {'client_id': None, 'client_secret': None}, - 'auth': ('fake_id', 'fake_secret'), - } - - assert self.g.check_authorization(None) is False - self.not_called() - - self.g.set_client_id('fake_id', 'fake_secret') - assert self.g.check_authorization('access_token') - self.mock_assertions() - def test_create_gist(self): self.response('gist', 201) From 65a196ca61d4cea35f32bcaaa7acf7546e602552 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 16 Jul 2014 21:05:49 -0500 Subject: [PATCH 121/972] Satisfy PEP-257 --- github3/github.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/github3/github.py b/github3/github.py index f526ce2d0..5e49a9fc5 100644 --- a/github3/github.py +++ b/github3/github.py @@ -110,7 +110,9 @@ def authorize(self, login, password, scopes=None, note='', note_url='', return Authorization(json, self) if json else None def check_authorization(self, access_token): - """OAuth applications can use this method to check token validity + """Check an authorization created by a registered application. + + OAuth applications can use this method to check token validity without hitting normal rate limits because of failed login attempts. If the token is valid, it will return True, otherwise it will return False. From 6fd2e1b4044157f81335e5e2582d01bf5ffa63f4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 16 Jul 2014 21:27:35 -0500 Subject: [PATCH 122/972] Rename Organization#iter_members --- HISTORY.rst | 1 + github3/models.py | 4 ++-- github3/orgs.py | 2 +- tests/test_orgs.py | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 61e783e06..4b8458e6b 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -44,6 +44,7 @@ Old name New name ``GitHub#iter_repos`` ``GitHub#reposistories`` ``GitHub#iter_user_repos`` ``GitHub#repositories_by`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` +``Organization#iter_members`` ``Organization#members`` ============================== ============================================== diff --git a/github3/models.py b/github3/models.py index 8103a613a..85925c6f8 100644 --- a/github3/models.py +++ b/github3/models.py @@ -195,12 +195,12 @@ def refresh(self, conditional=False): The reasoning for the return value is the following example: :: - repos = [r.refresh() for r in g.iter_repos('kennethreitz')] + repos = [r.refresh() for r in g.repositories_by('kennethreitz')] Without the return value, that would be an array of ``None``'s and you would otherwise have to do: :: - repos = [r for i in g.iter_repos('kennethreitz')] + repos = [r for i in g.repositories_by('kennethreitz')] [r.refresh() for r in repos] Which is really an anti-pattern. diff --git a/github3/orgs.py b/github3/orgs.py index 3adc1e882..25bc409ff 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -142,7 +142,7 @@ def is_member(self, login): url = self._build_url('members', login, base_url=self._api) return self._boolean(self._get(url), 204, 404) - def iter_members(self, filter=None, number=-1, etag=None): + def members(self, number=-1, etag=None): """Iterate over the members of this team. :param str filter: (optional), filter members returned by this method. diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 4df21cc48..7ee4cc746 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -84,11 +84,11 @@ def test_is_member(self): assert self.team.is_member('user') is False self.mock_assertions() - def test_iter_members(self): + def test_members(self): self.response('user', _iter=True) self.get(self.api + '/members') - assert isinstance(next(self.team.iter_members()), github3.users.User) + assert isinstance(next(self.team.members()), github3.users.User) self.mock_assertions() def test_iter_repos(self): From e847dbf3c8abbab9c9ff21e8d45fb0deb78df71c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 16 Jul 2014 21:34:42 -0500 Subject: [PATCH 123/972] Actually update Organization#iter_members Previous commit updated Team#iter_members --- github3/orgs.py | 2 +- tests/test_orgs.py | 7 ------- tests/unit/test_orgs.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 tests/unit/test_orgs.py diff --git a/github3/orgs.py b/github3/orgs.py index 25bc409ff..f89f08f18 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -448,7 +448,7 @@ def iter_events(self, number=-1, etag=None): url = self._build_url('events', base_url=self._api) return self._iter(int(number), url, Event, etag=etag) - def iter_members(self, number=-1, etag=None): + def members(self, number=-1, etag=None): """Iterate over members of this organization. :param int number: (optional), number of members to return. Default: diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 7ee4cc746..9c3d65003 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -268,13 +268,6 @@ def test_iter_events(self): assert isinstance(next(self.org.iter_events()), github3.events.Event) self.mock_assertions() - def test_iter_members(self): - self.response('user', _iter=True) - self.get(self.api + '/members') - - assert isinstance(next(self.org.iter_members()), github3.users.User) - self.mock_assertions() - def test_iter_public_members(self): self.response('user', _iter=True) self.get(self.api + '/public_members') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py new file mode 100644 index 000000000..a84e07b81 --- /dev/null +++ b/tests/unit/test_orgs.py @@ -0,0 +1,29 @@ +from github3.orgs import Organization + +from .helper import UnitIteratorHelper + + +def url_for(path=''): + """Simple function to generate URLs with the base Org URL.""" + if path: + path = '/' + path.strip('/') + return 'https://api.github.com/orgs/hapy' + path + + +class TestOrganizationIterator(UnitIteratorHelper): + described_class = Organization + + example_data = { + 'url': url_for() + } + + def test_members(self): + """Show that one can iterate over all members.""" + i = self.instance.members() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('members'), + params={'per_page': 100}, + headers={} + ) From f05d6cdaa4db1d51c716aeb5670cdd342325c77f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 17 Jul 2014 08:58:04 -0500 Subject: [PATCH 124/972] Update Organization#iter_public_members --- github3/orgs.py | 2 +- tests/test_orgs.py | 8 -------- tests/unit/test_orgs.py | 11 +++++++++++ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index f89f08f18..72553da17 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -460,7 +460,7 @@ def members(self, number=-1, etag=None): url = self._build_url('members', base_url=self._api) return self._iter(int(number), url, User, etag=etag) - def iter_public_members(self, number=-1, etag=None): + def public_members(self, number=-1, etag=None): """Iterate over public members of this organization. :param int number: (optional), number of members to return. Default: diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 9c3d65003..1cdf9ba27 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -268,14 +268,6 @@ def test_iter_events(self): assert isinstance(next(self.org.iter_events()), github3.events.Event) self.mock_assertions() - def test_iter_public_members(self): - self.response('user', _iter=True) - self.get(self.api + '/public_members') - - assert isinstance(next(self.org.iter_public_members()), - github3.users.User) - self.mock_assertions() - def test_iter_repos(self): self.response('repo', _iter=True) self.get(self.api + '/repos') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index a84e07b81..4178e8b3f 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -27,3 +27,14 @@ def test_members(self): params={'per_page': 100}, headers={} ) + + def test_public_members(self): + """Show that one can iterate over all public members.""" + i = self.instance.public_members() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('public_members'), + params={'per_page': 100}, + headers={} + ) From 57d9b9a1bb429e16c7eb798f13696f452f6838d7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 17 Jul 2014 22:46:28 -0500 Subject: [PATCH 125/972] Update HISTORY --- HISTORY.rst | 69 +++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 4b8458e6b..a8848f1d5 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -13,40 +13,41 @@ Breaking Changes - All methods and functions starting with ``iter_`` have been renamed. -============================== ============================================== -Old name New name -============================== ============================================== -``github3.iter_all_repos`` ``github3.all_repositories`` -``github3.iter_all_users`` ``github3.all_users`` -``github3.iter_events`` ``github3.all_events`` -``github3.iter_followers`` ``github3.followers_of`` -``github3.iter_following`` ``github3.followed_by`` -``github3.iter_repo_issues`` ``github3.repository_issues`` -``github3.iter_orgs`` ``github3.organizations_with`` -``github3.iter_user_repos`` ``github3.repositories_by`` -``github3.iter_starred`` ``github3.starred_by`` -``github3.iter_subscriptions`` ``github3.subscriptions_for`` -``GitHub#iter_all_repos`` ``GitHub#all_repositories`` -``GitHub#iter_all_users`` ``GitHub#all_users`` -``GitHub#iter_authorizations`` ``GitHub#authorizations`` -``GitHub#iter_emails`` ``GitHub#emails`` -``GitHub#iter_events`` ``GitHub#events`` -``GitHub#iter_followers`` ``GitHub#{followers,followers_of}`` -``GitHub#iter_following`` ``GitHub#{following,followed_by}`` -``GitHub#iter_gists`` ``GitHub#{gists,gists_by,public_gists}`` -``GitHub#iter_notifications`` ``GitHub#notifications`` -``GitHub#iter_org_issues`` ``GitHub#organization_issues`` -``GitHub#iter_issues`` ``GitHub#issues`` -``GitHub#iter_user_issues`` ``GitHub#user_issues`` -``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` -``GitHub#iter_keys`` ``GitHub#keys`` -``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` -``GitHub#iter_repos`` ``GitHub#reposistories`` -``GitHub#iter_user_repos`` ``GitHub#repositories_by`` -``GitHub#iter_user_teams`` ``GitHub#user_teams`` -``Organization#iter_members`` ``Organization#members`` - -============================== ============================================== +==================================== ============================================== +Old name New name +==================================== ============================================== +``github3.iter_all_repos`` ``github3.all_repositories`` +``github3.iter_all_users`` ``github3.all_users`` +``github3.iter_events`` ``github3.all_events`` +``github3.iter_followers`` ``github3.followers_of`` +``github3.iter_following`` ``github3.followed_by`` +``github3.iter_repo_issues`` ``github3.repository_issues`` +``github3.iter_orgs`` ``github3.organizations_with`` +``github3.iter_user_repos`` ``github3.repositories_by`` +``github3.iter_starred`` ``github3.starred_by`` +``github3.iter_subscriptions`` ``github3.subscriptions_for`` +``GitHub#iter_all_repos`` ``GitHub#all_repositories`` +``GitHub#iter_all_users`` ``GitHub#all_users`` +``GitHub#iter_authorizations`` ``GitHub#authorizations`` +``GitHub#iter_emails`` ``GitHub#emails`` +``GitHub#iter_events`` ``GitHub#events`` +``GitHub#iter_followers`` ``GitHub#{followers,followers_of}`` +``GitHub#iter_following`` ``GitHub#{following,followed_by}`` +``GitHub#iter_gists`` ``GitHub#{gists,gists_by,public_gists}`` +``GitHub#iter_notifications`` ``GitHub#notifications`` +``GitHub#iter_org_issues`` ``GitHub#organization_issues`` +``GitHub#iter_issues`` ``GitHub#issues`` +``GitHub#iter_user_issues`` ``GitHub#user_issues`` +``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` +``GitHub#iter_keys`` ``GitHub#keys`` +``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` +``GitHub#iter_repos`` ``GitHub#reposistories`` +``GitHub#iter_user_repos`` ``GitHub#repositories_by`` +``GitHub#iter_user_teams`` ``GitHub#user_teams`` +``Organization#iter_members`` ``Organization#members`` +``Organization#iter_public_members`` ``Organization#public_members`` + +==================================== ============================================== - ``github3.login`` has been simplified and split into two functions: From 933b87b300e59f779bd2371b67e02ca65ea1476b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 17 Jul 2014 22:51:11 -0500 Subject: [PATCH 126/972] Rename Organization#iter_repos -> Organization#repositories --- github3/orgs.py | 2 +- tests/test_orgs.py | 18 ------------------ tests/unit/test_orgs.py | 22 ++++++++++++++++++++++ 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 72553da17..e5b05955d 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -472,7 +472,7 @@ def public_members(self, number=-1, etag=None): url = self._build_url('public_members', base_url=self._api) return self._iter(int(number), url, User, etag=etag) - def iter_repos(self, type='', number=-1, etag=None): + def repositories(self, type='', number=-1, etag=None): """Iterate over repos for this organization. :param str type: (optional), accepted values: diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 1cdf9ba27..4753fafb6 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -268,24 +268,6 @@ def test_iter_events(self): assert isinstance(next(self.org.iter_events()), github3.events.Event) self.mock_assertions() - def test_iter_repos(self): - self.response('repo', _iter=True) - self.get(self.api + '/repos') - self.conf = {'params': {'per_page': 100}} - - assert isinstance(next(self.org.iter_repos()), - github3.repos.Repository) - self.mock_assertions() - - assert isinstance(next(self.org.iter_repos('foo')), - github3.repos.Repository) - self.mock_assertions() - - self.conf['params'] = {'type': 'all', 'per_page': 100} - assert isinstance(next(self.org.iter_repos('all')), - github3.repos.Repository) - self.mock_assertions() - def test_iter_teams(self): self.response('team', _iter=True) self.get(self.api + '/teams') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 4178e8b3f..793df8834 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -38,3 +38,25 @@ def test_public_members(self): params={'per_page': 100}, headers={} ) + + def test_repositories(self): + """Show that one can iterate over an organization's repositories.""" + i = self.instance.repositories() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('repos'), + params={'per_page': 100}, + headers={} + ) + + def test_respositories_accepts_type(self): + """Show that one can pass a repository type.""" + i = self.instance.repositories('all') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('repos'), + params={'type': 'all', 'per_page': 100}, + headers={} + ) From 01c76d0576a7ea163b5df547a84bb67a38438691 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 17 Jul 2014 22:52:17 -0500 Subject: [PATCH 127/972] Update HISTORY regarding iter_repos rename --- HISTORY.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index a8848f1d5..b797128fb 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,4 +1,5 @@ .. vim: set tw=100 + History/Changelog ----------------- @@ -46,6 +47,7 @@ Old name New name ``GitHub#iter_user_teams`` ``GitHub#user_teams`` ``Organization#iter_members`` ``Organization#members`` ``Organization#iter_public_members`` ``Organization#public_members`` +``Organization#iter_repos`` ``Organization#repositories`` ==================================== ============================================== From ddefa2d176e16a0043c78d7c78a76237a10cba61 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 17 Jul 2014 23:02:09 -0500 Subject: [PATCH 128/972] Organization#iter_teams -> Organization#teams --- github3/orgs.py | 13 ++++--------- tests/test_orgs.py | 17 +++-------------- tests/unit/test_orgs.py | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index e5b05955d..c9c554b74 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -282,12 +282,7 @@ def add_member(self, login, team): :param str team: (required), team name :returns: bool """ - warnings.warn( - 'This is no longer supported by the GitHub API, see ' - 'https://developer.github.com/changes/2014-09-23-one-more-week' - '-before-the-add-team-member-api-breaking-change/', - DeprecationWarning) - for t in self.iter_teams(): + for t in self.teams(): if team == t.name: return t.add_member(login) return False @@ -306,7 +301,7 @@ def add_repo(self, repo, team): :param str repo: (required), form: 'user/repo' :param str team: (required), team name """ - for t in self.iter_teams(): + for t in self.teams(): if team == t.name: return t.add_repo(repo) return False @@ -491,7 +486,7 @@ def repositories(self, type='', number=-1, etag=None): return self._iter(int(number), url, Repository, params, etag) @requires_auth - def iter_teams(self, number=-1, etag=None): + def teams(self, number=-1, etag=None): """Iterate over teams that are part of this organization. :param int number: (optional), number of teams to return. Default: -1 @@ -530,7 +525,7 @@ def remove_repo(self, repo, team): :param str team: (required) :returns: bool """ - for t in self.iter_teams(): + for t in self.teams(): if team == t.name: return t.remove_repo(repo) return False diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 4753fafb6..fc4f3e3a0 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -145,7 +145,7 @@ def test_add_member(self): self.assertRaises(github3.GitHubError, self.org.add_member, None, None) self.login() - with mock.patch.object(github3.orgs.Organization, 'iter_teams') as it: + with mock.patch.object(github3.orgs.Organization, 'teams') as it: it.return_value = iter([]) assert self.org.add_member('foo', 'bar') is False team = mock.Mock() @@ -159,7 +159,7 @@ def test_add_repo(self): self.assertRaises(github3.GitHubError, self.org.add_repo, None, None) self.login() - with mock.patch.object(github3.orgs.Organization, 'iter_teams') as it: + with mock.patch.object(github3.orgs.Organization, 'teams') as it: it.return_value = iter([]) assert self.org.add_repo('foo', 'bar') is False team = mock.Mock() @@ -268,17 +268,6 @@ def test_iter_events(self): assert isinstance(next(self.org.iter_events()), github3.events.Event) self.mock_assertions() - def test_iter_teams(self): - self.response('team', _iter=True) - self.get(self.api + '/teams') - - self.assertRaises(github3.GitHubError, self.org.iter_teams) - - self.not_called() - self.login() - assert isinstance(next(self.org.iter_teams()), github3.orgs.Team) - self.mock_assertions() - def test_publicize_member(self): self.response('', 204) self.put(self.api + '/public_members/user') @@ -306,7 +295,7 @@ def test_remove_repo(self): None, None) self.login() - with mock.patch.object(github3.orgs.Organization, 'iter_teams') as it: + with mock.patch.object(github3.orgs.Organization, 'teams') as it: it.return_value = iter([]) assert self.org.remove_repo('foo', 'bar') is False team = mock.Mock() diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 793df8834..f542abdc2 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -1,3 +1,6 @@ +import pytest + +from github3 import GitHubError from github3.orgs import Organization from .helper import UnitIteratorHelper @@ -60,3 +63,21 @@ def test_respositories_accepts_type(self): params={'type': 'all', 'per_page': 100}, headers={} ) + + def test_teams(self): + """Show that one can iterate over an organization's teams.""" + i = self.instance.teams() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('teams'), + params={'per_page': 100}, + headers={} + ) + + def test_teams_requires_auth(self): + """Show that one must be authenticated to retrieve an org's teams.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.teams() From 715ec25029a387ba0f7d7613cb105018dfe9fe50 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 17 Jul 2014 23:02:44 -0500 Subject: [PATCH 129/972] Update HISTORY to mention Organization#teams --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index b797128fb..832d59003 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -48,6 +48,7 @@ Old name New name ``Organization#iter_members`` ``Organization#members`` ``Organization#iter_public_members`` ``Organization#public_members`` ``Organization#iter_repos`` ``Organization#repositories`` +``Organization#iter_teams`` ``Organization#teams`` ==================================== ============================================== From 3ef566b3577668359c1711e4e6381f3c21117149 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 18 Jul 2014 08:35:38 -0500 Subject: [PATCH 130/972] Update Team class and tests --- HISTORY.rst | 2 ++ github3/orgs.py | 2 +- tests/test_orgs.py | 8 -------- tests/unit/test_orgs_team.py | 40 ++++++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 tests/unit/test_orgs_team.py diff --git a/HISTORY.rst b/HISTORY.rst index 832d59003..b754752d5 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -49,6 +49,8 @@ Old name New name ``Organization#iter_public_members`` ``Organization#public_members`` ``Organization#iter_repos`` ``Organization#repositories`` ``Organization#iter_teams`` ``Organization#teams`` +``Team#iter_members`` ``Team#members`` +``Team#iter_repos`` ``Team#repositories`` ==================================== ============================================== diff --git a/github3/orgs.py b/github3/orgs.py index c9c554b74..38828128e 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -161,7 +161,7 @@ def members(self, number=-1, etag=None): url = self._build_url('members', base_url=self._api) return self._iter(int(number), url, User, params=params, etag=etag) - def iter_repos(self, number=-1, etag=None): + def repositories(self, number=-1, etag=None): """Iterate over the repositories this team has access to. :param int number: (optional), number of repos to iterate over. diff --git a/tests/test_orgs.py b/tests/test_orgs.py index fc4f3e3a0..30c464406 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -91,14 +91,6 @@ def test_members(self): assert isinstance(next(self.team.members()), github3.users.User) self.mock_assertions() - def test_iter_repos(self): - self.response('repo', _iter=True) - self.get(self.api + '/repos') - - assert isinstance(next(self.team.iter_repos()), - github3.repos.Repository) - self.mock_assertions() - def test_remove_member(self): self.response('', 204) self.delete(self.api + '/members/user') diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py new file mode 100644 index 000000000..857a5ade7 --- /dev/null +++ b/tests/unit/test_orgs_team.py @@ -0,0 +1,40 @@ +from github3.orgs import Team + +from .helper import UnitIteratorHelper + + +def url_for(path=''): + """Simple function to generate URLs with the base Org URL.""" + if path: + path = '/' + path.strip('/') + return 'https://api.github.com/teams/10' + path + + +class TestTeamIterator(UnitIteratorHelper): + described_class = Team + + example_data = { + 'url': url_for() + } + + def test_members(self): + """Show that one can iterate over all members of a Team.""" + i = self.instance.members() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('members'), + params={'per_page': 100}, + headers={} + ) + + def test_repositories(self): + """Show that one can iterate over an organization's repositories.""" + i = self.instance.repositories() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('repos'), + params={'per_page': 100}, + headers={} + ) From 9c326f94bad61bd0e0537e81c7efde5a4fb6fd5b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 18 Jul 2014 19:46:02 -0500 Subject: [PATCH 131/972] Update Organization#iter_events -> Organization#events --- github3/orgs.py | 2 +- tests/test_orgs.py | 7 ------- tests/unit/test_orgs.py | 11 +++++++++++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 38828128e..d2472ed59 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -431,7 +431,7 @@ def is_public_member(self, login): url = self._build_url('public_members', login, base_url=self._api) return self._boolean(self._get(url), 204, 404) - def iter_events(self, number=-1, etag=None): + def events(self, number=-1, etag=None): """Iterate over events for this org. :param int number: (optional), number of events to return. Default: -1 diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 30c464406..2cbc310ab 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -253,13 +253,6 @@ def test_is_public_member(self): assert self.org.is_public_member('user') is True self.mock_assertions() - def test_iter_events(self): - self.response('event', _iter=True) - self.get(self.api + '/events') - - assert isinstance(next(self.org.iter_events()), github3.events.Event) - self.mock_assertions() - def test_publicize_member(self): self.response('', 204) self.put(self.api + '/public_members/user') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index f542abdc2..3b976ea49 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -20,6 +20,17 @@ class TestOrganizationIterator(UnitIteratorHelper): 'url': url_for() } + def test_events(self): + """Show that one can iterate over an organization's events.""" + i = self.instance.events() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('events'), + params={'per_page': 100}, + headers={} + ) + def test_members(self): """Show that one can iterate over all members.""" i = self.instance.members() From 361139037fa32e7abe9623e4f22b6557ee939cb8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 18 Jul 2014 21:27:48 -0500 Subject: [PATCH 132/972] Break how Organization#add_{member,repo} worked - Rename Organization#add_repo -> Organization#add_repository - Rename Team#add_repo -> Team#add_repository - Start new Unit tests for Organization --- HISTORY.rst | 9 +++++++ github3/orgs.py | 56 +++++++++++++++++++++-------------------- tests/unit/test_orgs.py | 27 +++++++++++++++++++- 3 files changed, 64 insertions(+), 28 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index b754752d5..e1d9d04b1 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -12,6 +12,12 @@ It is suggested you read the following release notes *very* carefully. Breaking Changes ```````````````` +- ``Organization#add_member`` has been changed. The second parameter has been + changed to ``team_id`` and now expects an integer. + +- ``Organization#add_repository`` has been changed. The second parameter has been + changed to ``team_id`` and now expects an integer. + - All methods and functions starting with ``iter_`` have been renamed. ==================================== ============================================== @@ -126,6 +132,9 @@ Old name New name - ``Repository#ignore`` ignores notifications from the repository for the authenticated user +- ``Organization#add_repo`` and ``Team#add_repo`` have been renamed to + ``Organization#add_repository`` and ``Team#add_repository`` respectively. + - ``github3.ratelimit_remaining`` was removed - ``GitHub`` instances can no longer be used as context managers diff --git a/github3/orgs.py b/github3/orgs.py index d2472ed59..d98453db6 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -77,13 +77,13 @@ def add_member(self, login): return self._boolean(self._put(url), 204, 404) @requires_auth - def add_repo(self, repo): + def add_repository(self, repository): """Add ``repo`` to this team. :param str repo: (required), form: 'user/repo' :returns: bool """ - url = self._build_url('repos', repo, base_url=self._api) + url = self._build_url('repos', repository, base_url=self._api) return self._boolean(self._put(url), 204, 404) @requires_auth @@ -260,7 +260,7 @@ def __init__(self, org, session=None): self.repos_url = org.get('repos_url') @requires_auth - def add_member(self, login, team): + def add_member(self, login, team_id): """Add ``login`` to ``team`` and thereby to this organization. .. warning:: @@ -271,40 +271,42 @@ def add_member(self, login, team): Any user that is to be added to an organization, must be added to a team as per the GitHub api. - .. note:: - This method is of complexity O(n). This iterates over all teams in - your organization and only adds the user when the team name - matches the team parameter above. If you want constant time, you - should retrieve the team and call ``add_member`` on that team - directly. + .. versionchanged:: 1.0 + + The second parameter used to be ``team`` but has been changed to + ``team_id``. This parameter is now required to be an integer to + improve performance of this method. :param str login: (required), login name of the user to be added - :param str team: (required), team name + :param int team_id: (required), team id :returns: bool """ - for t in self.teams(): - if team == t.name: - return t.add_member(login) - return False + if int(team_id, base=10) < 0: + return False + + url = self._build_url('teams', str(team_id), 'members', str(login)) + return self._boolean(self._put(url), 204, 404) @requires_auth - def add_repo(self, repo, team): - """Add ``repo`` to ``team``. + def add_repository(self, repository, team_id): + """Add ``repository`` to ``team``. - .. note:: - This method is of complexity O(n). This iterates over all teams in - your organization and only adds the repo when the team name - matches the team parameter above. If you want constant time, you - should retrieve the team and call ``add_repo`` on that team - directly. + .. versionchanged:: 1.0 + + The second parameter used to be ``team`` but has been changed to + ``team_id``. This parameter is now required to be an integer to + improve performance of this method. :param str repo: (required), form: 'user/repo' - :param str team: (required), team name + :param int team_id: (required), team id + :returns: bool """ - for t in self.teams(): - if team == t.name: - return t.add_repo(repo) - return False + if int(team_id, base=10) < 0: + return False + + url = self._build_url('teams', str(team_id), 'members', + str(repository)) + return self._boolean(self._put(url), 204, 404) @requires_auth def create_repo(self, diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 3b976ea49..4c3fb5ffe 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -3,7 +3,7 @@ from github3 import GitHubError from github3.orgs import Organization -from .helper import UnitIteratorHelper +from .helper import UnitHelper, UnitIteratorHelper def url_for(path=''): @@ -13,6 +13,31 @@ def url_for(path=''): return 'https://api.github.com/orgs/hapy' + path +class TestOrganization(UnitHelper): + described_class = Organization + example_data = { + 'login': 'hapy', + 'id': 1, + 'url': 'https://api.github.com/orgs/hapy', + 'avatar_url': 'https://github.com/images/error/octocat_happy.gif', + 'name': 'github', + 'company': 'GitHub', + 'blog': 'https://github.com/blog', + 'location': 'San Francisco', + 'email': 'octocat@github.com', + 'public_repos': 2, + 'public_gists': 1, + 'followers': 20, + 'following': 0, + 'html_url': 'https://github.com/hapy', + 'created_at': '2008-01-14T04:33:35Z', + 'type': 'Organization' + } + + def test_add_member(self): + """Show that an authenticated user can add a member to an org.""" + + class TestOrganizationIterator(UnitIteratorHelper): described_class = Organization From b06a680f57aaa61bdca8c3905edc42608971037c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 18 Jul 2014 21:48:10 -0500 Subject: [PATCH 133/972] Do not use an explicit base --- github3/orgs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index d98453db6..2d2ca3f6a 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -281,7 +281,7 @@ def add_member(self, login, team_id): :param int team_id: (required), team id :returns: bool """ - if int(team_id, base=10) < 0: + if int(team_id) < 0: return False url = self._build_url('teams', str(team_id), 'members', str(login)) @@ -301,7 +301,7 @@ def add_repository(self, repository, team_id): :param int team_id: (required), team id :returns: bool """ - if int(team_id, base=10) < 0: + if int(team_id) < 0: return False url = self._build_url('teams', str(team_id), 'members', From 5513a957e6a65402430a3376bbd6e30b4124fce2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 18 Jul 2014 21:48:33 -0500 Subject: [PATCH 134/972] Use the repos endpoint instead of the members endpoint --- github3/orgs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 2d2ca3f6a..3e1054a72 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -304,8 +304,7 @@ def add_repository(self, repository, team_id): if int(team_id) < 0: return False - url = self._build_url('teams', str(team_id), 'members', - str(repository)) + url = self._build_url('teams', str(team_id), 'repos', str(repository)) return self._boolean(self._put(url), 204, 404) @requires_auth From bd6ef0bacd221e54ca8219901e1edf8fad0fbfb2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 18 Jul 2014 21:48:44 -0500 Subject: [PATCH 135/972] Remove old tests for Team and Organization --- tests/test_orgs.py | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 2cbc310ab..dfc530c16 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -33,18 +33,6 @@ def test_add_member(self): assert self.team.add_member('foo') self.mock_assertions() - def test_add_repo(self): - self.response('', 204) - self.put(self.api + '/repos/repo') - self.conf = {'data': None} - - self.assertRaises(github3.GitHubError, self.team.add_repo, 'repo') - - self.not_called() - self.login() - assert self.team.add_repo('repo') - self.mock_assertions() - def test_delete(self): self.response('', 204) self.delete(self.api) @@ -133,34 +121,6 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_add_member(self): - self.assertRaises(github3.GitHubError, self.org.add_member, None, None) - - self.login() - with mock.patch.object(github3.orgs.Organization, 'teams') as it: - it.return_value = iter([]) - assert self.org.add_member('foo', 'bar') is False - team = mock.Mock() - team.name = 'bar' - team.add_member.return_value = True - it.return_value = iter([team]) - assert self.org.add_member('foo', 'bar') - team.add_member.assert_called_once_with('foo') - - def test_add_repo(self): - self.assertRaises(github3.GitHubError, self.org.add_repo, None, None) - - self.login() - with mock.patch.object(github3.orgs.Organization, 'teams') as it: - it.return_value = iter([]) - assert self.org.add_repo('foo', 'bar') is False - team = mock.Mock() - team.name = 'bar' - team.add_repo.return_value = True - it.return_value = iter([team]) - assert self.org.add_repo('foo', 'bar') - team.add_repo.assert_called_once_with('foo') - def test_create_repo(self): self.response('repo', 201) self.post(self.api + '/repos') From 5ff1db012c6d97c2d3552219d5d34c52f3aab128 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 18 Jul 2014 21:49:02 -0500 Subject: [PATCH 136/972] Replace old tests for Organization --- tests/unit/test_orgs.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 4c3fb5ffe..a7d0497c4 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -36,6 +36,33 @@ class TestOrganization(UnitHelper): def test_add_member(self): """Show that an authenticated user can add a member to an org.""" + self.instance.add_member('user', 10) + + self.session.put.assert_called_once_with( + 'https://api.github.com/teams/10/members/user' + ) + + def test_add_member_requires_auth(self): + """Show that one must be authenticated to add a member to an org.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.add_member('user', 10) + + def test_add_repository(self): + """Show that one can add a repository to an organization.""" + self.instance.add_repository('name-of-repo', 10) + + self.session.put.assert_called_once_with( + 'https://api.github.com/teams/10/repos/name-of-repo' + ) + + def test_add_repository_requires_auth(self): + """Show that one must be authenticated to add a repo to an org.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.add_repository('foo', 10) class TestOrganizationIterator(UnitIteratorHelper): From d57a83929edbf395e2dbc217d613d8a8e6d29b6b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 18 Jul 2014 21:49:11 -0500 Subject: [PATCH 137/972] Replace Team tests --- tests/unit/test_orgs_team.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index 857a5ade7..315cec7d7 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -1,6 +1,9 @@ +import pytest + +from github3 import GitHubError from github3.orgs import Team -from .helper import UnitIteratorHelper +from .helper import UnitHelper, UnitIteratorHelper def url_for(path=''): @@ -10,6 +13,37 @@ def url_for(path=''): return 'https://api.github.com/teams/10' + path +class TestTeam(UnitHelper): + described_class = Team + example_data = { + 'url': 'https://api.github.com/teams/10', + 'name': 'Owners', + 'id': 10, + 'permission': 'admin', + 'members_count': 3, + 'repos_count': 10, + 'organization': { + 'login': 'github', + 'id': 1, + 'url': 'https://api.github.com/orgs/github', + 'avatar_url': 'https://github.com/images/error/octocat_happy.gif' + } + } + + def test_add_repository(self): + """Show that one can add a repository to an organization team.""" + self.instance.add_repository('name-of-repo') + + self.session.put.assert_called_once_with(url_for('repos/name-of-repo')) + + def test_add_repository_requires_auth(self): + """Show that adding a repo to a team requires authentication.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.add_repository('repo') + + class TestTeamIterator(UnitIteratorHelper): described_class = Team From 27b6bca8254a4a057c9c50e9459f7f1c933927c2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 10:52:15 -0500 Subject: [PATCH 138/972] Rename Organization#create_repo -> Organization#create_repository - Update parameters to the method --- github3/orgs.py | 25 ++++++++++--------------- tests/test_orgs.py | 26 -------------------------- tests/unit/test_orgs.py | 27 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 3e1054a72..5f4f95f3e 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -308,19 +308,14 @@ def add_repository(self, repository, team_id): return self._boolean(self._put(url), 204, 404) @requires_auth - def create_repo(self, - name, - description='', - homepage='', - private=False, - has_issues=True, - has_wiki=True, - has_downloads=True, - team_id=0, - auto_init=False, - gitignore_template=''): - """Create a repository for this organization if the authenticated user - is a member. + def create_repository(self, name, description='', homepage='', + private=False, has_issues=True, has_wiki=True, + team_id=0, auto_init=False, gitignore_template='', + license_template=''): + """Create a repository for this organization. + + If the client is authenticated and a member of the organization, this + will create a new repository in the organization. :param str name: (required), name of the repository :param str description: (optional) @@ -346,9 +341,9 @@ def create_repo(self, data = {'name': name, 'description': description, 'homepage': homepage, 'private': private, 'has_issues': has_issues, 'has_wiki': has_wiki, - 'has_downloads': has_downloads, 'auto_init': auto_init, + 'license_template': license_template, 'auto_init': auto_init, 'gitignore_template': gitignore_template} - if team_id > 0: + if int(team_id) > 0: data.update({'team_id': team_id}) json = self._json(self._post(url, data), 201) return Repository(json, self) if json else None diff --git a/tests/test_orgs.py b/tests/test_orgs.py index dfc530c16..8948dc87d 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -121,32 +121,6 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_create_repo(self): - self.response('repo', 201) - self.post(self.api + '/repos') - self.conf = { - 'data': { - 'name': 'repo', - 'description': 'desc', - 'homepage': '', - 'private': False, - 'has_issues': True, - 'has_wiki': True, - 'has_downloads': True, - 'auto_init': False, - 'team_id': 1, - 'gitignore_template': '', - } - } - - self.assertRaises(github3.GitHubError, self.org.create_repo, None) - - self.not_called() - self.login() - assert isinstance(self.org.create_repo('repo', 'desc', team_id=1), - github3.repos.Repository) - self.mock_assertions() - def test_conceal_member(self): self.response('', 204) self.delete(self.api + '/public_members/user') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index a7d0497c4..ba734f927 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -64,6 +64,33 @@ def test_add_repository_requires_auth(self): with pytest.raises(GitHubError): self.instance.add_repository('foo', 10) + def test_create_repository(self): + """Show that one can create a repository in an organization.""" + self.instance.create_repository('repo-name', 'description', team_id=1) + + self.post_called_with( + url_for('repos'), + data={ + 'name': 'repo-name', + 'description': 'description', + 'homepage': '', + 'private': False, + 'has_issues': True, + 'has_wiki': True, + 'auto_init': False, + 'team_id': 1, + 'gitignore_template': '', + 'license_template': '' + } + ) + + def test_create_repository_requires_auth(self): + """Show that one must be authenticated to create a repo for an org.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.create_repository('foo') + class TestOrganizationIterator(UnitIteratorHelper): described_class = Organization From 8d2e3eb66c3c492e05bf3d3ec9f609cfbbbefb5d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 10:55:09 -0500 Subject: [PATCH 139/972] Update history. Correct docstring --- HISTORY.rst | 4 ++++ github3/orgs.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index e1d9d04b1..44a391404 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -135,6 +135,10 @@ Old name New name - ``Organization#add_repo`` and ``Team#add_repo`` have been renamed to ``Organization#add_repository`` and ``Team#add_repository`` respectively. +- ``Organization#create_repo`` has been renamed to + ``Organization#create_repository``. It no longer accepts ``has_downloads``. + It now accepts ``license_template``. + - ``github3.ratelimit_remaining`` was removed - ``GitHub`` instances can no longer be used as context managers diff --git a/github3/orgs.py b/github3/orgs.py index 5f4f95f3e..6e83e8156 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -326,13 +326,13 @@ def create_repository(self, name, description='', homepage='', this repository. API default: ``True`` :param bool has_wiki: (optional), If ``True``, enable the wiki for this repository. API default: ``True`` - :param bool has_downloads: (optional), If ``True``, enable downloads - for this repository. API default: ``True`` :param int team_id: (optional), id of the team that will be granted access to this repository :param bool auto_init: (optional), auto initialize the repository. :param str gitignore_template: (optional), name of the template; this is ignored if auto_int = False. + :param str license_template: (optional), name of the license; this + is ignored if auto_int = False. :returns: :class:`Repository ` .. warning: ``name`` should be no longer than 100 characters From 12b594593d7d7b11b4cca6953b89aad448af2e1c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 10:57:35 -0500 Subject: [PATCH 140/972] Replace login with username --- github3/orgs.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 6e83e8156..fcf0209d7 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -63,17 +63,14 @@ def _update_(self, team): self.__init__(team, self._session) @requires_auth - def add_member(self, login): - """Add ``login`` to this team. + def add_member(self, username): + """Add ``username`` to this team. + :param str username: the username of the user you would like to add to + the team. :returns: bool """ - warnings.warn( - 'This is no longer supported by the GitHub API, see ' - 'https://developer.github.com/changes/2014-09-23-one-more-week' - '-before-the-add-team-member-api-breaking-change/', - DeprecationWarning) - url = self._build_url('members', login, base_url=self._api) + url = self._build_url('members', username, base_url=self._api) return self._boolean(self._put(url), 204, 404) @requires_auth From a20c02abe5961be73af9079c547d8c8d50f466ff Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 10:58:17 -0500 Subject: [PATCH 141/972] Fix Team#add_repository docstring --- github3/orgs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index fcf0209d7..84ea963ca 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -75,9 +75,9 @@ def add_member(self, username): @requires_auth def add_repository(self, repository): - """Add ``repo`` to this team. + """Add ``repository`` to this team. - :param str repo: (required), form: 'user/repo' + :param str repository: (required), form: 'user/repo' :returns: bool """ url = self._build_url('repos', repository, base_url=self._api) From 7184e3e7494f7df1e861411ee33f4fc5360eefac Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 15:53:55 -0500 Subject: [PATCH 142/972] Replace login with username --- github3/orgs.py | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 84ea963ca..c132cab48 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -172,29 +172,13 @@ def repositories(self, number=-1, etag=None): return self._iter(int(number), url, Repository, etag=etag) @requires_auth - def membership_for(self, username): - """Retrieve the membership information for the user. + def remove_member(self, username): + """Remove ``username`` from this team. - :param str username: (required), name of the user - :returns: dictionary - """ - url = self._build_url('memberships', username, base_url=self._api) - json = self._json(self._get(url), 200) - return json or {} - - @requires_auth - def remove_member(self, login): - """Remove ``login`` from this team. - - :param str login: (required), login of the member to remove + :param str username: (required), username of the member to remove :returns: bool """ - warnings.warn( - 'This is no longer supported by the GitHub API, see ' - 'https://developer.github.com/changes/2014-09-23-one-more-week' - '-before-the-add-team-member-api-breaking-change/', - DeprecationWarning) - url = self._build_url('members', login, base_url=self._api) + url = self._build_url('members', username, base_url=self._api) return self._boolean(self._delete(url), 204, 404) @requires_auth From acfbf871b7546b42db9b0ead6d12d3a59f7ba158 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 15:55:29 -0500 Subject: [PATCH 143/972] Rename Team#remove_repo to Team#remove_repository --- HISTORY.rst | 3 +++ github3/orgs.py | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 44a391404..214be117a 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -139,6 +139,9 @@ Old name New name ``Organization#create_repository``. It no longer accepts ``has_downloads``. It now accepts ``license_template``. +- ``Organization#remove_repo`` has been renamed to + ``Organization#remove_repository``. + - ``github3.ratelimit_remaining`` was removed - ``GitHub`` instances can no longer be used as context managers diff --git a/github3/orgs.py b/github3/orgs.py index c132cab48..03954b8db 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -192,13 +192,13 @@ def revoke_membership(self, username): return self._boolean(self._delete(url), 204, 404) @requires_auth - def remove_repo(self, repo): - """Remove ``repo`` from this team. + def remove_repository(self, repository): + """Remove ``repository`` from this team. - :param str repo: (required), form: 'user/repo' + :param str repository: (required), form: 'user/repo' :returns: bool """ - url = self._build_url('repos', repo, base_url=self._api) + url = self._build_url('repos', repository, base_url=self._api) return self._boolean(self._delete(url), 204, 404) From 1fdaa1e7b234c0de3752f1bed08124e5693dc23c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 15:58:59 -0500 Subject: [PATCH 144/972] Migrate Team#remove_repo tests --- tests/test_orgs.py | 11 ----------- tests/unit/test_orgs_team.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 8948dc87d..bca33aa0a 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -90,17 +90,6 @@ def test_remove_member(self): assert self.team.remove_member('user') self.mock_assertions() - def test_remove_repo(self): - self.response('', 204) - self.delete(self.api + '/repos/repo') - - self.assertRaises(github3.GitHubError, self.team.remove_repo, None) - - self.not_called() - self.login() - assert self.team.remove_repo('repo') - self.mock_assertions() - class TestOrganization(BaseCase): def __init__(self, methodName='runTest'): diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index 315cec7d7..bf918a181 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -43,6 +43,19 @@ def test_add_repository_requires_auth(self): with pytest.raises(GitHubError): self.instance.add_repository('repo') + def test_remove_repository(self): + """Show that a user can remove a repository from a team.""" + self.instance.remove_repository('repo') + + self.session.delete.assert_called_once_with(url_for('/repos/repo')) + + def test_remove_repository_requires_auth(self): + """Show that removing a repo from a team requires authentication.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.remove_repository('repo') + class TestTeamIterator(UnitIteratorHelper): described_class = Team From 618f369deb21535091ce589003f4b12ebd740fd8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 16:18:35 -0500 Subject: [PATCH 145/972] Replace unnecessary branch --- github3/orgs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 03954b8db..c6ed3d4a7 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -222,8 +222,7 @@ class Organization(BaseAccount): def __init__(self, org, session=None): super(Organization, self).__init__(org, session) - if not self.type: - self.type = 'Organization' + self.type = self.type or 'Organization' #: Events url (not a template) self.events_url = org.get('events_url') From 962dd636b9e3ee99e066de07c93478a29fd2c5f3 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 16:20:21 -0500 Subject: [PATCH 146/972] Fix docstring --- github3/orgs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github3/orgs.py b/github3/orgs.py index c6ed3d4a7..e16fab79f 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -277,7 +277,7 @@ def add_repository(self, repository, team_id): ``team_id``. This parameter is now required to be an integer to improve performance of this method. - :param str repo: (required), form: 'user/repo' + :param str repository: (required), form: 'user/repo' :param int team_id: (required), team id :returns: bool """ From d22a8b63c1a61212d5e39f1547f16783a882554d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 16:28:58 -0500 Subject: [PATCH 147/972] Replace login with username --- github3/orgs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index e16fab79f..3e8d6cdeb 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -329,12 +329,13 @@ def create_repository(self, name, description='', homepage='', return Repository(json, self) if json else None @requires_auth - def conceal_member(self, login): - """Conceal ``login``'s membership in this organization. + def conceal_member(self, username): + """Conceal ``username``'s membership in this organization. + :param str username: username of the organization member to conceal :returns: bool """ - url = self._build_url('public_members', login, base_url=self._api) + url = self._build_url('public_members', username, base_url=self._api) return self._boolean(self._delete(url), 204, 404) @requires_auth From d0fe8c7665f524145f99675efa6e28ab9de42a84 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 19:00:58 -0500 Subject: [PATCH 148/972] Update Organization#create_team docstring --- github3/orgs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 3e8d6cdeb..762d343f5 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -340,8 +340,9 @@ def conceal_member(self, username): @requires_auth def create_team(self, name, repo_names=[], permission=''): - """Assuming the authenticated user owns this organization, - create and return a new team. + """Create a new team and return it. + + This only works if the authenticated user owns this organization. :param str name: (required), name to be given to the team :param list repo_names: (optional) repositories, e.g. From eb7d85b96e136056d6b4ab2d36bc7af296df5c24 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 19:01:05 -0500 Subject: [PATCH 149/972] Consistency --- github3/orgs.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 762d343f5..5db5e92f4 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -365,11 +365,7 @@ def create_team(self, name, repo_names=[], permission=''): return Team(json, self._session) if json else None @requires_auth - def edit(self, - billing_email=None, - company=None, - email=None, - location=None, + def edit(self, billing_email=None, company=None, email=None, location=None, name=None): """Edit this organization. From 5bf8109f9469e37dcac760056403a47f9549e8a2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 19:19:24 -0500 Subject: [PATCH 150/972] Replace login with username --- github3/orgs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 5db5e92f4..1d37574c3 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -389,12 +389,13 @@ def edit(self, billing_email=None, company=None, email=None, location=None, return True return False - def is_member(self, login): - """Check if the user with login ``login`` is a member. + def is_member(self, username): + """Check if the user named ``username`` is a member. + :param str username: name of the user you'd like to check :returns: bool """ - url = self._build_url('members', login, base_url=self._api) + url = self._build_url('members', username, base_url=self._api) return self._boolean(self._get(url), 204, 404) def is_public_member(self, login): From b145a53dab8e157cd9503e6b0b533973a9403c37 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 19:22:54 -0500 Subject: [PATCH 151/972] Use username instead of login --- github3/orgs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 1d37574c3..e448caa9e 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -398,12 +398,13 @@ def is_member(self, username): url = self._build_url('members', username, base_url=self._api) return self._boolean(self._get(url), 204, 404) - def is_public_member(self, login): - """Check if the user with login ``login`` is a public member. + def is_public_member(self, username): + """Check if the user named ``username`` is a public member. + :param str username: name of the user you'd like to check :returns: bool """ - url = self._build_url('public_members', login, base_url=self._api) + url = self._build_url('public_members', username, base_url=self._api) return self._boolean(self._get(url), 204, 404) def events(self, number=-1, etag=None): From 8bdaae4e137017a3377bc9bf29ef0b8032efde70 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 19:25:56 -0500 Subject: [PATCH 152/972] Various pep257 fixes --- github3/orgs.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index e448caa9e..ecafbf0b0 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -108,7 +108,7 @@ def edit(self, name, permission=''): return False def has_repo(self, repo): - """Checks if this team has access to ``repo`` + """Check if this team has access to ``repo``. :param str repo: (required), form: 'user/repo' :returns: bool @@ -140,7 +140,7 @@ def is_member(self, login): return self._boolean(self._get(url), 204, 404) def members(self, number=-1, etag=None): - """Iterate over the members of this team. + r"""Iterate over the members of this team. :param str filter: (optional), filter members returned by this method. Can be one of: ``"2fa_disabled"``, ``"all"``. Default: ``"all"``. @@ -408,7 +408,7 @@ def is_public_member(self, username): return self._boolean(self._get(url), 204, 404) def events(self, number=-1, etag=None): - """Iterate over events for this org. + r"""Iterate over events for this org. :param int number: (optional), number of events to return. Default: -1 iterates over all events available. @@ -420,7 +420,7 @@ def events(self, number=-1, etag=None): return self._iter(int(number), url, Event, etag=etag) def members(self, number=-1, etag=None): - """Iterate over members of this organization. + r"""Iterate over members of this organization. :param int number: (optional), number of members to return. Default: -1 will return all available. @@ -432,7 +432,7 @@ def members(self, number=-1, etag=None): return self._iter(int(number), url, User, etag=etag) def public_members(self, number=-1, etag=None): - """Iterate over public members of this organization. + r"""Iterate over public members of this organization. :param int number: (optional), number of members to return. Default: -1 will return all available. @@ -444,7 +444,7 @@ def public_members(self, number=-1, etag=None): return self._iter(int(number), url, User, etag=etag) def repositories(self, type='', number=-1, etag=None): - """Iterate over repos for this organization. + r"""Iterate over repos for this organization. :param str type: (optional), accepted values: ('all', 'public', 'member', 'private', 'forks', 'sources'), API @@ -463,7 +463,7 @@ def repositories(self, type='', number=-1, etag=None): @requires_auth def teams(self, number=-1, etag=None): - """Iterate over teams that are part of this organization. + r"""Iterate over teams that are part of this organization. :param int number: (optional), number of teams to return. Default: -1 returns all available teams. @@ -485,8 +485,7 @@ def publicize_member(self, login): @requires_auth def remove_member(self, login): - """Remove the user with login ``login`` from this - organization. + """Remove the user with login ``login`` from this organization. :returns: bool """ @@ -508,8 +507,7 @@ def remove_repo(self, repo, team): @requires_auth def team(self, team_id): - """Returns Team object with information about team specified by - ``team_id``. + """Return the team specified by ``team_id``. :param int team_id: (required), unique id for the team :returns: :class:`Team ` From cffa6bde0874a1baafec1b1bee1564db091e232a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 19:53:17 -0500 Subject: [PATCH 153/972] Use username instead of login --- github3/orgs.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index ecafbf0b0..467345246 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -475,12 +475,14 @@ def teams(self, number=-1, etag=None): return self._iter(int(number), url, Team, etag=etag) @requires_auth - def publicize_member(self, login): - """Make ``login``'s membership in this organization public. + def publicize_member(self, username): + """Make ``username``'s membership in this organization public. + :param str username: the name of the user whose membership you wish to + publicize :returns: bool """ - url = self._build_url('public_members', login, base_url=self._api) + url = self._build_url('public_members', username, base_url=self._api) return self._boolean(self._put(url), 204, 404) @requires_auth From e428b9b58c4a75fc184ca693ed42538b46c2ed2f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 20:01:56 -0500 Subject: [PATCH 154/972] Replace login with username --- github3/orgs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 467345246..a72362855 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -486,12 +486,13 @@ def publicize_member(self, username): return self._boolean(self._put(url), 204, 404) @requires_auth - def remove_member(self, login): - """Remove the user with login ``login`` from this organization. + def remove_member(self, username): + """Remove the user named ``username`` from this organization. + :param str username: name of the user to remove from the org :returns: bool """ - url = self._build_url('members', login, base_url=self._api) + url = self._build_url('members', username, base_url=self._api) return self._boolean(self._delete(url), 204, 404) @requires_auth From 8756098b7253db2bc5ac51470fbb659f91f8f0b5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 20:35:45 -0500 Subject: [PATCH 155/972] Rename Organization#remove_repo to Organization#remove_repository --- HISTORY.rst | 3 ++- github3/orgs.py | 15 ++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 214be117a..04cf19580 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -140,7 +140,8 @@ Old name New name It now accepts ``license_template``. - ``Organization#remove_repo`` has been renamed to - ``Organization#remove_repository``. + ``Organization#remove_repository``. It now accepts ``team_id`` instead of + ``team``. - ``github3.ratelimit_remaining`` was removed diff --git a/github3/orgs.py b/github3/orgs.py index a72362855..6472a121b 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -496,16 +496,17 @@ def remove_member(self, username): return self._boolean(self._delete(url), 204, 404) @requires_auth - def remove_repo(self, repo, team): - """Remove ``repo`` from ``team``. + def remove_repository(self, repository, team_id): + """Remove ``repository`` from the team with ``team_id``. - :param str repo: (required), form: 'user/repo' - :param str team: (required) + :param str repository: (required), form: 'user/repo' + :param int team_id: (required) :returns: bool """ - for t in self.teams(): - if team == t.name: - return t.remove_repo(repo) + if int(team_id) > 0: + url = self._build_url('teams', str(team_id), 'repos', + str(repository)) + return self._boolean(self._delete(url), 204, 404) return False @requires_auth From e986504cc28db148623fb78ee9e9995b037d8951 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 20:36:02 -0500 Subject: [PATCH 156/972] Migrate Organization#remove_repository tests --- tests/test_orgs.py | 17 +---------------- tests/unit/test_orgs.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index bca33aa0a..6a191101d 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -1,5 +1,5 @@ import github3 -from tests.utils import BaseCase, load, mock +from tests.utils import BaseCase, load class TestTeam(BaseCase): @@ -198,21 +198,6 @@ def test_remove_member(self): assert self.org.remove_member('user') is False self.mock_assertions() - def test_remove_repo(self): - self.assertRaises(github3.GitHubError, self.org.remove_repo, - None, None) - - self.login() - with mock.patch.object(github3.orgs.Organization, 'teams') as it: - it.return_value = iter([]) - assert self.org.remove_repo('foo', 'bar') is False - team = mock.Mock() - team.name = 'bar' - team.remove_repo.return_value = True - it.return_value = iter([team]) - assert self.org.remove_repo('foo', 'bar') is True - team.remove_repo.assert_called_once_with('foo') - def test_team(self): self.response('team') self.get(self.github_url + 'teams/1') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index ba734f927..d3d0f79c8 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -91,6 +91,27 @@ def test_create_repository_requires_auth(self): with pytest.raises(GitHubError): self.instance.create_repository('foo') + def test_remove_repository(self): + """Show that one can remove a repository from a team.""" + self.instance.remove_repository('repo-name', 10) + + self.session.delete.assert_called_once_with( + 'https://api.github.com/teams/10/repos/repo-name' + ) + + def test_remove_repository_requires_positive_team_id(self): + """Show that remove_repository requires a team_id greater than 0.""" + assert self.instance.remove_repository('name', -1) is False + + assert self.session.delete.called is False + + def test_remove_repository_requires_auth(self): + """Show that a user must be authenticated to remove a repository.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.remove_repository('repo-name', 10) + class TestOrganizationIterator(UnitIteratorHelper): described_class = Organization From 7c576ed31c3b2b7ef3d26e71b0e4c4bd7546fd0f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 21:36:24 -0500 Subject: [PATCH 157/972] One last conversion of login to username --- github3/orgs.py | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 6472a121b..5befd969b 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -116,27 +116,13 @@ def has_repo(self, repo): url = self._build_url('repos', repo, base_url=self._api) return self._boolean(self._get(url), 204, 404) - @requires_auth - def invite(self, username): - """Invite the user to join this team. - - This returns a dictionary like so:: - - {'state': 'pending', 'url': 'https://api.github.com/teams/...'} - - :param str username: (required), user to invite to join this team. - :returns: dictionary - """ - url = self._build_url('memberships', username, base_url=self._api) - return self._json(self._put(url), 200) - - def is_member(self, login): - """Check if ``login`` is a member of this team. + def is_member(self, username): + """Check if ``username`` is a member of this team. - :param str login: (required), login name of the user + :param str username: (required), username name of the user :returns: bool """ - url = self._build_url('members', login, base_url=self._api) + url = self._build_url('members', username, base_url=self._api) return self._boolean(self._get(url), 204, 404) def members(self, number=-1, etag=None): @@ -240,8 +226,8 @@ def __init__(self, org, session=None): self.repos_url = org.get('repos_url') @requires_auth - def add_member(self, login, team_id): - """Add ``login`` to ``team`` and thereby to this organization. + def add_member(self, username, team_id): + """Add ``username`` to ``team`` and thereby to this organization. .. warning:: This method is no longer valid. To add a member to a team, you @@ -257,14 +243,14 @@ def add_member(self, login, team_id): ``team_id``. This parameter is now required to be an integer to improve performance of this method. - :param str login: (required), login name of the user to be added + :param str username: (required), login name of the user to be added :param int team_id: (required), team id :returns: bool """ if int(team_id) < 0: return False - url = self._build_url('teams', str(team_id), 'members', str(login)) + url = self._build_url('teams', str(team_id), 'members', str(username)) return self._boolean(self._put(url), 204, 404) @requires_auth From d2792eb8c640e2e9738ed0f64d2c66b303d28abb Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 19 Jul 2014 21:43:00 -0500 Subject: [PATCH 158/972] Start integration testing the Organization class --- tests/cassettes/Organization_add_member.json | 1 + tests/integration/test_orgs.py | 0 2 files changed, 1 insertion(+) create mode 100644 tests/cassettes/Organization_add_member.json create mode 100644 tests/integration/test_orgs.py diff --git a/tests/cassettes/Organization_add_member.json b/tests/cassettes/Organization_add_member.json new file mode 100644 index 000000000..897b6c8ec --- /dev/null +++ b/tests/cassettes/Organization_add_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA51Sy3LCIBT9F9YxD2K0ZdP+QTeuusncJASZEmCA6FjHf+/Nwxrtyu7CyT2X8+BMlBFSE0aEDPu+yu2JREQ2hGXbF5oVm4j0TuHvfQjWsyQBK+NpNK5NlxgnfLKkOm6NL5/gJCMDL+UHrsNz1ImC3I53FXfPkWfOOZk+LrjG9pWSdfmfbffU5VI4QAD3GMkI+jnK3nNXGx0wgDHVPpnTf0NRGjp+6yceC8IhC/q0gKVBuMIyCdO9UhH2WkOQBqudzrwDiUVOh1ntFD0rfp0L6YMnLI1Ia5QyR8x0cZIat+O/fejUg5/Fk1i+htpxCLwpIaBUmmZ0lRYrut2la0YLlm8+UXRvm7uZ9TCT0V1KWZGx/HWYCSc7ZPDhBGj5PflC1ARQpXUSw+TlbAb1maPGO//iV+TmspH+q+w9CNyepeshWKWgMg6Cma1XUik0Xs75EeFiaNsYhqZU3EkdC3N4F0O6Q3fDK1KAqZ+vxbWOc0S9hRpvydMtTVHjo7rL5QeAH8A5iwMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"96201f4717f724b9c677d987fe7172ee\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4984", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3D:238A4C5:53CB2C93", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Mon, 12 May 2014 02:51:39 GMT", "date": "Sun, 20 Jul 2014 02:42:27 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405826331"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T02:42:28"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63SzYrCMBQF4FeRrKuJimC61bU+gAxDai82kOSG/OBCfPcJbSxjZxatdNc295zwJb08iBEaSEnOdwPOk4LImpTrPedsXRCv4i2t4WvNgtPSe4kmfRW1liYFolPprQnB+pJSYeXqJkMTq9UVNQ0gtKddX5rVoKu0zffoDM2JR354phIHFr0M6CRMaWpj5Fn05AMqJSp0IlX1cs7YftvLr4ORtwOwUamR/rZ1or/NzOLvmv7xm+BkFQd8xn/x3yYGet+M1zM+Xc/4XPrU9Ed/xMUJw+IICgLk/55vtju+6/k1Lg2GZf0a+fD2u9Zp/i4zhz83Zf/XDzsPJ7byAwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f2ac1c071e4bd300c5bf11848d67d16\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4983", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3D:238A51C:53CB2C93", "cache-control": "private, max-age=60, s-maxage=60", "date": "Sun, 20 Jul 2014 02:42:27 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405826331"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "recorded_at": "2014-07-20T02:42:28"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/teams/923595/members/esacteksab"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4982", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:1C3D:238A538:53CB2C93", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 02:42:27 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405826331"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/923595/members/esacteksab"}, "recorded_at": "2014-07-20T02:42:28"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py new file mode 100644 index 000000000..e69de29bb From c5cc5ba3647d4fbe34d8055d52b3cccef2a39aca Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 07:33:34 -0500 Subject: [PATCH 159/972] Put tests in correct file and add test for add_repository --- .../Organization_add_repository.json | 1 + tests/integration/test_orgs.py | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/cassettes/Organization_add_repository.json diff --git a/tests/cassettes/Organization_add_repository.json b/tests/cassettes/Organization_add_repository.json new file mode 100644 index 000000000..72df32cb0 --- /dev/null +++ b/tests/cassettes/Organization_add_repository.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA51Sy3LCIBT9F9YxD2K0ZdP+QTeuusncJASZEmCA6FjHf+/Nwxrtyu7CyT2X8+BMlBFSE0aEDPu+yu2JREQ2hGXbF5oVm4j0TuHvfQjWsyQBK+NpNK5NlxgnfLKkOm6NL5/gJCMDL+UHrsNz1ImC3I53FXfPkWfOOZk+LrjG9pWSdfmfbffU5VI4QAD3GMkI+jnK3nNXGx0wgDHVPpnTf0NRGjp+6yceC8IhC/q0gKVBuMIyCdO9UhH2WkOQBqudzrwDiUVOh1ntFD0rfp0L6YMnLI1Ia5QyR8x0cZIat+O/fejUg5/Fk1i+htpxCLwpIaBUmmZ0lRYrut2la0YLlm8+UXRvm7uZ9TCT0V1KWZGx/HWYCSc7ZPDhBGj5PflC1ARQpXUSw+TlbAb1maPGO//iV+TmspH+q+w9CNyepeshWKWgMg6Cma1XUik0Xs75EeFiaNsYhqZU3EkdC3N4F0O6Q3fDK1KAqZ+vxbWOc0S9hRpvydMtTVHjo7rL5QeAH8A5iwMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"96201f4717f724b9c677d987fe7172ee\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4985", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:28C299C:53CBB666", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Mon, 12 May 2014 02:51:39 GMT", "date": "Sun, 20 Jul 2014 12:30:30 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405861497"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T12:30:30"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63SzYrCMBQF4FeRrKuJimC61bU+gAxDai82kOSG/OBCfPcJbSxjZxatdNc295zwJb08iBEaSEnOdwPOk4LImpTrPedsXRCv4i2t4WvNgtPSe4kmfRW1liYFolPprQnB+pJSYeXqJkMTq9UVNQ0gtKddX5rVoKu0zffoDM2JR354phIHFr0M6CRMaWpj5Fn05AMqJSp0IlX1cs7YftvLr4ORtwOwUamR/rZ1or/NzOLvmv7xm+BkFQd8xn/x3yYGet+M1zM+Xc/4XPrU9Ed/xMUJw+IICgLk/55vtju+6/k1Lg2GZf0a+fD2u9Zp/i4zhz83Zf/XDzsPJ7byAwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f2ac1c071e4bd300c5bf11848d67d16\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4984", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:28C29E1:53CBB666", "cache-control": "private, max-age=60, s-maxage=60", "date": "Sun, 20 Jul 2014 12:30:30 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405861497"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "recorded_at": "2014-07-20T12:30:30"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/teams/923595/repos/github3py/urllib3"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4983", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:1C3C:28C2A03:53CBB666", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 12:30:30 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405861497"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/923595/repos/github3py/urllib3"}, "recorded_at": "2014-07-20T12:30:31"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index e69de29bb..c0b4886d5 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +"""Integration tests for methods implemented on Organization.""" +import github3 + +from .helper import IntegrationHelper + + +class TestOrganization(IntegrationHelper): + + """Organization integration tests.""" + + def test_add_member(self): + """Test the ability to add a member to an organization.""" + self.basic_login() + cassette_name = self.cassette_name('add_member') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + for team in o.teams(): + if team.name == 'Do Not Delete': + break + else: + assert False, 'Could not find team' + assert o.add_member('esacteksab', team.id) is True + + def test_add_repository(self): + """Test the ability to add a repository to an organization.""" + self.basic_login() + cassette_name = self.cassette_name('add_repository') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + for team in o.teams(): + if team.name == 'Do Not Delete': + break + else: + assert False, 'Could not find team' + + assert o.add_repository('github3py/urllib3', team.id) is True From e94c94209073338f4d804e80e8137170ebea99bb Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 08:14:47 -0500 Subject: [PATCH 160/972] Include betamax_matchers and start using them --- dev-requirements.txt | 1 + tests/conftest.py | 4 ++++ tests/integration/test_orgs.py | 2 ++ 3 files changed, 7 insertions(+) diff --git a/dev-requirements.txt b/dev-requirements.txt index 6ab032431..6ea91ae66 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -5,3 +5,4 @@ mock==1.0.1 pytest>=2.3.5 wheel==0.21.0 git+git://github.com/sigmavirus24/betamax +git+git://github.com/sigmavirus24/betamax_matchers diff --git a/tests/conftest.py b/tests/conftest.py index 81cbc145f..cc9e5d290 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,9 +2,13 @@ import betamax import os +from betamax_matchers import json_body + credentials = [os.environ.get('GH_USER', 'foo').encode(), os.environ.get('GH_PASSWORD', 'bar').encode()] +betamax.Betamax.register_request_matcher(json_body.JSONBodyMatcher) + with betamax.Betamax.configure() as config: config.cassette_library_dir = 'tests/cassettes' diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index c0b4886d5..a15079bdd 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -9,6 +9,8 @@ class TestOrganization(IntegrationHelper): """Organization integration tests.""" + betamax_kwargs = {'match_requests_on': ['method', 'uri', 'json-body']} + def test_add_member(self): """Test the ability to add a member to an organization.""" self.basic_login() From f627a1e1d1cb26e537c67cf2e5b6bbac55b55a2f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 08:15:07 -0500 Subject: [PATCH 161/972] Record test for Organization#create_repository --- tests/cassettes/Organization_create_repository.json | 1 + tests/integration/test_orgs.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/cassettes/Organization_create_repository.json diff --git a/tests/cassettes/Organization_create_repository.json b/tests/cassettes/Organization_create_repository.json new file mode 100644 index 000000000..f7d15b598 --- /dev/null +++ b/tests/cassettes/Organization_create_repository.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA51Sy3LCIBT9F9YxD2K0ZdP+QTeuusncJASZEmCA6FjHf+/Nwxrtyu7CyT2X8+BMlBFSE0aEDPu+yu2JREQ2hGXbF5oVm4j0TuHvfQjWsyQBK+NpNK5NlxgnfLKkOm6NL5/gJCMDL+UHrsNz1ImC3I53FXfPkWfOOZk+LrjG9pWSdfmfbffU5VI4QAD3GMkI+jnK3nNXGx0wgDHVPpnTf0NRGjp+6yceC8IhC/q0gKVBuMIyCdO9UhH2WkOQBqudzrwDiUVOh1ntFD0rfp0L6YMnLI1Ia5QyR8x0cZIat+O/fejUg5/Fk1i+htpxCLwpIaBUmmZ0lRYrut2la0YLlm8+UXRvm7uZ9TCT0V1KWZGx/HWYCSc7ZPDhBGj5PflC1ARQpXUSw+TlbAb1maPGO//iV+TmspH+q+w9CNyepeshWKWgMg6Cma1XUik0Xs75EeFiaNsYhqZU3EkdC3N4F0O6Q3fDK1KAqZ+vxbWOc0S9hRpvydMtTVHjo7rL5QeAH8A5iwMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"96201f4717f724b9c677d987fe7172ee\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4987", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:3AFE:28F3119:53CBC0AC", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Mon, 12 May 2014 02:51:39 GMT", "date": "Sun, 20 Jul 2014 13:14:21 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405865168"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T13:14:21"}, {"request": {"body": {"string": "{\"gitignore_template\": \"\", \"has_wiki\": true, \"name\": \"test-repository\", \"auto_init\": false, \"has_issues\": true, \"license_template\": \"\", \"homepage\": \"\", \"private\": false, \"description\": \"hi\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "190", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "POST", "uri": "https://api.github.com/orgs/github3py/repos"}, "response": {"body": {"string": "{\"id\":22033498,\"name\":\"test-repository\",\"full_name\":\"github3py/test-repository\",\"owner\":{\"login\":\"github3py\",\"id\":1782156,\"avatar_url\":\"https://avatars.githubusercontent.com/u/1782156?\",\"gravatar_id\":\"396e3de53320abf9855d912cd3d9431f\",\"url\":\"https://api.github.com/users/github3py\",\"html_url\":\"https://github.com/github3py\",\"followers_url\":\"https://api.github.com/users/github3py/followers\",\"following_url\":\"https://api.github.com/users/github3py/following{/other_user}\",\"gists_url\":\"https://api.github.com/users/github3py/gists{/gist_id}\",\"starred_url\":\"https://api.github.com/users/github3py/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/github3py/subscriptions\",\"organizations_url\":\"https://api.github.com/users/github3py/orgs\",\"repos_url\":\"https://api.github.com/users/github3py/repos\",\"events_url\":\"https://api.github.com/users/github3py/events{/privacy}\",\"received_events_url\":\"https://api.github.com/users/github3py/received_events\",\"type\":\"Organization\",\"site_admin\":false},\"private\":false,\"html_url\":\"https://github.com/github3py/test-repository\",\"description\":\"hi\",\"fork\":false,\"url\":\"https://api.github.com/repos/github3py/test-repository\",\"forks_url\":\"https://api.github.com/repos/github3py/test-repository/forks\",\"keys_url\":\"https://api.github.com/repos/github3py/test-repository/keys{/key_id}\",\"collaborators_url\":\"https://api.github.com/repos/github3py/test-repository/collaborators{/collaborator}\",\"teams_url\":\"https://api.github.com/repos/github3py/test-repository/teams\",\"hooks_url\":\"https://api.github.com/repos/github3py/test-repository/hooks\",\"issue_events_url\":\"https://api.github.com/repos/github3py/test-repository/issues/events{/number}\",\"events_url\":\"https://api.github.com/repos/github3py/test-repository/events\",\"assignees_url\":\"https://api.github.com/repos/github3py/test-repository/assignees{/user}\",\"branches_url\":\"https://api.github.com/repos/github3py/test-repository/branches{/branch}\",\"tags_url\":\"https://api.github.com/repos/github3py/test-repository/tags\",\"blobs_url\":\"https://api.github.com/repos/github3py/test-repository/git/blobs{/sha}\",\"git_tags_url\":\"https://api.github.com/repos/github3py/test-repository/git/tags{/sha}\",\"git_refs_url\":\"https://api.github.com/repos/github3py/test-repository/git/refs{/sha}\",\"trees_url\":\"https://api.github.com/repos/github3py/test-repository/git/trees{/sha}\",\"statuses_url\":\"https://api.github.com/repos/github3py/test-repository/statuses/{sha}\",\"languages_url\":\"https://api.github.com/repos/github3py/test-repository/languages\",\"stargazers_url\":\"https://api.github.com/repos/github3py/test-repository/stargazers\",\"contributors_url\":\"https://api.github.com/repos/github3py/test-repository/contributors\",\"subscribers_url\":\"https://api.github.com/repos/github3py/test-repository/subscribers\",\"subscription_url\":\"https://api.github.com/repos/github3py/test-repository/subscription\",\"commits_url\":\"https://api.github.com/repos/github3py/test-repository/commits{/sha}\",\"git_commits_url\":\"https://api.github.com/repos/github3py/test-repository/git/commits{/sha}\",\"comments_url\":\"https://api.github.com/repos/github3py/test-repository/comments{/number}\",\"issue_comment_url\":\"https://api.github.com/repos/github3py/test-repository/issues/comments/{number}\",\"contents_url\":\"https://api.github.com/repos/github3py/test-repository/contents/{+path}\",\"compare_url\":\"https://api.github.com/repos/github3py/test-repository/compare/{base}...{head}\",\"merges_url\":\"https://api.github.com/repos/github3py/test-repository/merges\",\"archive_url\":\"https://api.github.com/repos/github3py/test-repository/{archive_format}{/ref}\",\"downloads_url\":\"https://api.github.com/repos/github3py/test-repository/downloads\",\"issues_url\":\"https://api.github.com/repos/github3py/test-repository/issues{/number}\",\"pulls_url\":\"https://api.github.com/repos/github3py/test-repository/pulls{/number}\",\"milestones_url\":\"https://api.github.com/repos/github3py/test-repository/milestones{/number}\",\"notifications_url\":\"https://api.github.com/repos/github3py/test-repository/notifications{?since,all,participating}\",\"labels_url\":\"https://api.github.com/repos/github3py/test-repository/labels{/name}\",\"releases_url\":\"https://api.github.com/repos/github3py/test-repository/releases{/id}\",\"created_at\":\"2014-07-20T13:14:21Z\",\"updated_at\":\"2014-07-20T13:14:21Z\",\"pushed_at\":\"2014-07-20T13:14:21Z\",\"git_url\":\"git://github.com/github3py/test-repository.git\",\"ssh_url\":\"git@github.com:github3py/test-repository.git\",\"clone_url\":\"https://github.com/github3py/test-repository.git\",\"svn_url\":\"https://github.com/github3py/test-repository\",\"homepage\":\"\",\"size\":0,\"stargazers_count\":0,\"watchers_count\":0,\"language\":null,\"has_issues\":true,\"has_downloads\":true,\"has_wiki\":true,\"forks_count\":0,\"mirror_url\":null,\"open_issues_count\":0,\"forks\":0,\"open_issues\":0,\"watchers\":0,\"default_branch\":\"master\",\"permissions\":{\"admin\":true,\"push\":true,\"pull\":true},\"organization\":{\"login\":\"github3py\",\"id\":1782156,\"avatar_url\":\"https://avatars.githubusercontent.com/u/1782156?\",\"gravatar_id\":\"396e3de53320abf9855d912cd3d9431f\",\"url\":\"https://api.github.com/users/github3py\",\"html_url\":\"https://github.com/github3py\",\"followers_url\":\"https://api.github.com/users/github3py/followers\",\"following_url\":\"https://api.github.com/users/github3py/following{/other_user}\",\"gists_url\":\"https://api.github.com/users/github3py/gists{/gist_id}\",\"starred_url\":\"https://api.github.com/users/github3py/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/github3py/subscriptions\",\"organizations_url\":\"https://api.github.com/users/github3py/orgs\",\"repos_url\":\"https://api.github.com/users/github3py/repos\",\"events_url\":\"https://api.github.com/users/github3py/events{/privacy}\",\"received_events_url\":\"https://api.github.com/users/github3py/received_events\",\"type\":\"Organization\",\"site_admin\":false},\"network_count\":0,\"subscribers_count\":1}", "encoding": "utf-8"}, "headers": {"content-length": "5872", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"609989154b40836a01d8114d325ecb50\"", "location": "https://api.github.com/repos/github3py/test-repository", "access-control-allow-credentials": "true", "status": "201 Created", "x-ratelimit-remaining": "4986", "x-github-media-type": "github.v3; param=full; 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": "48A0C4D3:3AFE:28F3156:53CBC0AD", "cache-control": "private, max-age=60, s-maxage=60", "date": "Sun, 20 Jul 2014 13:14:21 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405865168"}, "status": {"message": "Created", "code": 201}, "url": "https://api.github.com/orgs/github3py/repos"}, "recorded_at": "2014-07-20T13:14:21"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/repos/github3py/test-repository"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4985", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:3AFE:28F31A3:53CBC0AD", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 13:14:21 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405865168"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/repos/github3py/test-repository"}, "recorded_at": "2014-07-20T13:14:21"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index a15079bdd..5a530a1d2 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -40,3 +40,15 @@ def test_add_repository(self): assert False, 'Could not find team' assert o.add_repository('github3py/urllib3', team.id) is True + + def test_create_repository(self): + """Test the ability to create a repository in an organization.""" + self.basic_login() + cassette_name = self.cassette_name('create_repository') + with self.recorder.use_cassette(cassette_name, **self.betamax_kwargs): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + r = o.create_repository('test-repository', description='hi') + assert isinstance(r, github3.repos.Repository) + assert r.delete() is True From 211d9fdb0ee3d759f1fade3fd87a9270bcb3ec3f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 10:07:08 -0500 Subject: [PATCH 162/972] Add integration test for Organizatio#conceal_member --- .../cassettes/Organization_conceal_member.json | 1 + tests/integration/test_orgs.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/cassettes/Organization_conceal_member.json diff --git a/tests/cassettes/Organization_conceal_member.json b/tests/cassettes/Organization_conceal_member.json new file mode 100644 index 000000000..bb1fd6fea --- /dev/null +++ b/tests/cassettes/Organization_conceal_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA51Sy3KDIBT9F9ZGUWPssGn/oJusunGuioQpAgOYTJrJv/f6SGPTVbqT4z2X8+BClBFSE0aEDIehzu2ZRES2hKXlS5YWu4gMTuHvQwjWsyQBK+N5NG5MnxgnfLKmOm6Nr57gJBMDL+VHrsNz1JmC3J73NXfPkRfOJZk/rrjGDrWSTfWfbb+p66VwhADuMZIJ9EuUg+euMTpgAFOqQ7Kk/4qiNPT83k88FYRDFvR5BUuDcI1lEqYHpSLstYEgDVY7n3kPEoucD4vaOXpW/DgX0gdPGI1IZ5QyJ8x0dZIat+O/Q+jVg5/Vk1i/hsZxCLytIKDUjKbZhhabrNzTLcsKlu8+UPRg218z2w0tNxndpzlLcSwdZ8LZjhm8OwFafs2+EDUBVGWdxDB5tZhBfeak8c6/+A25u2yl/6wGDwK3p3Q7BqsU1MZBMIv1WiqFxqslPyJcDF0Xw9iUinupY2GOb2JMd+xufEUKMPXLrbjOcY6ot9DgLTktM4oaH9Vdr99KSPnAiwMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"035b23d4556a47c056f25f2f67342d25\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4933", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:3AFF:3646132:53CBDB03", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 13:14:21 GMT", "date": "Sun, 20 Jul 2014 15:06:43 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405868958"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T15:06:43"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/public_members?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52Ty26DMBBF/8XrKA6PJMAmX9FVVSFjBhgJbGQbohTl3zsGVKlsKliBkM+Z64v9ObFW16hYxizWnRjRDDaM2YlhybIwviTR5cTEKJww+WBaWtc419uM8+WjPdfomqEYLBiplQPlzlJ3fOAL/CBVbVaBdzIZxEl0vZVJWqXhFW5pGNyTAiAo00jI6k7AZlCP65DFTJMs36RtXNdu8i25ZmSzuNJtq59k2e7ov0H8l6SQyzuq+qCFyIlr1wAVS1t6+6LQuv2hZmri/pFj6T2W/paBcnewlaNYT0WJJm6g17NwKKw02DvUan/APzTZtKmFwm9xzEa0JYmPtj/KTBENIx3U/fiCTbw3OAr58tUYkIAjlX1QueHJ6F490D35oEPhq0cHuSg7f0cr0Vp4f/0A/p8Y7LUDAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"6e61732b48fdd33d664a49419e6ae91c\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4932", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:3AFF:36461A0:53CBDB03", "cache-control": "private, max-age=60, s-maxage=60", "date": "Sun, 20 Jul 2014 15:06:43 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405868958"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/public_members?per_page=100"}, "recorded_at": "2014-07-20T15:06:43"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/orgs/github3py/public_members/sigmavirus24"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4931", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:3AFF:36461D6:53CBDB03", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 15:06:43 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405868958"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/orgs/github3py/public_members/sigmavirus24"}, "recorded_at": "2014-07-20T15:06:43"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/orgs/github3py/public_members/sigmavirus24"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4930", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:3AFF:364621D:53CBDB03", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 15:06:43 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405868958"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/orgs/github3py/public_members/sigmavirus24"}, "recorded_at": "2014-07-20T15:06:44"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 5a530a1d2..2a504ec9c 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -52,3 +52,20 @@ def test_create_repository(self): r = o.create_repository('test-repository', description='hi') assert isinstance(r, github3.repos.Repository) assert r.delete() is True + + def test_conceal_member(self): + """Test the ability to conceal a User's membership.""" + self.basic_login() + cassette_name = self.cassette_name('conceal_member') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + # Get a public member of the organization + public_member = next(o.public_members()) + assert isinstance(public_member, github3.users.User) + + # Conceal their membership + assert o.conceal_member(public_member) is True + # Re-publicize their membership + assert o.publicize_member(public_member) is True From 2b0d5416704f30aa5d6677db06220d500a99eebb Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 10:31:17 -0500 Subject: [PATCH 163/972] Add integration test for Organization#create_team --- tests/cassettes/Organization_create_team.json | 1 + tests/integration/test_orgs.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/cassettes/Organization_create_team.json diff --git a/tests/cassettes/Organization_create_team.json b/tests/cassettes/Organization_create_team.json new file mode 100644 index 000000000..2ba445286 --- /dev/null +++ b/tests/cassettes/Organization_create_team.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA51Sy3KDIBT9F9ZGUWPssGn/oJusunGuioQpAgOYTJrJv/f6SGPTVbqT4z2X8+BClBFSE0aEDIehzu2ZRES2hKXlS5YWu4gMTuHvQwjWsyQBK+N5NG5MnxgnfLKmOm6Nr57gJBMDL+VHrsNz1JmC3J73NXfPkRfOJZk/rrjGDrWSTfWfbb+p66VwhADuMZIJ9EuUg+euMTpgAFOqQ7Kk/4qiNPT83k88FYRDFvR5BUuDcI1lEqYHpSLstYEgDVY7n3kPEoucD4vaOXpW/DgX0gdPGI1IZ5QyJ8x0dZIat+O/Q+jVg5/Vk1i/hsZxCLytIKDUjKbZhhabrNzTLcsKlu8+UPRg218z2w0tNxndpzlLcSwdZ8LZjhm8OwFafs2+EDUBVGWdxDB5tZhBfeak8c6/+A25u2yl/6wGDwK3p3Q7BqsU1MZBMIv1WiqFxqslPyJcDF0Xw9iUinupY2GOb2JMd+xufEUKMPXLrbjOcY6ot9DgLTktM4oaH9Vdr99KSPnAiwMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"035b23d4556a47c056f25f2f67342d25\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4985", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2CFE2EE:53CBE0B2", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 13:14:21 GMT", "date": "Sun, 20 Jul 2014 15:30:58 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405872559"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T15:30:58"}, {"request": {"body": {"string": "{\"repo_names\": [], \"name\": \"temp-team\", \"permission\": \"\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "57", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "POST", "uri": "https://api.github.com/orgs/github3py/teams"}, "response": {"body": {"string": "{\"name\":\"temp-team\",\"id\":923964,\"slug\":\"temp-team\",\"permission\":\"pull\",\"url\":\"https://api.github.com/teams/923964\",\"members_url\":\"https://api.github.com/teams/923964/members{/member}\",\"repositories_url\":\"https://api.github.com/teams/923964/repos\",\"members_count\":0,\"repos_count\":0,\"organization\":{\"login\":\"github3py\",\"id\":1782156,\"url\":\"https://api.github.com/orgs/github3py\",\"repos_url\":\"https://api.github.com/orgs/github3py/repos\",\"events_url\":\"https://api.github.com/orgs/github3py/events\",\"members_url\":\"https://api.github.com/orgs/github3py/members{/member}\",\"public_members_url\":\"https://api.github.com/orgs/github3py/public_members{/member}\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/1782156?\",\"name\":\"github3.py\",\"company\":\"github3.io\",\"blog\":null,\"location\":null,\"email\":null,\"public_repos\":5,\"public_gists\":0,\"followers\":0,\"following\":0,\"html_url\":\"https://github.com/github3py\",\"created_at\":\"2012-05-27T04:25:36Z\",\"updated_at\":\"2014-07-20T13:14:21Z\",\"type\":\"Organization\"}}", "encoding": "utf-8"}, "headers": {"content-length": "997", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a9277ef53e8a5f2118172ef38d88fb6b\"", "location": "https://api.github.com/teams/923964", "access-control-allow-credentials": "true", "status": "201 Created", "x-ratelimit-remaining": "4984", "x-github-media-type": "github.v3; param=full; 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": "48A0C4D3:1C3C:2CFE33C:53CBE0B2", "cache-control": "private, max-age=60, s-maxage=60", "date": "Sun, 20 Jul 2014 15:30:58 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405872559"}, "status": {"message": "Created", "code": 201}, "url": "https://api.github.com/orgs/github3py/teams"}, "recorded_at": "2014-07-20T15:30:58"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/teams/923964"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4983", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:1C3C:2CFE376:53CBE0B2", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 15:30:58 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405872559"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/923964"}, "recorded_at": "2014-07-20T15:30:58"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 2a504ec9c..de0303115 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -69,3 +69,15 @@ def test_conceal_member(self): assert o.conceal_member(public_member) is True # Re-publicize their membership assert o.publicize_member(public_member) is True + + def test_create_team(self): + """Test teh ability to create a new team.""" + self.basic_login() + cassette_name = self.cassette_name('create_team') + with self.recorder.use_cassette(cassette_name, **self.betamax_kwargs): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + t = o.create_team('temp-team') + assert isinstance(t, github3.orgs.Team) + assert t.delete() is True From 5f1423c4cbc557cb4c81052a7a2f50595ec63505 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 10:59:07 -0500 Subject: [PATCH 164/972] Fix typo --- tests/integration/test_orgs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index de0303115..80a6b8f9b 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -71,7 +71,7 @@ def test_conceal_member(self): assert o.publicize_member(public_member) is True def test_create_team(self): - """Test teh ability to create a new team.""" + """Test the ability to create a new team.""" self.basic_login() cassette_name = self.cassette_name('create_team') with self.recorder.use_cassette(cassette_name, **self.betamax_kwargs): From adabb47243309244824a74bb642137ef893bbc65 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 11:01:08 -0500 Subject: [PATCH 165/972] Add Organization#edit test --- tests/cassettes/Organization_edit.json | 1 + tests/integration/test_orgs.py | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/cassettes/Organization_edit.json diff --git a/tests/cassettes/Organization_edit.json b/tests/cassettes/Organization_edit.json new file mode 100644 index 000000000..d729d2faa --- /dev/null +++ b/tests/cassettes/Organization_edit.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA51Sy3KDIBT9F9ZGUWPssGn/oJusunGuioQpAgOYTJrJv/f6SGPTVbqT4z2X8+BClBFSE0aEDIehzu2ZRES2hKXlS5YWu4gMTuHvQwjWsyQBK+N5NG5MnxgnfLKmOm6Nr57gJBMDL+VHrsNz1JmC3J73NXfPkRfOJZk/rrjGDrWSTfWfbb+p66VwhADuMZIJ9EuUg+euMTpgAFOqQ7Kk/4qiNPT83k88FYRDFvR5BUuDcI1lEqYHpSLstYEgDVY7n3kPEoucD4vaOXpW/DgX0gdPGI1IZ5QyJ8x0dZIat+O/Q+jVg5/Vk1i/hsZxCLytIKDUjKbZhhabrNzTLcsKlu8+UPRg218z2w0tNxndpzlLcSwdZ8LZjhm8OwFafs2+EDUBVGWdxDB5tZhBfeak8c6/+A25u2yl/6wGDwK3p3Q7BqsU1MZBMIv1WiqFxqslPyJcDF0Xw9iUinupY2GOb2JMd+xufEUKMPXLrbjOcY6ot9DgLTktM4oaH9Vdr99KSPnAiwMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"035b23d4556a47c056f25f2f67342d25\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4966", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3D:38D496D:53CBE7A0", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 13:14:21 GMT", "date": "Sun, 20 Jul 2014 16:00:32 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405872559"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T16:00:32"}, {"request": {"body": {"string": "{\"location\": \"Madison, WI\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "27", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PATCH", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4965", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3D:38D49BD:53CBE7A0", "cache-control": "private, max-age=60, s-maxage=60", "date": "Sun, 20 Jul 2014 16:00:32 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405872559"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T16:00:32"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 80a6b8f9b..96af4e41e 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -81,3 +81,13 @@ def test_create_team(self): t = o.create_team('temp-team') assert isinstance(t, github3.orgs.Team) assert t.delete() is True + + def test_edit(self): + """Test the ability to edit an organization.""" + self.basic_login() + cassette_name = self.cassette_name('edit') + with self.recorder.use_cassette(cassette_name, **self.betamax_kwargs): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + assert o.edit(location='Madison, WI') is True From d6a887a4bd19ff2915bf938aac5eccd4ea270e64 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 11:03:28 -0500 Subject: [PATCH 166/972] Add integration test for Organization#is_member --- tests/cassettes/Organization_is_member.json | 1 + tests/integration/test_orgs.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Organization_is_member.json diff --git a/tests/cassettes/Organization_is_member.json b/tests/cassettes/Organization_is_member.json new file mode 100644 index 000000000..347a6530b --- /dev/null +++ b/tests/cassettes/Organization_is_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SO2/DIBSF/0rFbAeMY7tiydyh6hKpUpcI29RGwoB4pHKj/PdeP9Q62dINLudcLt/hgpTppEYMdTL0sc7tiBIkW8Sy6plmRZmg6BQc9yFYzzDmVu4W6a4xAzau83hrdcIaf3rAg2cHXCrOQofHrIsFvIMYauEeM6+eC14WV2hjY61kc/pPt1vrtik/88DdPZK56FeU0QvXGB0AwEw14pX+AYbSfBB/+ezmgEBkuR43ZWmgXEOYiOmoVAK5NjxIM0X7ylvpjU6e3l8mzgOXkOiiWsdeMmDFL4JO+uARIwn6NEqZL4C72UkN18BZHwZ197DN39h+i8YJHkR74gHmoSSjKSlSWh3JntGC5eUHDBZte6PZp6RKKTlmJSOE5XTShNFOMN5cx7X8Xh54/QGLVPk+xQIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"c9a7eeb8f362d26360a9fc5362b01586\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3A:1417650:53CBE820", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Sun, 20 Jul 2014 16:02:40 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405872193"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T16:02:40"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/members/sigmavirus24"}, "response": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"status": "302 Found", "x-ratelimit-remaining": "56", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:1C3A:1417665:53CBE820", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "content-length": "0", "server": "GitHub.com", "x-ratelimit-limit": "60", "location": "https://api.github.com/organizations/1782156/public_members/sigmavirus24", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 16:02:40 GMT", "x-frame-options": "deny", "content-type": "text/html;charset=utf-8", "access-control-allow-origin": "*", "x-ratelimit-reset": "1405872193"}, "status": {"message": "Found", "code": 302}, "url": "https://api.github.com/orgs/github3py/members/sigmavirus24"}, "recorded_at": "2014-07-20T16:02:40"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/public_members/sigmavirus24"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "55", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:1C3A:1417670:53CBE820", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "60", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 16:02:40 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405872193"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/organizations/1782156/public_members/sigmavirus24"}, "recorded_at": "2014-07-20T16:02:40"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 96af4e41e..6bb36e64a 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -91,3 +91,12 @@ def test_edit(self): assert isinstance(o, github3.orgs.Organization) assert o.edit(location='Madison, WI') is True + + def test_is_member(self): + """Test the ability to check if a User is a member of the org.""" + cassette_name = self.cassette_name('is_member') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + assert o.is_member('sigmavirus24') is True From 626dce656d50f44144ceaa6db8c5c3903f65336e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 11:11:23 -0500 Subject: [PATCH 167/972] Add integration test for Organization#is_public_member --- tests/cassettes/Organization_is_public_member.json | 1 + tests/integration/test_orgs.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Organization_is_public_member.json diff --git a/tests/cassettes/Organization_is_public_member.json b/tests/cassettes/Organization_is_public_member.json new file mode 100644 index 000000000..e1e0f25ab --- /dev/null +++ b/tests/cassettes/Organization_is_public_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SO2/DIBSF/0rFbAeMY7tiydyh6hKpUpcI29RGwoB4pHKj/PdeP9Q62dINLudcLt/hgpTppEYMdTL0sc7tiBIkW8Sy6plmRZmg6BQc9yFYzzDmVu4W6a4xAzau83hrdcIaf3rAg2cHXCrOQofHrIsFvIMYauEeM6+eC14WV2hjY61kc/pPt1vrtik/88DdPZK56FeU0QvXGB0AwEw14pX+AYbSfBB/+ezmgEBkuR43ZWmgXEOYiOmoVAK5NjxIM0X7ylvpjU6e3l8mzgOXkOiiWsdeMmDFL4JO+uARIwn6NEqZL4C72UkN18BZHwZ197DN39h+i8YJHkR74gHmoSSjKSlSWh3JntGC5eUHDBZte6PZp6RKKTlmJSOE5XTShNFOMN5cx7X8Xh54/QGLVPk+xQIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"c9a7eeb8f362d26360a9fc5362b01586\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:22D5:1776D7C:53CBEA08", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Sun, 20 Jul 2014 16:10:48 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T16:10:49"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/public_members/defunkt"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAAy2NQQ7CIBBFrzLBrS0Ld72HawN0hImFIczQGI13l1iX7+fl/bfJKOIimsVcBRusjAKFFfBJosAN6GAHtfuNAmTMfoh8B004hOgKvZwSF3M2K4eeseiPb71to5tUqyzWrrjjxhXbHElT93PgbPeLHQmxR1XsKSQMj+n4mv5romo+X6QEX7irAAAA", "encoding": "utf-8"}, "headers": {"status": "404 Not Found", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:22D5:1776DA3:53CBEA08", "access-control-allow-origin": "*", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "content-encoding": "gzip", "x-ratelimit-limit": "60", "access-control-allow-credentials": "true", "date": "Sun, 20 Jul 2014 16:10:49 GMT", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405876220"}, "status": {"message": "Not Found", "code": 404}, "url": "https://api.github.com/orgs/github3py/public_members/defunkt"}, "recorded_at": "2014-07-20T16:10:49"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 6bb36e64a..627fd0878 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -100,3 +100,12 @@ def test_is_member(self): assert isinstance(o, github3.orgs.Organization) assert o.is_member('sigmavirus24') is True + + def test_is_public_member(self): + """Test the ability to check if a User is a public member.""" + cassette_name = self.cassette_name('is_public_member') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + assert o.is_public_member('defunkt') is False From 8faace27bcc5661867bf65bb8cd0226e30072284 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 11:12:36 -0500 Subject: [PATCH 168/972] Add integration test for Organization#events --- tests/cassettes/Organization_events.json | 1 + tests/integration/test_orgs.py | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/cassettes/Organization_events.json diff --git a/tests/cassettes/Organization_events.json b/tests/cassettes/Organization_events.json new file mode 100644 index 000000000..b8b038790 --- /dev/null +++ b/tests/cassettes/Organization_events.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SO2/DIBSF/0rFbAeMY7tiydyh6hKpUpcI29RGwoB4pHKj/PdeP9Q62dINLudcLt/hgpTppEYMdTL0sc7tiBIkW8Sy6plmRZmg6BQc9yFYzzDmVu4W6a4xAzau83hrdcIaf3rAg2cHXCrOQofHrIsFvIMYauEeM6+eC14WV2hjY61kc/pPt1vrtik/88DdPZK56FeU0QvXGB0AwEw14pX+AYbSfBB/+ezmgEBkuR43ZWmgXEOYiOmoVAK5NjxIM0X7ylvpjU6e3l8mzgOXkOiiWsdeMmDFL4JO+uARIwn6NEqZL4C72UkN18BZHwZ197DN39h+i8YJHkR74gHmoSSjKSlSWh3JntGC5eUHDBZte6PZp6RKKTlmJSOE5XTShNFOMN5cx7X8Xh54/QGLVPk+xQIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"c9a7eeb8f362d26360a9fc5362b01586\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "55", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE0C7:53CBEA5F", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Sun, 20 Jul 2014 16:12:15 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/events?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a4e8370ade0c0fab78c72d3bd3c21d3e\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "54", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE0F6:53CBEA5F", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 06:14:21 GMT", "link": "; rel=\"next\"", "date": "Sun, 20 Jul 2014 16:12:15 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/events?per_page=100"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=2"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ae589be222575d8733d46383f5218b81\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "53", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE112:53CBEA5F", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 02 Feb 2014 16:51:07 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:15 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=2"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=3"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"82841916ead002f746046efb83d2154b\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "52", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE139:53CBEA5F", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 30 Dec 2013 21:32:30 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=3"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=4"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"1e1bc2b5cbb639824357fe5ad6ddd57a\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "51", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE161:53CBEA60", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 22 Dec 2013 18:14:56 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=4"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=5"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"1af1daa367fdcfa15c919028f6561ad3\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "50", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE183:53CBEA60", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 15 Nov 2013 22:19:26 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=5"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=6"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"2591ef75d2f9c8055bbd95066bcae737\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "49", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE1A7:53CBEA60", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 28 Oct 2013 03:06:54 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=6"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=7"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"9d27d0095ab400b13c4ed35a03a410c2\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "48", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE1DA:53CBEA60", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 21 Sep 2013 04:02:14 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=7"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=8"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"8cf5691256391c3c9c668ac26311b2fe\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "47", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE215:53CBEA60", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 14 Jun 2013 16:35:58 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=8"}, "recorded_at": "2014-07-20T16:12:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=9"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d1949f154e9e8a354bfb0878644bd041\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "46", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE23C:53CBEA60", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 16 Apr 2013 16:59:38 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=9"}, "recorded_at": "2014-07-20T16:12:17"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/organizations/1782156/events?per_page=100&page=10"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"147257e689c023fe4300300cd2127021\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "45", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1C3C:2DFE259:53CBEA60", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 26 Mar 2013 22:46:53 GMT", "link": "; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 20 Jul 2014 16:12:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405876220"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/organizations/1782156/events?per_page=100&page=10"}, "recorded_at": "2014-07-20T16:12:17"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 627fd0878..e2567a32f 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -109,3 +109,13 @@ def test_is_public_member(self): assert isinstance(o, github3.orgs.Organization) assert o.is_public_member('defunkt') is False + + def test_events(self): + """Test the ability to retrieve an organization's event stream.""" + cassette_name = self.cassette_name('events') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + for event in o.events(): + assert isinstance(event, github3.events.Event) From 9bbd28b7733ad99f20608a597a58e5f5ebc94f37 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 21:21:27 -0500 Subject: [PATCH 169/972] Add integration test for Organization#members --- tests/cassettes/Organization_members.json | 1 + tests/integration/test_orgs.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/cassettes/Organization_members.json diff --git a/tests/cassettes/Organization_members.json b/tests/cassettes/Organization_members.json new file mode 100644 index 000000000..4cb539ed6 --- /dev/null +++ b/tests/cassettes/Organization_members.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4948", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:55C1:7111A9:53CC790A", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Mon, 21 Jul 2014 02:20:58 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405911623"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-21T02:20:59"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/members?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62TXW+CMBSG/wvXxspHFbzZr9jVsphSDtgMKWkLxhH/+07FbJYtxjKvIKTPe14OPG9DUMtKNME2AM24gQ/N8mARiCLYrtOMZuEiYD0zTO06VeOpvTGt3hIyPtTLSph9l3caFJeNgcYsuTyQjozwC0ZV6hpgM4MVUAijgvKkTDOAJKbRpkxXrKAJBZrHCEwGteI6ZEzGSZo4XffmUE/aja0ugHO0lHUtj5gwfZv7Q8g3h/XGe9FUszKQG4g0e8CF4quc7YKENr6FLsxA7GUnCpui8RspKDxLXSmsdGywzUAUtPIS1+WaK9EaIRvfcg6LWVJVrBGfbE4WshojbC3fGhcGWejxt/SFR2ggrRI94ye7EgUcRI8rnhU4oTHPnFpAI17xN7ALFwZ2rDhYF0tWazgvftzUojqwXqhORwmetSZFySqNVzPtHOHfdvIwSWO6LtKszCIK6ywKN2kOEBZZzHi5wdkP2Dlpe9/PyWEvQ2/Z+Y7+kfIfS524f3nqJD3PVDf21nP8vN6uOmm+tjqwv68O/hxjJ40c4x9w9v0LOH8telEHAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"b9889daf1e146f0dc5ac6d7f9852a69a\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4947", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:55C1:7111DD:53CC790A", "cache-control": "private, max-age=60, s-maxage=60", "date": "Mon, 21 Jul 2014 02:20:58 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405911623"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/members?per_page=100"}, "recorded_at": "2014-07-21T02:20:59"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index e2567a32f..89bdaa01a 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -119,3 +119,14 @@ def test_events(self): for event in o.events(): assert isinstance(event, github3.events.Event) + + def test_members(self): + """Test the ability to retrieve an organization's members.""" + self.basic_login() + cassette_name = self.cassette_name('members') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + for member in o.members(): + assert isinstance(member, github3.users.User) From 5110990b3402383ed0a434d5768685dd66af8a3a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 21:22:19 -0500 Subject: [PATCH 170/972] Add integration test for Organization#public_members --- tests/cassettes/Organization_public members.json | 1 + tests/integration/test_orgs.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/cassettes/Organization_public members.json diff --git a/tests/cassettes/Organization_public members.json b/tests/cassettes/Organization_public members.json new file mode 100644 index 000000000..6c822985d --- /dev/null +++ b/tests/cassettes/Organization_public members.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4946", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4562:378C37:53CC7942", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Mon, 21 Jul 2014 02:21:54 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405911623"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-21T02:21:55"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/public_members?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52Ty26DMBBF/8XrKA6PJMAmX9FVVSFjBhgJbGQbohTl3zsGVKlsKliBkM+Z64v9ObFW16hYxizWnRjRDDaM2YlhybIwviTR5cTEKJww+WBaWtc419uM8+WjPdfomqEYLBiplQPlzlJ3fOAL/CBVbVaBdzIZxEl0vZVJWqXhFW5pGNyTAiAo00jI6k7AZlCP65DFTJMs36RtXNdu8i25ZmSzuNJtq59k2e7ov0H8l6SQyzuq+qCFyIlr1wAVS1t6+6LQuv2hZmri/pFj6T2W/paBcnewlaNYT0WJJm6g17NwKKw02DvUan/APzTZtKmFwm9xzEa0JYmPtj/KTBENIx3U/fiCTbw3OAr58tUYkIAjlX1QueHJ6F490D35oEPhq0cHuSg7f0cr0Vp4f/0A/p8Y7LUDAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"6e61732b48fdd33d664a49419e6ae91c\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4945", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4562:378C51:53CC7942", "cache-control": "private, max-age=60, s-maxage=60", "date": "Mon, 21 Jul 2014 02:21:54 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405911623"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/public_members?per_page=100"}, "recorded_at": "2014-07-21T02:21:55"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 89bdaa01a..752679544 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -130,3 +130,14 @@ def test_members(self): for member in o.members(): assert isinstance(member, github3.users.User) + + def test_public_members(self): + """Test the ability to retrieve an organization's public members.""" + self.basic_login() + cassette_name = self.cassette_name('public members') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + for member in o.public_members(): + assert isinstance(member, github3.users.User) From edd5382f3007f933b309303638cfb10dfce8852e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 21:23:48 -0500 Subject: [PATCH 171/972] Rename cassette --- ...ion_public members.json => Organization_public_members.json} | 0 tests/integration/test_orgs.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/cassettes/{Organization_public members.json => Organization_public_members.json} (100%) diff --git a/tests/cassettes/Organization_public members.json b/tests/cassettes/Organization_public_members.json similarity index 100% rename from tests/cassettes/Organization_public members.json rename to tests/cassettes/Organization_public_members.json diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 752679544..862e7cd03 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -134,7 +134,7 @@ def test_members(self): def test_public_members(self): """Test the ability to retrieve an organization's public members.""" self.basic_login() - cassette_name = self.cassette_name('public members') + cassette_name = self.cassette_name('public_members') with self.recorder.use_cassette(cassette_name): o = self.gh.organization('github3py') assert isinstance(o, github3.orgs.Organization) From 1c6dda3733fc8c8a757acbd1ab55fa8def28e109 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 21:26:33 -0500 Subject: [PATCH 172/972] Add integration test for Organization#repositories --- tests/integration/test_orgs.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 862e7cd03..1d211e8c5 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -141,3 +141,13 @@ def test_public_members(self): for member in o.public_members(): assert isinstance(member, github3.users.User) + + def test_repositories(self): + """Test the ability to retrieve an organization's repositories.""" + cassette_name = self.cassette_name('repositories') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + for repo in o.repositories(): + assert isinstance(repo, github3.repos.Repository) From 780bae83a368a44133c9891c721fabf35c163209 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 20 Jul 2014 21:34:33 -0500 Subject: [PATCH 173/972] Add forgotten cassette --- tests/cassettes/Organization_repositories.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/cassettes/Organization_repositories.json diff --git a/tests/cassettes/Organization_repositories.json b/tests/cassettes/Organization_repositories.json new file mode 100644 index 000000000..907d05ad9 --- /dev/null +++ b/tests/cassettes/Organization_repositories.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SO2/DIBSF/0rFbAeMY7tiydyh6hKpUpcI29RGwoB4pHKj/PdeP9Q62dINLudcLt/hgpTppEYMdTL0sc7tiBIkW8Sy6plmRZmg6BQc9yFYzzDmVu4W6a4xAzau83hrdcIaf3rAg2cHXCrOQofHrIsFvIMYauEeM6+eC14WV2hjY61kc/pPt1vrtik/88DdPZK56FeU0QvXGB0AwEw14pX+AYbSfBB/+ezmgEBkuR43ZWmgXEOYiOmoVAK5NjxIM0X7ylvpjU6e3l8mzgOXkOiiWsdeMmDFL4JO+uARIwn6NEqZL4C72UkN18BZHwZ197DN39h+i8YJHkR74gHmoSSjKSlSWh3JntGC5eUHDBZte6PZp6RKKTlmJSOE5XTShNFOMN5cx7X8Xh54/QGLVPk+xQIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"c9a7eeb8f362d26360a9fc5362b01586\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "50", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:55C4:34A72F:53CC79FB", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Mon, 21 Jul 2014 02:24:59 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405911846"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-21T02:25:00"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/repos?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ce7600c610ba38ae8d42d93d0e64a188\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "49", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:55C4:34A739:53CC79FB", "cache-control": "public, max-age=60, s-maxage=60", "date": "Mon, 21 Jul 2014 02:24:59 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405911846"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/repos?per_page=100"}, "recorded_at": "2014-07-21T02:25:00"}], "recorded_with": "betamax/{version}"} \ No newline at end of file From 6530f456a05ea3f965b31f2c1f838bc6f4719781 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 21 Jul 2014 08:20:57 -0500 Subject: [PATCH 174/972] Add integration test for Organization#teams --- tests/cassettes/Organization_teams.json | 1 + tests/integration/test_orgs.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/cassettes/Organization_teams.json diff --git a/tests/cassettes/Organization_teams.json b/tests/cassettes/Organization_teams.json new file mode 100644 index 000000000..2b90754f9 --- /dev/null +++ b/tests/cassettes/Organization_teams.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4952", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4562:975F23:53CD11A3", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Mon, 21 Jul 2014 13:12:04 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405949535"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-21T13:12:04"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63SzYrCMBQF4FeRrKuJimC61bU+gAxDai82kOSG/OBCfPcJbSxjZxatdNc295zwJb08iBEaSEnOdwPOk4LImpTrPedsXRCv4i2t4WvNgtPSe4kmfRW1liYFolPprQnB+pJSYeXqJkMTq9UVNQ0gtKddX5rVoKu0zffoDM2JR354phIHFr0M6CRMaWpj5Fn05AMqJSp0IlX1cs7YftvLr4ORtwOwUamR/rZ1or/NzOLvmv7xm+BkFQd8xn/x3yYGet+M1zM+Xc/4XPrU9Ed/xMUJw+IICgLk/55vtju+6/k1Lg2GZf0a+fD2u9Zp/i4zhz83Zf/XDzsPJ7byAwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f2ac1c071e4bd300c5bf11848d67d16\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4951", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4562:975F4D:53CD11A4", "cache-control": "private, max-age=60, s-maxage=60", "date": "Mon, 21 Jul 2014 13:12:04 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405949535"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "recorded_at": "2014-07-21T13:12:04"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 1d211e8c5..90d1a4d97 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -151,3 +151,14 @@ def test_repositories(self): for repo in o.repositories(): assert isinstance(repo, github3.repos.Repository) + + def test_teams(self): + """Test the ability to retrieve an organization's teams.""" + self.basic_login() + cassette_name = self.cassette_name('teams') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + for team in o.teams(): + assert isinstance(team, github3.orgs.Team) From 395ebdbcdc3077aa570e4f5f280c56d6f2d8b488 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 21 Jul 2014 08:51:39 -0500 Subject: [PATCH 175/972] Add test for Organization#publicize_member --- .../Organization_publicize_member.json | 1 + tests/integration/test_orgs.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/cassettes/Organization_publicize_member.json diff --git a/tests/cassettes/Organization_publicize_member.json b/tests/cassettes/Organization_publicize_member.json new file mode 100644 index 000000000..81570b336 --- /dev/null +++ b/tests/cassettes/Organization_publicize_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4999", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:72A5:7109B7:53CD1737", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Mon, 21 Jul 2014 13:35:52 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405953352"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-21T13:35:52"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/orgs/github3py/public_members/esacteksab"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAAxXMPQrDMAwG0KsYzSUesuUSPUKwnY9Y4D8kOdCW3r3p+ob3oQrVcII2erbycpbhpkJcCs2NGQsnfuPPLK6iRohmHvSgo6dZ0SwY97ZPKXeRzYZu3h+4UPqALCdbnnFJvfprpe8PpiDhVHAAAAA=", "encoding": "utf-8"}, "headers": {"status": "403 Forbidden", "x-ratelimit-remaining": "4998", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:72A5:7109DA:53CD1738", "access-control-allow-origin": "*", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "content-encoding": "gzip", "x-ratelimit-limit": "5000", "access-control-allow-credentials": "true", "date": "Mon, 21 Jul 2014 13:35:52 GMT", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405953352"}, "status": {"message": "Forbidden", "code": 403}, "url": "https://api.github.com/orgs/github3py/public_members/esacteksab"}, "recorded_at": "2014-07-21T13:35:52"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/orgs/github3py/public_members/sigmavirus24"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4997", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:72A5:7109EA:53CD1738", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "access-control-allow-credentials": "true", "date": "Mon, 21 Jul 2014 13:35:52 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405953352"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/orgs/github3py/public_members/sigmavirus24"}, "recorded_at": "2014-07-21T13:35:52"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 90d1a4d97..2ac1010c9 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- """Integration tests for methods implemented on Organization.""" +import pytest + import github3 from .helper import IntegrationHelper @@ -162,3 +164,18 @@ def test_teams(self): for team in o.teams(): assert isinstance(team, github3.orgs.Team) + + def test_publicize_member(self): + """Test the ability to publicize a member of the organization.""" + self.basic_login() + cassette_name = self.cassette_name('publicize_member') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + # Show that we cannot publicize someone other than the current + # user + with pytest.raises(github3.GitHubError): + o.publicize_member('esacteksab') + + assert o.publicize_member('sigmavirus24') is True From e0ea6ee60407aa16c4a55542125b74423ae888c4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 21 Jul 2014 21:31:45 -0500 Subject: [PATCH 176/972] Add Organization#remove_member integration test --- .../cassettes/Organization_remove_member.json | 1 + tests/integration/test_orgs.py | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/cassettes/Organization_remove_member.json diff --git a/tests/cassettes/Organization_remove_member.json b/tests/cassettes/Organization_remove_member.json new file mode 100644 index 000000000..76f613f92 --- /dev/null +++ b/tests/cassettes/Organization_remove_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4986", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4565:2B49B89:53CDCAB8", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Tue, 22 Jul 2014 02:21:45 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405998527"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-22T02:21:45"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63SzYrCMBQF4FeRrKuJimC61bU+gAxDai82kOSG/OBCfPcJbSxjZxatdNc295zwJb08iBEaSEnOdwPOk4LImpTrPedsXRCv4i2t4WvNgtPSe4kmfRW1liYFolPprQnB+pJSYeXqJkMTq9UVNQ0gtKddX5rVoKu0zffoDM2JR354phIHFr0M6CRMaWpj5Fn05AMqJSp0IlX1cs7YftvLr4ORtwOwUamR/rZ1or/NzOLvmv7xm+BkFQd8xn/x3yYGet+M1zM+Xc/4XPrU9Ed/xMUJw+IICgLk/55vtju+6/k1Lg2GZf0a+fD2u9Zp/i4zhz83Zf/XDzsPJ7byAwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f2ac1c071e4bd300c5bf11848d67d16\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4985", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4565:2B49BD1:53CDCAB9", "cache-control": "private, max-age=60, s-maxage=60", "date": "Tue, 22 Jul 2014 02:21:45 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405998527"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "recorded_at": "2014-07-22T02:21:45"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/teams/923595/members/gh3test"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4984", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:4565:2B49C01:53CDCAB9", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "132026e9262a0093e437f99db5f1e499", "access-control-allow-credentials": "true", "date": "Tue, 22 Jul 2014 02:21:45 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405998527"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/923595/members/gh3test"}, "recorded_at": "2014-07-22T02:21:45"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/orgs/github3py/members/gh3test"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4983", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:4565:2B49C51:53CDCAB9", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "3061975e1f37121b3751604ad153c687", "access-control-allow-credentials": "true", "date": "Tue, 22 Jul 2014 02:21:45 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405998527"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/orgs/github3py/members/gh3test"}, "recorded_at": "2014-07-22T02:21:45"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 2ac1010c9..d82338864 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -179,3 +179,23 @@ def test_publicize_member(self): o.publicize_member('esacteksab') assert o.publicize_member('sigmavirus24') is True + + def test_remove_member(self): + """Test the ability to remove a member of the organization.""" + self.basic_login() + cassette_name = self.cassette_name('remove_member') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + # First find the team we want to use + for team in o.teams(): + if team.name == 'Do Not Delete': + break + else: + assert False, 'Could not find team' + + # First add the user + assert o.add_member('gh3test', team.id) is True + # Now remove them + assert o.remove_member('gh3test') is True From 8b6c1eee72b8546a4c55a1b5aa4416189bccb390 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 21 Jul 2014 21:47:43 -0500 Subject: [PATCH 177/972] Add Organization#remove_repository integration test --- .../Organization_remove_repository.json | 1 + tests/integration/test_orgs.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/cassettes/Organization_remove_repository.json diff --git a/tests/cassettes/Organization_remove_repository.json b/tests/cassettes/Organization_remove_repository.json new file mode 100644 index 000000000..6611595b8 --- /dev/null +++ b/tests/cassettes/Organization_remove_repository.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4977", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4564:2424F76:53CDD0B5", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Tue, 22 Jul 2014 02:47:17 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405998527"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-22T02:47:17"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63SzYrCMBQF4FeRrKuJimC61bU+gAxDai82kOSG/OBCfPcJbSxjZxatdNc295zwJb08iBEaSEnOdwPOk4LImpTrPedsXRCv4i2t4WvNgtPSe4kmfRW1liYFolPprQnB+pJSYeXqJkMTq9UVNQ0gtKddX5rVoKu0zffoDM2JR354phIHFr0M6CRMaWpj5Fn05AMqJSp0IlX1cs7YftvLr4ORtwOwUamR/rZ1or/NzOLvmv7xm+BkFQd8xn/x3yYGet+M1zM+Xc/4XPrU9Ed/xMUJw+IICgLk/55vtju+6/k1Lg2GZf0a+fD2u9Zp/i4zhz83Zf/XDzsPJ7byAwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f2ac1c071e4bd300c5bf11848d67d16\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4976", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4564:2424FB3:53CDD0B5", "cache-control": "private, max-age=60, s-maxage=60", "date": "Tue, 22 Jul 2014 02:47:17 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405998527"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "recorded_at": "2014-07-22T02:47:18"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/teams/923595/repos/github3py/urllib3"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4975", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:4564:2424FDC:53CDD0B5", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "c436b2b44345c72ff906059f604991e7", "access-control-allow-credentials": "true", "date": "Tue, 22 Jul 2014 02:47:18 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1405998527"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/923595/repos/github3py/urllib3"}, "recorded_at": "2014-07-22T02:47:18"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index d82338864..a0d5a7596 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -199,3 +199,20 @@ def test_remove_member(self): assert o.add_member('gh3test', team.id) is True # Now remove them assert o.remove_member('gh3test') is True + + def test_remove_repository(self): + """Test the ability to remove a repository from a team.""" + self.basic_login() + cassette_name = self.cassette_name('remove_repository') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + # First find the team we want to use + for team in o.teams(): + if team.name == 'Do Not Delete': + break + else: + assert False, 'Could not find team' + + assert o.remove_repository('github3py/urllib3', team.id) is True From 6dd22cce179fefe944bf1ba3aae02fa20d1d21d9 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 21 Jul 2014 21:50:22 -0500 Subject: [PATCH 178/972] Add integration test for Organization#team --- tests/cassettes/Organization_team.json | 1 + tests/integration/test_orgs.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/cassettes/Organization_team.json diff --git a/tests/cassettes/Organization_team.json b/tests/cassettes/Organization_team.json new file mode 100644 index 000000000..7f4fb963c --- /dev/null +++ b/tests/cassettes/Organization_team.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4972", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:72A9:344B8D2:53CDD142", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Tue, 22 Jul 2014 02:49:38 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405998527"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-22T02:49:38"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63SzYrCMBQF4FeRrKuJimC61bU+gAxDai82kOSG/OBCfPcJbSxjZxatdNc295zwJb08iBEaSEnOdwPOk4LImpTrPedsXRCv4i2t4WvNgtPSe4kmfRW1liYFolPprQnB+pJSYeXqJkMTq9UVNQ0gtKddX5rVoKu0zffoDM2JR354phIHFr0M6CRMaWpj5Fn05AMqJSp0IlX1cs7YftvLr4ORtwOwUamR/rZ1or/NzOLvmv7xm+BkFQd8xn/x3yYGet+M1zM+Xc/4XPrU9Ed/xMUJw+IICgLk/55vtju+6/k1Lg2GZf0a+fD2u9Zp/i4zhz83Zf/XDzsPJ7byAwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f2ac1c071e4bd300c5bf11848d67d16\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4971", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:72A9:344B91E:53CDD142", "cache-control": "private, max-age=60, s-maxage=60", "date": "Tue, 22 Jul 2014 02:49:38 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405998527"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py/teams?per_page=100"}, "recorded_at": "2014-07-22T02:49:38"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTyW7CMBT8lcrnLE4gUHzpuYeqF6RKvURO4gZL3uQFRBH/3kdiREBVCzf7+c1bZsYHpKhkiKD3nWLWoQTxDpHiebXCRYKcCD286fObYVZy57hWEKWd5AoAwQq4bbw3juQ5NTzrud+EJmu1zD2j0uVjPciVTDbQpr4bk0fEIR6OUMQyox332nL2SKUBNpmh1UF52DUWrOO9SpC2PVX8m/ph0QMSuodNCRr3mpn9mablc1lUi38ogGoun0KHQf6m4BqTn0dnW6b8Y9ARci/1N31/Id+ERvC2vkvIm2rX0KmidEs9tbeUDEEX3RQcs61WHggYjBXyYmT/BXaLHo4kZ4NAkGSo2l9ky7iGcANiIqKCEAno2kaN0RvtuNMqefp4hSQmKQdTj1lx7FEDAvaIgZ477xDBCfrSQujd6ftcblxBG3jbeCluFpt8j6ktWsuoZ11NwZSoxEWZ4iotl2s8J2VFZotPGCyY7ipnnuJlWuJ1sSAYk1l5yvF7M3zoqYmPxx8B305P6QMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a7a21842a7b4f3bff9b46d086d6364aa\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4970", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:72A9:344B94F:53CDD142", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 20 Oct 2007 11:24:19 GMT", "date": "Tue, 22 Jul 2014 02:49:38 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1405998527"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901"}, "recorded_at": "2014-07-22T02:49:38"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index a0d5a7596..76b6acb86 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -216,3 +216,17 @@ def test_remove_repository(self): assert False, 'Could not find team' assert o.remove_repository('github3py/urllib3', team.id) is True + + def test_team(self): + """Test the ability retrieve an individual team by id.""" + self.basic_login() + cassette_name = self.cassette_name('team') + with self.recorder.use_cassette(cassette_name): + o = self.gh.organization('github3py') + assert isinstance(o, github3.orgs.Organization) + + # Grab a team, any team + first_team = next(o.teams()) + + fetched_team = o.team(first_team.id) + assert first_team == fetched_team From 0a8d1994301f8a94ccaf0a5cf9169520654d01a0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 08:11:15 -0500 Subject: [PATCH 179/972] Refactor Organization integration tests --- tests/integration/test_orgs.py | 99 +++++++++++++--------------------- 1 file changed, 37 insertions(+), 62 deletions(-) diff --git a/tests/integration/test_orgs.py b/tests/integration/test_orgs.py index 76b6acb86..0176e8b1b 100644 --- a/tests/integration/test_orgs.py +++ b/tests/integration/test_orgs.py @@ -13,18 +13,29 @@ class TestOrganization(IntegrationHelper): betamax_kwargs = {'match_requests_on': ['method', 'uri', 'json-body']} + def get_organization(self, name='github3py'): + """Get the organization for each test.""" + o = self.gh.organization(name) + assert isinstance(o, github3.orgs.Organization) + return o + + def get_team(self, organization, team_name='Do Not Delete'): + """Get the desired team.""" + for team in organization.teams(): + if team.name == team_name: + break + else: + assert False, 'Could not find team "{0}"'.format(team_name) + + return team + def test_add_member(self): """Test the ability to add a member to an organization.""" self.basic_login() cassette_name = self.cassette_name('add_member') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) - for team in o.teams(): - if team.name == 'Do Not Delete': - break - else: - assert False, 'Could not find team' + o = self.get_organization() + team = self.get_team(o) assert o.add_member('esacteksab', team.id) is True def test_add_repository(self): @@ -32,15 +43,8 @@ def test_add_repository(self): self.basic_login() cassette_name = self.cassette_name('add_repository') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) - - for team in o.teams(): - if team.name == 'Do Not Delete': - break - else: - assert False, 'Could not find team' - + o = self.get_organization() + team = self.get_team(o) assert o.add_repository('github3py/urllib3', team.id) is True def test_create_repository(self): @@ -48,9 +52,7 @@ def test_create_repository(self): self.basic_login() cassette_name = self.cassette_name('create_repository') with self.recorder.use_cassette(cassette_name, **self.betamax_kwargs): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) - + o = self.get_organization() r = o.create_repository('test-repository', description='hi') assert isinstance(r, github3.repos.Repository) assert r.delete() is True @@ -60,8 +62,7 @@ def test_conceal_member(self): self.basic_login() cassette_name = self.cassette_name('conceal_member') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() # Get a public member of the organization public_member = next(o.public_members()) @@ -77,8 +78,7 @@ def test_create_team(self): self.basic_login() cassette_name = self.cassette_name('create_team') with self.recorder.use_cassette(cassette_name, **self.betamax_kwargs): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() t = o.create_team('temp-team') assert isinstance(t, github3.orgs.Team) @@ -89,8 +89,7 @@ def test_edit(self): self.basic_login() cassette_name = self.cassette_name('edit') with self.recorder.use_cassette(cassette_name, **self.betamax_kwargs): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() assert o.edit(location='Madison, WI') is True @@ -98,8 +97,7 @@ def test_is_member(self): """Test the ability to check if a User is a member of the org.""" cassette_name = self.cassette_name('is_member') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() assert o.is_member('sigmavirus24') is True @@ -107,8 +105,7 @@ def test_is_public_member(self): """Test the ability to check if a User is a public member.""" cassette_name = self.cassette_name('is_public_member') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() assert o.is_public_member('defunkt') is False @@ -116,8 +113,7 @@ def test_events(self): """Test the ability to retrieve an organization's event stream.""" cassette_name = self.cassette_name('events') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() for event in o.events(): assert isinstance(event, github3.events.Event) @@ -127,8 +123,7 @@ def test_members(self): self.basic_login() cassette_name = self.cassette_name('members') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() for member in o.members(): assert isinstance(member, github3.users.User) @@ -138,8 +133,7 @@ def test_public_members(self): self.basic_login() cassette_name = self.cassette_name('public_members') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() for member in o.public_members(): assert isinstance(member, github3.users.User) @@ -148,8 +142,7 @@ def test_repositories(self): """Test the ability to retrieve an organization's repositories.""" cassette_name = self.cassette_name('repositories') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() for repo in o.repositories(): assert isinstance(repo, github3.repos.Repository) @@ -159,8 +152,7 @@ def test_teams(self): self.basic_login() cassette_name = self.cassette_name('teams') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() for team in o.teams(): assert isinstance(team, github3.orgs.Team) @@ -170,8 +162,7 @@ def test_publicize_member(self): self.basic_login() cassette_name = self.cassette_name('publicize_member') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() # Show that we cannot publicize someone other than the current # user @@ -185,15 +176,8 @@ def test_remove_member(self): self.basic_login() cassette_name = self.cassette_name('remove_member') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) - - # First find the team we want to use - for team in o.teams(): - if team.name == 'Do Not Delete': - break - else: - assert False, 'Could not find team' + o = self.get_organization() + team = self.get_team(o) # First add the user assert o.add_member('gh3test', team.id) is True @@ -205,16 +189,8 @@ def test_remove_repository(self): self.basic_login() cassette_name = self.cassette_name('remove_repository') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) - - # First find the team we want to use - for team in o.teams(): - if team.name == 'Do Not Delete': - break - else: - assert False, 'Could not find team' - + o = self.get_organization() + team = self.get_team(o) assert o.remove_repository('github3py/urllib3', team.id) is True def test_team(self): @@ -222,8 +198,7 @@ def test_team(self): self.basic_login() cassette_name = self.cassette_name('team') with self.recorder.use_cassette(cassette_name): - o = self.gh.organization('github3py') - assert isinstance(o, github3.orgs.Organization) + o = self.get_organization() # Grab a team, any team first_team = next(o.teams()) From caa1979b9bec9db23dcc174b7f043a661da772c1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 08:55:37 -0500 Subject: [PATCH 180/972] Start integration testing Teams Add test for Organization#add_member --- tests/cassettes/Team_add_member.json | 1 + tests/integration/test_orgs_team.py | 30 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/cassettes/Team_add_member.json create mode 100644 tests/integration/test_orgs_team.py diff --git a/tests/cassettes/Team_add_member.json b/tests/cassettes/Team_add_member.json new file mode 100644 index 000000000..e9b5a96ab --- /dev/null +++ b/tests/cassettes/Team_add_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4901", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6435:46769A0:53CE6D39", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Tue, 22 Jul 2014 13:55:06 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406037620"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-22T13:55:06"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTyW7CMBT8lcrnLE4gUHzpuYeqF6RKvURO4gZL3uQFRBH/3kdiREBVCzf7+c1bZsYHpKhkiKD3nWLWoQTxDpHiebXCRYKcCD286fObYVZy57hWEKWd5AoAwQq4bbw3juQ5NTzrud+EJmu1zD2j0uVjPciVTDbQpr4bk0fEIR6OUMQyox332nL2SKUBNpmh1UF52DUWrOO9SpC2PVX8m/ph0QMSuodNCRr3mpn9mablc1lUi38ogGoun0KHQf6m4BqTn0dnW6b8Y9ARci/1N31/Id+ERvC2vkvIm2rX0KmidEs9tbeUDEEX3RQcs61WHggYjBXyYmT/BXaLHo4kZ4NAkGSo2l9ky7iGcANiIqKCEAno2kaN0RvtuNMqefp4hSQmKQdTj1lx7FEDAvaIgZ477xDBCfrSQujd6ftcblxBG3jbeCluFpt8j6ktWsuoZ11NwZSoxEWZ4iotl2s8J2VFZotPGCyY7ipnnuJlWuJ1sSAYk1l5yvF7M3zoqYmPxx8B305P6QMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a7a21842a7b4f3bff9b46d086d6364aa\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4900", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6435:46769EA:53CE6D3A", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 20 Oct 2007 11:24:19 GMT", "date": "Tue, 22 Jul 2014 13:55:06 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406037620"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901"}, "recorded_at": "2014-07-22T13:55:06"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/teams/189901/members/esacteksab"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4899", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:6435:4676A2B:53CE6D3A", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "access-control-allow-credentials": "true", "date": "Tue, 22 Jul 2014 13:55:06 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406037620"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/189901/members/esacteksab"}, "recorded_at": "2014-07-22T13:55:06"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py new file mode 100644 index 000000000..1ed91f349 --- /dev/null +++ b/tests/integration/test_orgs_team.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +"""Integration tests for methods implemented on Team.""" +import pytest + +import github3 + +from .helper import IntegrationHelper + + +class TestTeam(IntegrationHelper): + + """Team integration tests.""" + + betamax_kwargs = {'match_requests_on': ['method', 'uri', 'json-body']} + + def get_team(self, organization='github3py', id=189901): + """Get our desired team.""" + o = self.gh.organization(organization) + assert isinstance(o, github3.orgs.Organization) + t = o.team(id) + assert isinstance(t, github3.orgs.Team) + return t + + def test_add_member(self): + """Show a user can add a member to a team.""" + self.basic_login() + cassette_name = self.cassette_name('add_member') + with self.recorder.use_cassette(cassette_name): + team = self.get_team() + assert team.add_member('esacteksab') is True From 7ffa41a6c7acface33ea2de344be8bda05873457 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 08:58:03 -0500 Subject: [PATCH 181/972] Add integration test for Team#remove_member --- tests/cassettes/Team_remove_member.json | 1 + tests/integration/test_orgs_team.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/Team_remove_member.json diff --git a/tests/cassettes/Team_remove_member.json b/tests/cassettes/Team_remove_member.json new file mode 100644 index 000000000..fddad776e --- /dev/null +++ b/tests/cassettes/Team_remove_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4897", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:55BE:914C97:53CE6DAD", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Tue, 22 Jul 2014 13:57:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406037620"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-22T13:57:02"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTyW7CMBT8lcrnLE4gUHzpuYeqF6RKvURO4gZL3uQFRBH/3kdiREBVCzf7+c1bZsYHpKhkiKD3nWLWoQTxDpHiebXCRYKcCD286fObYVZy57hWEKWd5AoAwQq4bbw3juQ5NTzrud+EJmu1zD2j0uVjPciVTDbQpr4bk0fEIR6OUMQyox332nL2SKUBNpmh1UF5RMpYsI73KkHa9lTxb+qHRQ9I6B42JWjca2b2Z5qWz2VRLf6hAKq5fAodBvmbgmtMfh6dbZnyj0FHyL3U3/T9hXwTGsHb+i4hb6pdQ6eK0i311N5SMgRddFNwzLZaeSBgMFbIi5H9F9gtejiSnA0CQZKhan+RLeMawg2IiYgKQiSgaxs1Rm+0406r5OnjFZKYpBxMPWbFsUcNCNgjBnruvEMEJ+hLC6F3p+9zuXEFbeBt46W4WWzyPaa2aC2jnnU1BVOiEhdliqu0XK7xnJQVmS0+YbBguquceYqXaYnXxYJgTGblKcfvzfChpyY+Hn8AaRrFQ+kDAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"fa1c2a657ab0d3cb10e5ae5b26d77bf8\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4896", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:55BE:914CBA:53CE6DAE", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 20 Oct 2007 11:24:19 GMT", "date": "Tue, 22 Jul 2014 13:57:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406037620"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901"}, "recorded_at": "2014-07-22T13:57:02"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/teams/189901/members/esacteksab"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4895", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:55BE:914CD9:53CE6DAE", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "access-control-allow-credentials": "true", "date": "Tue, 22 Jul 2014 13:57:02 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406037620"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/189901/members/esacteksab"}, "recorded_at": "2014-07-22T13:57:02"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index 1ed91f349..335e9809b 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -28,3 +28,11 @@ def test_add_member(self): with self.recorder.use_cassette(cassette_name): team = self.get_team() assert team.add_member('esacteksab') is True + + def test_remove_member(self): + """Show a user can remove a member from a team.""" + self.basic_login() + cassette_name = self.cassette_name('remove_member') + with self.recorder.use_cassette(cassette_name): + team = self.get_team() + assert team.remove_member('esacteksab') is True From c07a17b9aae4fd4db56b725c1f1c2ac3fbee0a5c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 18:33:42 -0500 Subject: [PATCH 182/972] Add Organization#add_repository integration test --- tests/cassettes/Team_add_repository.json | 1 + tests/integration/test_orgs_team.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/Team_add_repository.json diff --git a/tests/cassettes/Team_add_repository.json b/tests/cassettes/Team_add_repository.json new file mode 100644 index 000000000..b1f3d836b --- /dev/null +++ b/tests/cassettes/Team_add_repository.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4976", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:11E5:8BD47:53CEF47C", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Tue, 22 Jul 2014 23:32:12 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406073636"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-22T23:32:12"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTyW7CMBT8lcrnLE4gUHzpuYeqF6RKvURO4gZL3uQFRBH/3kdiREBVCzf7+c1bZsYHpKhkiKD3nWLWoQTxDpHiebXCRYKcCD286fObYVZy57hWEKWd5AoAwQq4bbw3juQ5NTzrud+EJmu1zD2j0uVjPciVTDbQpr4bk0fEIR6OUMQyox332nL2SKUBNpmh1UF52DUWrOO9SpC2PVX8m/ph0QMSuodNCRr3mpn9mablc1lUi38ogGoun0KHQf6m4BqTn0dnW6b8Y9ARci/1N31/Id+ERvC2vkvIm2rX0KmidEs9tbeUDEEX3RQcs61WHggYjBXyYmT/BXaLHo4kZ4NAkGSo2l9ky7iGcANiIqKCEAno2kaN0RvtuNMqefp4hSQmKQdTj1lx7FEDAvaIgZ477xDBCfrSQujd6ftcblxBG3jbeCluFpt8j6ktWsuoZ11NwZSoxEWZ4iotl2s8J2VFZotPGCyY7ipnnuJlWuJ1sSAYk1l5yvF7M3zoqYmPxx8B305P6QMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a7a21842a7b4f3bff9b46d086d6364aa\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4975", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:11E5:8BD98:53CEF47C", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 20 Oct 2007 11:24:19 GMT", "date": "Tue, 22 Jul 2014 23:32:13 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406073636"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901"}, "recorded_at": "2014-07-22T23:32:13"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/teams/189901/repos/github3py/urllib3"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4974", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:11E5:8BDCE:53CEF47D", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "access-control-allow-credentials": "true", "date": "Tue, 22 Jul 2014 23:32:13 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406073636"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/189901/repos/github3py/urllib3"}, "recorded_at": "2014-07-22T23:32:13"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index 335e9809b..345d0372a 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -29,6 +29,14 @@ def test_add_member(self): team = self.get_team() assert team.add_member('esacteksab') is True + def test_add_repository(self): + """Show that a user can add a repository to a team.""" + self.basic_login() + cassette_name = self.cassette_name('add_repository') + with self.recorder.use_cassette(cassette_name): + team = self.get_team() + assert team.add_repository('github3py/urllib3') is True + def test_remove_member(self): """Show a user can remove a member from a team.""" self.basic_login() From 2ad5b5bfd0f7055ac68cb41723966502d55df8c3 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:05:41 -0500 Subject: [PATCH 183/972] Add Team#delete integration test --- tests/cassettes/Team_delete.json | 1 + tests/integration/test_orgs_team.py | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/cassettes/Team_delete.json diff --git a/tests/cassettes/Team_delete.json b/tests/cassettes/Team_delete.json new file mode 100644 index 000000000..6f5ab4220 --- /dev/null +++ b/tests/cassettes/Team_delete.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4996", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:5E3C:1E3732:53CF0A45", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Wed, 23 Jul 2014 01:05:09 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-23T01:05:10"}, {"request": {"body": {"string": "{\"repo_names\": [], \"name\": \"delete-me\", \"permission\": \"\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "57", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "POST", "uri": "https://api.github.com/orgs/github3py/teams"}, "response": {"body": {"string": "{\"name\":\"delete-me\",\"id\":928041,\"slug\":\"delete-me\",\"permission\":\"pull\",\"url\":\"https://api.github.com/teams/928041\",\"members_url\":\"https://api.github.com/teams/928041/members{/member}\",\"repositories_url\":\"https://api.github.com/teams/928041/repos\",\"members_count\":0,\"repos_count\":0,\"organization\":{\"login\":\"github3py\",\"id\":1782156,\"url\":\"https://api.github.com/orgs/github3py\",\"repos_url\":\"https://api.github.com/orgs/github3py/repos\",\"events_url\":\"https://api.github.com/orgs/github3py/events\",\"members_url\":\"https://api.github.com/orgs/github3py/members{/member}\",\"public_members_url\":\"https://api.github.com/orgs/github3py/public_members{/member}\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/1782156?\",\"name\":\"github3.py\",\"company\":\"github3.io\",\"blog\":null,\"location\":\"Madison, WI\",\"email\":null,\"public_repos\":5,\"public_gists\":0,\"followers\":0,\"following\":0,\"html_url\":\"https://github.com/github3py\",\"created_at\":\"2012-05-27T04:25:36Z\",\"updated_at\":\"2014-07-20T16:00:32Z\",\"type\":\"Organization\"}}", "encoding": "utf-8"}, "headers": {"content-length": "1006", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e90a39243710c2c2f3703804b6ac4a0d\"", "location": "https://api.github.com/teams/928041", "access-control-allow-credentials": "true", "status": "201 Created", "x-ratelimit-remaining": "4995", "x-github-media-type": "github.v3; param=full; 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": "48A0C4D3:5E3C:1E374C:53CF0A45", "cache-control": "private, max-age=60, s-maxage=60", "date": "Wed, 23 Jul 2014 01:05:10 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "Created", "code": 201}, "url": "https://api.github.com/orgs/github3py/teams"}, "recorded_at": "2014-07-23T01:05:10"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/teams/928041"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4994", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:5E3C:1E3765:53CF0A46", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "c436b2b44345c72ff906059f604991e7", "access-control-allow-credentials": "true", "date": "Wed, 23 Jul 2014 01:05:10 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406080845"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/928041"}, "recorded_at": "2014-07-23T01:05:10"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index 345d0372a..ddd24ab01 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -13,10 +13,14 @@ class TestTeam(IntegrationHelper): betamax_kwargs = {'match_requests_on': ['method', 'uri', 'json-body']} - def get_team(self, organization='github3py', id=189901): - """Get our desired team.""" + def get_organization(self, organization='github3py'): o = self.gh.organization(organization) assert isinstance(o, github3.orgs.Organization) + return o + + def get_team(self, organization='github3py', id=189901): + """Get our desired team.""" + o = self.get_organization(organization) t = o.team(id) assert isinstance(t, github3.orgs.Team) return t @@ -37,6 +41,16 @@ def test_add_repository(self): team = self.get_team() assert team.add_repository('github3py/urllib3') is True + def test_delete(self): + """Show that a user can delete a team.""" + self.basic_login() + cassette_name = self.cassette_name('delete') + with self.recorder.use_cassette(cassette_name): + o = self.get_organization() + t = o.create_team('delete-me') + assert isinstance(t, github3.orgs.Team) + assert t.delete() is True + def test_remove_member(self): """Show a user can remove a member from a team.""" self.basic_login() From e5b8908ac5f1d906834292896277e67a97239b2d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:12:18 -0500 Subject: [PATCH 184/972] Add Team#edit integration test --- tests/cassettes/Team_edit.json | 1 + tests/integration/test_orgs_team.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/cassettes/Team_edit.json diff --git a/tests/cassettes/Team_edit.json b/tests/cassettes/Team_edit.json new file mode 100644 index 000000000..bf48eeaac --- /dev/null +++ b/tests/cassettes/Team_edit.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4977", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:5E3F:4D4830:53CF0BDB", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Wed, 23 Jul 2014 01:11:56 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-23T01:11:56"}, {"request": {"body": {"string": "{\"repo_names\": [], \"name\": \"edit-me\", \"permission\": \"\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "55", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "POST", "uri": "https://api.github.com/orgs/github3py/teams"}, "response": {"body": {"string": "{\"name\":\"edit-me\",\"id\":928052,\"slug\":\"edit-me\",\"permission\":\"pull\",\"url\":\"https://api.github.com/teams/928052\",\"members_url\":\"https://api.github.com/teams/928052/members{/member}\",\"repositories_url\":\"https://api.github.com/teams/928052/repos\",\"members_count\":0,\"repos_count\":0,\"organization\":{\"login\":\"github3py\",\"id\":1782156,\"url\":\"https://api.github.com/orgs/github3py\",\"repos_url\":\"https://api.github.com/orgs/github3py/repos\",\"events_url\":\"https://api.github.com/orgs/github3py/events\",\"members_url\":\"https://api.github.com/orgs/github3py/members{/member}\",\"public_members_url\":\"https://api.github.com/orgs/github3py/public_members{/member}\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/1782156?\",\"name\":\"github3.py\",\"company\":\"github3.io\",\"blog\":null,\"location\":\"Madison, WI\",\"email\":null,\"public_repos\":5,\"public_gists\":0,\"followers\":0,\"following\":0,\"html_url\":\"https://github.com/github3py\",\"created_at\":\"2012-05-27T04:25:36Z\",\"updated_at\":\"2014-07-20T16:00:32Z\",\"type\":\"Organization\"}}", "encoding": "utf-8"}, "headers": {"content-length": "1002", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"4d86fa91fd0a316f4bdc6fed96039110\"", "location": "https://api.github.com/teams/928052", "access-control-allow-credentials": "true", "status": "201 Created", "x-ratelimit-remaining": "4976", "x-github-media-type": "github.v3; param=full; 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": "48A0C4D3:5E3F:4D486A:53CF0BDC", "cache-control": "private, max-age=60, s-maxage=60", "date": "Wed, 23 Jul 2014 01:11:56 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "Created", "code": 201}, "url": "https://api.github.com/orgs/github3py/teams"}, "recorded_at": "2014-07-23T01:11:56"}, {"request": {"body": {"string": "{\"name\": \"delete-me\", \"permission\": \"admin\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "44", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PATCH", "uri": "https://api.github.com/teams/928052"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTy27CMBD8lcrnhDiGAPWl5x6qXpAq9YKcxA2W/JIfVBTx710SV4SoauHm9e6sd2fGR6SZ4oiilkseeA7nDIkW0UeyxhXJkJexm6Qtd0p4L4yGBGuV0ICJTkK0C8F6WhTMilknwi7Ws8aoInCmfDG0hFrFVc2d396MKRLimA4naOK4NV4E4wS/p1MPG83QmKgDojg13F5i4zqmxRcL/aJHJE0Hm1I07DW3h8RUuVqTslr+QwF088UY2g/yNwXXmOJndL7nOtwHHSC3Uj959xfybaylaLY3CTnpdg0dK8r2LDA3paS/9MlN0XPXGB2AgN5YsUjsP8FuycmJ5FkvEBRZpg8X2WbCwHUNYiKqo5QZ6NokjdELa4U3Ont4e4YirpgAUw9VaexBA1plKF10wgff++fDSGk+wdejSGh4BnK7oORksdH3GNuicZwF3m4ZmBIRXJIcVzlZbfCCkorOl+8wWLTtVc0ix6uc4E25pBjTOTnXhIM9f+vXsYlPp2/tsHw27wMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"79156a21ab48604f76070f1566ecd571\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4975", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:5E3F:4D489F:53CF0BDC", "cache-control": "private, max-age=60, s-maxage=60", "date": "Wed, 23 Jul 2014 01:11:56 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/928052"}, "recorded_at": "2014-07-23T01:11:56"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/teams/928052"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4974", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:5E3F:4D48D4:53CF0BDC", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "access-control-allow-credentials": "true", "date": "Wed, 23 Jul 2014 01:11:56 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406080845"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/928052"}, "recorded_at": "2014-07-23T01:11:56"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index ddd24ab01..8a234e00d 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -51,6 +51,22 @@ def test_delete(self): assert isinstance(t, github3.orgs.Team) assert t.delete() is True + def test_edit(self): + """Show that a user can edit a team.""" + self.basic_login() + cassette_name = self.cassette_name('edit') + with self.recorder.use_cassette(cassette_name): + o = self.get_organization() + # Create a new team to play with + t = o.create_team('edit-me') + assert isinstance(t, github3.orgs.Team) + # Edit the new team + assert t.edit('delete-me', permission='admin') is True + # Assert that the name has changed + assert t.name == 'delete-me' + # Get rid of it, we don't need it. + assert t.delete() is True + def test_remove_member(self): """Show a user can remove a member from a team.""" self.basic_login() From c1e7e603ad21f50b540f35ee86d732ee6b345b26 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:14:58 -0500 Subject: [PATCH 185/972] Login for all tests in TestTeam --- tests/integration/test_orgs_team.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index 8a234e00d..d09181685 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -13,7 +13,12 @@ class TestTeam(IntegrationHelper): betamax_kwargs = {'match_requests_on': ['method', 'uri', 'json-body']} + def setUp(self): + super(TestTeam, self).setUp() + self.basic_login() + def get_organization(self, organization='github3py'): + """Get the desired organization.""" o = self.gh.organization(organization) assert isinstance(o, github3.orgs.Organization) return o @@ -27,7 +32,6 @@ def get_team(self, organization='github3py', id=189901): def test_add_member(self): """Show a user can add a member to a team.""" - self.basic_login() cassette_name = self.cassette_name('add_member') with self.recorder.use_cassette(cassette_name): team = self.get_team() @@ -35,7 +39,6 @@ def test_add_member(self): def test_add_repository(self): """Show that a user can add a repository to a team.""" - self.basic_login() cassette_name = self.cassette_name('add_repository') with self.recorder.use_cassette(cassette_name): team = self.get_team() @@ -43,7 +46,6 @@ def test_add_repository(self): def test_delete(self): """Show that a user can delete a team.""" - self.basic_login() cassette_name = self.cassette_name('delete') with self.recorder.use_cassette(cassette_name): o = self.get_organization() @@ -53,7 +55,6 @@ def test_delete(self): def test_edit(self): """Show that a user can edit a team.""" - self.basic_login() cassette_name = self.cassette_name('edit') with self.recorder.use_cassette(cassette_name): o = self.get_organization() @@ -67,9 +68,12 @@ def test_edit(self): # Get rid of it, we don't need it. assert t.delete() is True + def test_has_repository(self): + """Show that a user can check of a team has access to a repository.""" + pass + def test_remove_member(self): """Show a user can remove a member from a team.""" - self.basic_login() cassette_name = self.cassette_name('remove_member') with self.recorder.use_cassette(cassette_name): team = self.get_team() From 2083bda9568054a44df9d869e6b43f898e81c352 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:31:19 -0500 Subject: [PATCH 186/972] Add requires_auth decorator to Team methods --- github3/orgs.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/github3/orgs.py b/github3/orgs.py index 5befd969b..259436d39 100644 --- a/github3/orgs.py +++ b/github3/orgs.py @@ -107,15 +107,17 @@ def edit(self, name, permission=''): return True return False - def has_repo(self, repo): - """Check if this team has access to ``repo``. + @requires_auth + def has_repository(self, repository): + """Check if this team has access to ``repository``. - :param str repo: (required), form: 'user/repo' + :param str repository: (required), form: 'user/repo' :returns: bool """ - url = self._build_url('repos', repo, base_url=self._api) + url = self._build_url('repos', repository, base_url=self._api) return self._boolean(self._get(url), 204, 404) + @requires_auth def is_member(self, username): """Check if ``username`` is a member of this team. @@ -125,6 +127,7 @@ def is_member(self, username): url = self._build_url('members', username, base_url=self._api) return self._boolean(self._get(url), 204, 404) + @requires_auth def members(self, number=-1, etag=None): r"""Iterate over the members of this team. @@ -144,6 +147,7 @@ def members(self, number=-1, etag=None): url = self._build_url('members', base_url=self._api) return self._iter(int(number), url, User, params=params, etag=etag) + @requires_auth def repositories(self, number=-1, etag=None): """Iterate over the repositories this team has access to. From b965e5843c5221a16057ae69578c63c65b37ed34 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:31:41 -0500 Subject: [PATCH 187/972] Add Team#has_repository integration test --- tests/cassettes/Team_has_repository.json | 1 + tests/integration/test_orgs_team.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 tests/cassettes/Team_has_repository.json diff --git a/tests/cassettes/Team_has_repository.json b/tests/cassettes/Team_has_repository.json new file mode 100644 index 000000000..6d96839a4 --- /dev/null +++ b/tests/cassettes/Team_has_repository.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4969", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7283:108869:53CF0D36", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Wed, 23 Jul 2014 01:17:43 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-23T01:17:43"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTyW7CMBT8lcrnLE4gUHzpuYeqF6RKvURO4gZL3uQFRBH/3kdiREBVCzf7+c1bZsYHpKhkiKD3nWLWoQTxDpHiebXCRYKcCD286fObYVZy57hWEKWd5AoAwQq4bbw3juQ5NTzrud+EJmu1zD2j0uVjPciVTDbQpr4bk0fEIR6OUMQyox332nL2SKUBNpmh1UF52DUWrOO9SpC2PVX8m/ph0QMSuodNCRr3mpn9mablc1lUi38ogGoun0KHQf6m4BqTn0dnW6b8Y9ARci/1N31/Id+ERvC2vkvIm2rX0KmidEs9tbeUDEEX3RQcs61WHggYjBXyYmT/BXaLHo4kZ4NAkGSo2l9ky7iGcANiIqKCEAno2kaN0RvtuNMqefp4hSQmKQdTj1lx7FEDAvaIgZ477xDBCfrSQujd6ftcblxBG3jbeCluFpt8j6ktWsuoZ11NwZSoxEWZ4iotl2s8J2VFZotPGCyY7ipnnuJlWuJ1sSAYk1l5yvF7M3zoqYmPxx8B305P6QMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a7a21842a7b4f3bff9b46d086d6364aa\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4968", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7283:108873:53CF0D37", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 20 Oct 2007 11:24:19 GMT", "date": "Wed, 23 Jul 2014 01:17:43 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901"}, "recorded_at": "2014-07-23T01:17:43"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901/repos/github3py/urllib3"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4967", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:7283:10887A:53CF0D37", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "132026e9262a0093e437f99db5f1e499", "access-control-allow-credentials": "true", "date": "Wed, 23 Jul 2014 01:17:43 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406080845"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/189901/repos/github3py/urllib3"}, "recorded_at": "2014-07-23T01:17:43"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index d09181685..fbac8bade 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -70,7 +70,10 @@ def test_edit(self): def test_has_repository(self): """Show that a user can check of a team has access to a repository.""" - pass + cassette_name = self.cassette_name('has_repository') + with self.recorder.use_cassette(cassette_name): + t = self.get_team() + assert t.has_repository('github3py/urllib3') is True def test_remove_member(self): """Show a user can remove a member from a team.""" From ce81ae9cbea81eafc0f4b50508b0c39383ba8dbd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:31:55 -0500 Subject: [PATCH 188/972] Migrate Team unit tests --- tests/test_orgs.py | 21 --------------------- tests/unit/test_orgs_team.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 6a191101d..300ca371a 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -58,27 +58,6 @@ def test_edit(self): assert self.team.edit('Collab', 'admin') self.mock_assertions() - def test_has_repo(self): - self.response('', 204) - self.get(self.api + '/repos/repo') - - assert self.team.has_repo('repo') - self.mock_assertions() - - def test_is_member(self): - self.response('', 404) - self.get(self.api + '/members/user') - - assert self.team.is_member('user') is False - self.mock_assertions() - - def test_members(self): - self.response('user', _iter=True) - self.get(self.api + '/members') - - assert isinstance(next(self.team.members()), github3.users.User) - self.mock_assertions() - def test_remove_member(self): self.response('', 204) self.delete(self.api + '/members/user') diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index bf918a181..18c5ea01f 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -43,6 +43,32 @@ def test_add_repository_requires_auth(self): with pytest.raises(GitHubError): self.instance.add_repository('repo') + def test_has_repository(self): + """Show that a user can check if a team has access to a repository.""" + self.instance.has_repository('org/repo') + + self.session.get.assert_called_once_with(url_for('repos/org/repo')) + + def test_has_repository_requires_auth(self): + """Show that checking a team's access to a repo needs auth.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.has_repository('org/repo') + + def test_is_member(self): + """Show that a user can check if another user is a team member.""" + self.instance.is_member('username') + + self.session.get.assert_called_once_with(url_for('members/username')) + + def test_is_member_requires_auth(self): + """Show that checking a user's team membership requires auth.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.is_member('user') + def test_remove_repository(self): """Show that a user can remove a repository from a team.""" self.instance.remove_repository('repo') @@ -75,6 +101,13 @@ def test_members(self): headers={} ) + def test_members_requires_auth(self): + """Show that one needs to authenticate to get team members.""" + self.session.has_auth.return_value = False + + with pytest.raises(GitHubError): + self.instance.members() + def test_repositories(self): """Show that one can iterate over an organization's repositories.""" i = self.instance.repositories() From 2ae539eaba42f8593d8c84d027dcd711ab6733b4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:44:07 -0500 Subject: [PATCH 189/972] Add Test#is_member integration test --- tests/cassettes/Team_is_member.json | 1 + tests/integration/test_orgs_team.py | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 tests/cassettes/Team_is_member.json diff --git a/tests/cassettes/Team_is_member.json b/tests/cassettes/Team_is_member.json new file mode 100644 index 000000000..8555a7ce3 --- /dev/null +++ b/tests/cassettes/Team_is_member.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4962", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:32F8:22C089:53CF1316", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Wed, 23 Jul 2014 01:42:47 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-23T01:42:47"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTyW7CMBT8lcrnLE4gUHzpuYeqF6RKvURO4gZL3uQFRBH/3kdiREBVCzf7+c1bZsYHpKhkiKD3nWLWoQTxDpHiebXCRYKcCD286fObYVZy57hWEKWd5AoAwQq4bbw3juQ5NTzrud+EJmu1zD2j0uVjPciVTDbQpr4bk0fEIR6OUMQyox332nL2SKUBNpmh1UF52DUWrOO9SpC2PVX8m/ph0QMSuodNCRr3mpn9mablc1lUi38ogGoun0KHQf6m4BqTn0dnW6b8Y9ARci/1N31/Id+ERvC2vkvIm2rX0KmidEs9tbeUDEEX3RQcs61WHggYjBXyYmT/BXaLHo4kZ4NAkGSo2l9ky7iGcANiIqKCEAno2kaN0RvtuNMqefp4hSQmKQdTj1lx7FEDAvaIgZ477xDBCfrSQujd6ftcblxBG3jbeCluFpt8j6ktWsuoZ11NwZSoxEWZ4iotl2s8J2VFZotPGCyY7ipnnuJlWuJ1sSAYk1l5yvF7M3zoqYmPxx8B305P6QMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a7a21842a7b4f3bff9b46d086d6364aa\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4961", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:32F8:22C0B3:53CF1317", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 20 Oct 2007 11:24:19 GMT", "date": "Wed, 23 Jul 2014 01:42:47 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901"}, "recorded_at": "2014-07-23T01:42:47"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901/members/sigmavirus24"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4960", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:32F8:22C0D3:53CF1317", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "access-control-allow-credentials": "true", "date": "Wed, 23 Jul 2014 01:42:47 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406080845"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/189901/members/sigmavirus24"}, "recorded_at": "2014-07-23T01:42:47"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index fbac8bade..43d328c5f 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -75,6 +75,13 @@ def test_has_repository(self): t = self.get_team() assert t.has_repository('github3py/urllib3') is True + def test_is_member(self): + """Show that a user can check if another user is a team member.""" + cassette_name = self.cassette_name('is_member') + with self.recorder.use_cassette(cassette_name): + t = self.get_team() + assert t.is_member('sigmavirus24') is True + def test_remove_member(self): """Show a user can remove a member from a team.""" cassette_name = self.cassette_name('remove_member') From a4c2b18ad3728cb15b69637fdb0f517cda61e7e9 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:46:03 -0500 Subject: [PATCH 190/972] Add Team#members integration test --- tests/cassettes/Team_members.json | 1 + tests/integration/test_orgs_team.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/Team_members.json diff --git a/tests/cassettes/Team_members.json b/tests/cassettes/Team_members.json new file mode 100644 index 000000000..72b6bff78 --- /dev/null +++ b/tests/cassettes/Team_members.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4959", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:727F:1A5298:53CF13BD", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Wed, 23 Jul 2014 01:45:33 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-23T01:45:33"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTyW7CMBT8lcrnLE4gUHzpuYeqF6RKvURO4gZL3uQFRBH/3kdiREBVCzf7+c1bZsYHpKhkiKD3nWLWoQTxDpHiebXCRYKcCD286fObYVZy57hWEKWd5AoAwQq4bbw3juQ5NTzrud+EJmu1zD2j0uVjPciVTDbQpr4bk0fEIR6OUMQyox332nL2SKUBNpmh1UF52DUWrOO9SpC2PVX8m/ph0QMSuodNCRr3mpn9mablc1lUi38ogGoun0KHQf6m4BqTn0dnW6b8Y9ARci/1N31/Id+ERvC2vkvIm2rX0KmidEs9tbeUDEEX3RQcs61WHggYjBXyYmT/BXaLHo4kZ4NAkGSo2l9ky7iGcANiIqKCEAno2kaN0RvtuNMqefp4hSQmKQdTj1lx7FEDAvaIgZ477xDBCfrSQujd6ftcblxBG3jbeCluFpt8j6ktWsuoZ11NwZSoxEWZ4iotl2s8J2VFZotPGCyY7ipnnuJlWuJ1sSAYk1l5yvF7M3zoqYmPxx8B305P6QMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a7a21842a7b4f3bff9b46d086d6364aa\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4958", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:727F:1A52AF:53CF13BD", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 20 Oct 2007 11:24:19 GMT", "date": "Wed, 23 Jul 2014 01:45:33 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901"}, "recorded_at": "2014-07-23T01:45:33"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901/members?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52Ty26DMBBF/8XrKA6PJMAmX9FVVSFjBhgJbGQbohTl3zsGVKlsKliBkM+Z64v9ObFW16hYxizWnRjRDDaM2YlhybIwviTR5cTEKJww+WBaWtc419uM8+WjPdfomqEYLBiplQPlzlJ3fOAL/CBVbVaBdzIZxEl0vZVJWqXhFW5pGNyTAiAo00jI6k7AZlCP65DFTJMs36RtXNdu8i25ZmSzuNJtq59k2e7ov0H8l6SQyzuq+qCFyIlr1wAVS1t6+6LQuv2hZmri/pFj6T2W/paBcnewlaNYT0WJJm6g17NwKKw02DvUan/APzTZtKmFwm9xzEa0JYmPtj/KTBENIx3U/fiCTbw3OAr58tUYkIAjlX1QueHJ6F490D35oEPhq0cHuSg7f0cr0Vp4f/0A/p8Y7LUDAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"6e61732b48fdd33d664a49419e6ae91c\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4957", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:727F:1A52C2:53CF13BD", "cache-control": "private, max-age=60, s-maxage=60", "date": "Wed, 23 Jul 2014 01:45:33 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901/members?per_page=100"}, "recorded_at": "2014-07-23T01:45:33"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index 43d328c5f..10b41c624 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -82,6 +82,14 @@ def test_is_member(self): t = self.get_team() assert t.is_member('sigmavirus24') is True + def test_members(self): + """Show that a user can retrieve a team's members.""" + cassette_name = self.cassette_name('members') + with self.recorder.use_cassette(cassette_name): + t = self.get_team() + for user in t.members(): + assert isinstance(user, github3.users.User) + def test_remove_member(self): """Show a user can remove a member from a team.""" cassette_name = self.cassette_name('remove_member') From e362c1130f4cc7ab010c0d6f3f0e356ee36cc3c5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:47:43 -0500 Subject: [PATCH 191/972] Add Test#repositories integration test --- tests/cassettes/Team_repositories.json | 1 + tests/integration/test_orgs_team.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/Team_repositories.json diff --git a/tests/cassettes/Team_repositories.json b/tests/cassettes/Team_repositories.json new file mode 100644 index 000000000..c7cc2a323 --- /dev/null +++ b/tests/cassettes/Team_repositories.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4956", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:32F7:16C92C:53CF1427", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Wed, 23 Jul 2014 01:47:19 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-23T01:47:19"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTyW7CMBT8lcrnLE4gUHzpuYeqF6RKvURO4gZL3uQFRBH/3kdiREBVCzf7+c1bZsYHpKhkiKD3nWLWoQTxDpHiebXCRYKcCD286fObYVZy57hWEKWd5AoAwQq4bbw3juQ5NTzrud+EJmu1zD2j0uVjPciVTDbQpr4bk0fEIR6OUMQyox332nL2SKUBNpmh1UF52DUWrOO9SpC2PVX8m/ph0QMSuodNCRr3mpn9mablc1lUi38ogGoun0KHQf6m4BqTn0dnW6b8Y9ARci/1N31/Id+ERvC2vkvIm2rX0KmidEs9tbeUDEEX3RQcs61WHggYjBXyYmT/BXaLHo4kZ4NAkGSo2l9ky7iGcANiIqKCEAno2kaN0RvtuNMqefp4hSQmKQdTj1lx7FEDAvaIgZ477xDBCfrSQujd6ftcblxBG3jbeCluFpt8j6ktWsuoZ11NwZSoxEWZ4iotl2s8J2VFZotPGCyY7ipnnuJlWuJ1sSAYk1l5yvF7M3zoqYmPxx8B305P6QMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a7a21842a7b4f3bff9b46d086d6364aa\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4955", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:32F7:16C949:53CF1427", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 20 Oct 2007 11:24:19 GMT", "date": "Wed, 23 Jul 2014 01:47:19 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901"}, "recorded_at": "2014-07-23T01:47:19"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/189901/repos?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"6877b61b82525197dbbd565d97e7890b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4954", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:32F7:16C954:53CF1427", "cache-control": "private, max-age=60, s-maxage=60", "date": "Wed, 23 Jul 2014 01:47:19 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/189901/repos?per_page=100"}, "recorded_at": "2014-07-23T01:47:19"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index 10b41c624..031815100 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -90,6 +90,14 @@ def test_members(self): for user in t.members(): assert isinstance(user, github3.users.User) + def test_repositories(self): + """Show that a user can retrieve a team's repositories.""" + cassette_name = self.cassette_name('repositories') + with self.recorder.use_cassette(cassette_name): + t = self.get_team() + for repository in t.repositories(): + assert isinstance(repository, github3.repos.Repository) + def test_remove_member(self): """Show a user can remove a member from a team.""" cassette_name = self.cassette_name('remove_member') From 59053525a735e3b693289598322b72fc6a64026d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 20:49:57 -0500 Subject: [PATCH 192/972] Add Team#remove_repository integration test --- tests/cassettes/Team_remove_repository.json | 1 + tests/integration/test_orgs_team.py | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 tests/cassettes/Team_remove_repository.json diff --git a/tests/cassettes/Team_remove_repository.json b/tests/cassettes/Team_remove_repository.json new file mode 100644 index 000000000..5d10c64fe --- /dev/null +++ b/tests/cassettes/Team_remove_repository.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52SPW/CMBCG/0rlOSROIFB5adcOVRekSl2iS3CMVce2bAdEEf+9ZxJKSie6Jed77+N570iUEVITRoQM276e2wNJiNwQlq8ei7xcJqR3Cp+3IVjPsgysTIfUtDFdZpzw2VTquDW+ukOTnRXYlO+4DvdJBwlqO97V3N0nHjXHbPg4YRnb10o21X+q/ZZOi8IOArhbJOegH1H2nrvG6IAAzlT7bKT/hENp6PjVn/RsECZZ0IdJWBoM12gmYbpXKkFfGwjSRGtfYSO90cnD+0vk3IFER4escezBA1b+IBDSB08YTUhrlDJ7hDv5kxrb4Ns2dOpmscltTM+icRwC31QQcJ6C5sWMlrNitaYLVpRsvvzAwXq7+ZWzmNHVrKDrfMkoZfMi5oSDjTDenAAtv4YFMWoCqMo6iVR5NS6D85m9xp5/45fIdUsE9Fn1HgRWz+kiElYKauMgmHH1WiqFi1cjPyJcCm2bQrRMpZ3UqTC7ZxHpRhPjOSlA/MeLg63jHKPeQoNd5nRVUJzxdrrT6Rvyb5wJlAMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7a807b488b5268f40ea462dc5a957426\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4951", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7280:2AFEE9:53CF14B0", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 16:00:32 GMT", "date": "Wed, 23 Jul 2014 01:49:36 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2014-07-23T01:49:36"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/teams/923595"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5VTy27CMBD8FeRzQoJDoPjSC5ce2l6QKvWCTOIGS45t2Wsqivj3LolRA6pauPkxs96dGR+I5q0gjCzN6MXAaCmUAEESImvCFrQoF2VCvAoNQmqTagNpfYZY4VrpvTQaL21QCmnBKdxsAaxnWcatHDcStmEzrkybgeCtz/qqiG1FuxHOr2/mZJFxiIsjFnHCGi/BOCnuqdTRBj1UJmggjMaC67jPE2Jcw7X84tDNeSDKNPI0cD9XYfdRrMn8gU7K2T8SYDWfDaldI39LcMnJzq2LndBwH7Wn3Cr91bu/iG/DRslqfZORV9UuqUNH+Y4Dd9eSdIc+pil44SqjAQXoghWyqP4jzhYDHUUedwYhyHK9/7FtLA0eb9BMwjRGN0Ffq+gxeea19EYno7cnBImWSwx1j4pt9x4w/BvxoJEePGGYlw+jlPnEXA92UuMzeLeFVl0NNvgew1hUTnAQ9ZpjKAnNJzTNy5TOV/mU0ZIVs3dsLNj6AjNN83lK89VkxvKcFfSEgb09/e7XYYiPx2/vMnxZ9gMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"edeabf4202bc77a71f4736ad0d8dd01d\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4950", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7280:2AFF0C:53CF14B0", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 02:28:53 GMT", "date": "Wed, 23 Jul 2014 01:49:36 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406080845"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/teams/923595"}, "recorded_at": "2014-07-23T01:49:37"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/teams/923595/repos/github3py/urllib3"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4949", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:7280:2AFF2E:53CF14B0", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "access-control-allow-credentials": "true", "date": "Wed, 23 Jul 2014 01:49:36 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406080845"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/teams/923595/repos/github3py/urllib3"}, "recorded_at": "2014-07-23T01:49:37"}], "recorded_with": "betamax/{version}"} \ No newline at end of file diff --git a/tests/integration/test_orgs_team.py b/tests/integration/test_orgs_team.py index 031815100..37b9faaba 100644 --- a/tests/integration/test_orgs_team.py +++ b/tests/integration/test_orgs_team.py @@ -104,3 +104,10 @@ def test_remove_member(self): with self.recorder.use_cassette(cassette_name): team = self.get_team() assert team.remove_member('esacteksab') is True + + def test_remove_repository(self): + """Show a user can remove a repository from a team.""" + cassette_name = self.cassette_name('remove_repository') + with self.recorder.use_cassette(cassette_name): + team = self.get_team(id=923595) + assert team.remove_repository('github3py/urllib3') is True From 9944ad9b34c0e3667d63071a1448e6d5177ce2dd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 21:25:43 -0500 Subject: [PATCH 193/972] Refactor some tests --- tests/unit/test_orgs_team.py | 47 +++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index 18c5ea01f..fcbe661f9 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -36,26 +36,12 @@ def test_add_repository(self): self.session.put.assert_called_once_with(url_for('repos/name-of-repo')) - def test_add_repository_requires_auth(self): - """Show that adding a repo to a team requires authentication.""" - self.session.has_auth.return_value = False - - with pytest.raises(GitHubError): - self.instance.add_repository('repo') - def test_has_repository(self): """Show that a user can check if a team has access to a repository.""" self.instance.has_repository('org/repo') self.session.get.assert_called_once_with(url_for('repos/org/repo')) - def test_has_repository_requires_auth(self): - """Show that checking a team's access to a repo needs auth.""" - self.session.has_auth.return_value = False - - with pytest.raises(GitHubError): - self.instance.has_repository('org/repo') - def test_is_member(self): """Show that a user can check if another user is a team member.""" self.instance.is_member('username') @@ -83,6 +69,39 @@ def test_remove_repository_requires_auth(self): self.instance.remove_repository('repo') +class TestTeamRequiresAuth(UnitHelper): + described_class = Team + example_data = { + 'url': 'https://api.github.com/teams/10', + 'name': 'Owners', + 'id': 10, + 'permission': 'admin', + 'members_count': 3, + 'repos_count': 10, + 'organization': { + 'login': 'github', + 'id': 1, + 'url': 'https://api.github.com/orgs/github', + 'avatar_url': 'https://github.com/images/error/octocat_happy.gif' + } + } + + def setUp(self): + """Set up for test cases in TestTeamRequiresAuth.""" + super(TestTeamRequiresAuth, self).setUp() + self.session.has_auth.return_value = False + + def test_add_repository_requires_auth(self): + """Show that adding a repo to a team requires authentication.""" + with pytest.raises(GitHubError): + self.instance.add_repository('repo') + + def test_has_repository_requires_auth(self): + """Show that checking a team's access to a repo needs auth.""" + with pytest.raises(GitHubError): + self.instance.has_repository('org/repo') + + class TestTeamIterator(UnitIteratorHelper): described_class = Team From e2ad9613cab28635e7d9fc578e214d8a630ff963 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 21:26:22 -0500 Subject: [PATCH 194/972] Move and refactor last couple of tests --- tests/unit/test_orgs_team.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index fcbe661f9..77e6819a7 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -48,26 +48,12 @@ def test_is_member(self): self.session.get.assert_called_once_with(url_for('members/username')) - def test_is_member_requires_auth(self): - """Show that checking a user's team membership requires auth.""" - self.session.has_auth.return_value = False - - with pytest.raises(GitHubError): - self.instance.is_member('user') - def test_remove_repository(self): """Show that a user can remove a repository from a team.""" self.instance.remove_repository('repo') self.session.delete.assert_called_once_with(url_for('/repos/repo')) - def test_remove_repository_requires_auth(self): - """Show that removing a repo from a team requires authentication.""" - self.session.has_auth.return_value = False - - with pytest.raises(GitHubError): - self.instance.remove_repository('repo') - class TestTeamRequiresAuth(UnitHelper): described_class = Team @@ -101,6 +87,16 @@ def test_has_repository_requires_auth(self): with pytest.raises(GitHubError): self.instance.has_repository('org/repo') + def test_is_member_requires_auth(self): + """Show that checking a user's team membership requires auth.""" + with pytest.raises(GitHubError): + self.instance.is_member('user') + + def test_remove_repository_requires_auth(self): + """Show that removing a repo from a team requires authentication.""" + with pytest.raises(GitHubError): + self.instance.remove_repository('repo') + class TestTeamIterator(UnitIteratorHelper): described_class = Team From 2aa596ae7ed2709b754809dcbcc65c43ae1f2bae Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 21:49:46 -0500 Subject: [PATCH 195/972] Migrate Team#add_member unit test --- tests/test_orgs.py | 12 ------------ tests/unit/test_orgs_team.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 300ca371a..1870e43e0 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -21,18 +21,6 @@ def test_equality(self): t._uniq = 'foo' assert self.team != t - def test_add_member(self): - self.response('', 204) - self.put(self.api + '/members/foo') - self.conf = {'data': None} - - self.assertRaises(github3.GitHubError, self.team.add_member, 'foo') - - self.not_called() - self.login() - assert self.team.add_member('foo') - self.mock_assertions() - def test_delete(self): self.response('', 204) self.delete(self.api) diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index 77e6819a7..a03faf576 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -30,6 +30,12 @@ class TestTeam(UnitHelper): } } + def test_add_member(self): + """Show that one can add a member to an organization team.""" + self.instance.add_member('user') + + self.session.put.assert_called_once_with(url_for('members/user')) + def test_add_repository(self): """Show that one can add a repository to an organization team.""" self.instance.add_repository('name-of-repo') @@ -77,6 +83,11 @@ def setUp(self): super(TestTeamRequiresAuth, self).setUp() self.session.has_auth.return_value = False + def test_add_member_requires_auth(self): + """Show that adding a repo to a team requires authentication.""" + with pytest.raises(GitHubError): + self.instance.add_member('user') + def test_add_repository_requires_auth(self): """Show that adding a repo to a team requires authentication.""" with pytest.raises(GitHubError): From e4e07b369ebd2c9658898f564ce00a9ba4717327 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 21:53:19 -0500 Subject: [PATCH 196/972] Migrate unit tests for Team#delete --- tests/test_orgs.py | 11 ----------- tests/unit/test_orgs_team.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 1870e43e0..781d48e4f 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -21,17 +21,6 @@ def test_equality(self): t._uniq = 'foo' assert self.team != t - def test_delete(self): - self.response('', 204) - self.delete(self.api) - - self.assertRaises(github3.GitHubError, self.team.delete) - - self.not_called() - self.login() - assert self.team.delete() - self.mock_assertions() - def test_edit(self): self.response('team', 200) self.patch(self.api) diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index a03faf576..2ea891f95 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -42,6 +42,12 @@ def test_add_repository(self): self.session.put.assert_called_once_with(url_for('repos/name-of-repo')) + def test_delete(self): + """Show that a user can delete an organization team.""" + self.instance.delete() + + self.session.delete.assert_called_once_with(url_for()) + def test_has_repository(self): """Show that a user can check if a team has access to a repository.""" self.instance.has_repository('org/repo') @@ -93,6 +99,11 @@ def test_add_repository_requires_auth(self): with pytest.raises(GitHubError): self.instance.add_repository('repo') + def test_delete_requires_auth(self): + """Show that deleteing a team requires authentication.""" + with pytest.raises(GitHubError): + self.instance.delete() + def test_has_repository_requires_auth(self): """Show that checking a team's access to a repo needs auth.""" with pytest.raises(GitHubError): From 18cc9f1965c455e7c2a8634c84696df72abff62a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 22 Jul 2014 22:00:22 -0500 Subject: [PATCH 197/972] Migrate Team#edit unit tests - Add patch_called_with --- tests/test_orgs.py | 14 -------------- tests/unit/helper.py | 20 ++++++++++++++++++++ tests/unit/test_orgs_team.py | 12 ++++++++++++ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 781d48e4f..9ece8ec25 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -21,20 +21,6 @@ def test_equality(self): t._uniq = 'foo' assert self.team != t - def test_edit(self): - self.response('team', 200) - self.patch(self.api) - self.conf = {'data': {'name': 'Collab', 'permission': 'admin'}} - - self.assertRaises(github3.GitHubError, self.team.edit, None) - - self.login() - assert self.team.edit(None) is False - self.not_called() - - assert self.team.edit('Collab', 'admin') - self.mock_assertions() - def test_remove_member(self): self.response('', 204) self.delete(self.api + '/members/user') diff --git a/tests/unit/helper.py b/tests/unit/helper.py index 5a0e759ac..c657b39d7 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -48,6 +48,26 @@ def create_instance_of_described_class(self): return instance + def patch_called_with(self, *args, **kwargs): + assert self.session.patch.called is True + call_args, call_kwargs = self.session.patch.call_args + + # Data passed to assertion + data = kwargs.pop('data', None) + # Data passed to patch + call_data = call_kwargs.pop('data', None) + # Data passed by the call to post positionally + # URL, 'json string' + if call_data is None: + call_args, call_data = call_args[:1], call_args[1] + # If data is a dictionary (or list) and call_data exists + if not isinstance(data, str) and call_data: + call_data = json.loads(call_data) + + assert args == call_args + assert data == call_data + assert kwargs == call_kwargs + def post_called_with(self, *args, **kwargs): assert self.session.post.called is True call_args, call_kwargs = self.session.post.call_args diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index 2ea891f95..75b179c61 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -48,6 +48,13 @@ def test_delete(self): self.session.delete.assert_called_once_with(url_for()) + def test_edit(self): + """Show that a user can edit a team.""" + self.instance.edit('name', 'admin') + + self.patch_called_with(url_for(), + data={'name': 'name', 'permission': 'admin'}) + def test_has_repository(self): """Show that a user can check if a team has access to a repository.""" self.instance.has_repository('org/repo') @@ -104,6 +111,11 @@ def test_delete_requires_auth(self): with pytest.raises(GitHubError): self.instance.delete() + def test_edit_requires_auth(self): + """Show that editing a team requires authentication.""" + with pytest.raises(GitHubError): + self.instance.edit('name') + def test_has_repository_requires_auth(self): """Show that checking a team's access to a repo needs auth.""" with pytest.raises(GitHubError): From 70ff7bb65856ff85629636813e19d4d5993a3217 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 08:14:37 -0500 Subject: [PATCH 198/972] Migrate Team#remove_member unit tests --- tests/test_orgs.py | 11 ----------- tests/unit/test_orgs_team.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 9ece8ec25..52d85fe39 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -21,17 +21,6 @@ def test_equality(self): t._uniq = 'foo' assert self.team != t - def test_remove_member(self): - self.response('', 204) - self.delete(self.api + '/members/user') - - self.assertRaises(github3.GitHubError, self.team.remove_member, None) - - self.not_called() - self.login() - assert self.team.remove_member('user') - self.mock_assertions() - class TestOrganization(BaseCase): def __init__(self, methodName='runTest'): diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index 75b179c61..96047bcbb 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -67,6 +67,14 @@ def test_is_member(self): self.session.get.assert_called_once_with(url_for('members/username')) + def test_remove_member(self): + """Show that a user can check if another user is a team member.""" + self.instance.remove_member('username') + + self.session.delete.assert_called_once_with( + url_for('members/username') + ) + def test_remove_repository(self): """Show that a user can remove a repository from a team.""" self.instance.remove_repository('repo') @@ -126,6 +134,11 @@ def test_is_member_requires_auth(self): with pytest.raises(GitHubError): self.instance.is_member('user') + def test_remove_member_requires_auth(self): + """Show that removing a team member requires authentication.""" + with pytest.raises(GitHubError): + self.instance.remove_member('user') + def test_remove_repository_requires_auth(self): """Show that removing a repo from a team requires authentication.""" with pytest.raises(GitHubError): From 4be4b21008017d3376ba2ea2f9cfdfd727262975 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 08:24:59 -0500 Subject: [PATCH 199/972] Add some docstrings to UnitHelper --- tests/unit/helper.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index c657b39d7..bdc00a723 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -8,6 +8,7 @@ def build_url(self, *args, **kwargs): + """A function to proxy to the actual GitHubSession#build_url method.""" # We want to assert what is happening with the actual calls to the # Internet. We can proxy this. return github3.session.GitHubSession().build_url(*args, **kwargs) @@ -20,10 +21,12 @@ class UnitHelper(unittest.TestCase): example_data = {} def create_mocked_session(self): + """Use mock to auto-spec a GitHubSession and return an instance.""" MockedSession = mock.create_autospec(github3.session.GitHubSession) return MockedSession() def create_session_mock(self, *args): + """Create a mocked session and add headers and auth attributes.""" session = self.create_mocked_session() base_attrs = ['headers', 'auth'] attrs = dict( @@ -39,6 +42,12 @@ def create_session_mock(self, *args): return session def create_instance_of_described_class(self): + """ + Use cls.example_data to create an instance of the described class. + + If cls.example_data is None, just create a simple instance of the + class. + """ if self.example_data: instance = self.described_class(self.example_data, self.session) @@ -49,6 +58,7 @@ def create_instance_of_described_class(self): return instance def patch_called_with(self, *args, **kwargs): + """Use to assert patch was called with JSON.""" assert self.session.patch.called is True call_args, call_kwargs = self.session.patch.call_args @@ -69,6 +79,7 @@ def patch_called_with(self, *args, **kwargs): assert kwargs == call_kwargs def post_called_with(self, *args, **kwargs): + """Use to assert post was called with JSON.""" assert self.session.post.called is True call_args, call_kwargs = self.session.post.call_args @@ -86,6 +97,7 @@ def post_called_with(self, *args, **kwargs): assert kwargs == call_kwargs def setUp(self): + """Use to set up attributes on self before each test.""" self.session = self.create_session_mock() self.instance = self.create_instance_of_described_class() # Proxy the build_url method to the class so it can build the URL and From 751490677840ef263dc75c7616d126daea373c7d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 08:38:29 -0500 Subject: [PATCH 200/972] Improve unit helper docstrings and comments. --- tests/unit/helper.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index bdc00a723..f7582b73f 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -15,6 +15,9 @@ def build_url(self, *args, **kwargs): class UnitHelper(unittest.TestCase): + + """Base class for unittests.""" + # Sub-classes must assign the class to this during definition described_class = None # Sub-classes must also assign a dictionary to this during definition @@ -107,10 +110,19 @@ def setUp(self): class UnitIteratorHelper(UnitHelper): + + """Base class for iterator based unit tests.""" + def create_session_mock(self, *args): + """Override UnitHelper's create_session_mock method. + + We want all methods to return an instance of the NullObject. This + class has a dummy ``__iter__`` implementation which we want for + methods that iterate over the results of a response. + """ # Retrieve a mocked session object session = super(UnitIteratorHelper, self).create_mocked_session(*args) - # Initialize a NullObject + # Initialize a NullObject which has magical properties null = github3.structs.NullObject() # Set it as the return value for every method session.delete.return_value = null @@ -121,13 +133,14 @@ def create_session_mock(self, *args): return session def get_next(self, iterator): + """Nicely wrap up a call to the iterator.""" try: next(iterator) except StopIteration: pass def patch_get_json(self): - """Patch a GitHubIterator's _get_json method""" + """Patch a GitHubIterator's _get_json method.""" self.get_json_mock = mock.patch.object( github3.structs.GitHubIterator, '_get_json' ) @@ -135,9 +148,11 @@ def patch_get_json(self): self.patched_get_json.return_value = [] def setUp(self): + """Use UnitHelper's setUp but also patch _get_json.""" super(UnitIteratorHelper, self).setUp() self.patch_get_json() def tearDown(self): + """Stop mocking _get_json.""" super(UnitIteratorHelper, self).tearDown() self.get_json_mock.stop() From 15409e230eac2a66bc486e50a9518df27ec7f3fe Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 08:41:36 -0500 Subject: [PATCH 201/972] Separate Organization unit tests that require auth --- tests/unit/test_orgs.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index d3d0f79c8..3c87c6ab1 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -42,13 +42,6 @@ def test_add_member(self): 'https://api.github.com/teams/10/members/user' ) - def test_add_member_requires_auth(self): - """Show that one must be authenticated to add a member to an org.""" - self.session.has_auth.return_value = False - - with pytest.raises(GitHubError): - self.instance.add_member('user', 10) - def test_add_repository(self): """Show that one can add a repository to an organization.""" self.instance.add_repository('name-of-repo', 10) @@ -113,6 +106,38 @@ def test_remove_repository_requires_auth(self): self.instance.remove_repository('repo-name', 10) +class TestOrganizationRequiresAuth(UnitHelper): + described_class = Organization + example_data = { + 'login': 'hapy', + 'id': 1, + 'url': 'https://api.github.com/orgs/hapy', + 'avatar_url': 'https://github.com/images/error/octocat_happy.gif', + 'name': 'github', + 'company': 'GitHub', + 'blog': 'https://github.com/blog', + 'location': 'San Francisco', + 'email': 'octocat@github.com', + 'public_repos': 2, + 'public_gists': 1, + 'followers': 20, + 'following': 0, + 'html_url': 'https://github.com/hapy', + 'created_at': '2008-01-14T04:33:35Z', + 'type': 'Organization' + } + + def setUp(self): + """Set MockedSession#has_auth.return_value to False.""" + super(TestOrganizationIterator, self).setUp() + self.session.has_auth.return_value = False + + def test_add_member_requires_auth(self): + """Show that one must be authenticated to add a member to an org.""" + with pytest.raises(GitHubError): + self.instance.add_member('user', 10) + + class TestOrganizationIterator(UnitIteratorHelper): described_class = Organization From 27e369beb86486014fc5ac8e866c80c572b30fcb Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 08:42:07 -0500 Subject: [PATCH 202/972] Relocate Organization#add_repository auth unit test --- tests/unit/test_orgs.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 3c87c6ab1..6668e4bf0 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -50,13 +50,6 @@ def test_add_repository(self): 'https://api.github.com/teams/10/repos/name-of-repo' ) - def test_add_repository_requires_auth(self): - """Show that one must be authenticated to add a repo to an org.""" - self.session.has_auth.return_value = False - - with pytest.raises(GitHubError): - self.instance.add_repository('foo', 10) - def test_create_repository(self): """Show that one can create a repository in an organization.""" self.instance.create_repository('repo-name', 'description', team_id=1) @@ -137,6 +130,11 @@ def test_add_member_requires_auth(self): with pytest.raises(GitHubError): self.instance.add_member('user', 10) + def test_add_repository_requires_auth(self): + """Show that one must be authenticated to add a repo to an org.""" + with pytest.raises(GitHubError): + self.instance.add_repository('foo', 10) + class TestOrganizationIterator(UnitIteratorHelper): described_class = Organization From 31f06700b3c0109e9661e555234888a8006a0e20 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 17:18:18 -0500 Subject: [PATCH 203/972] Move last of requires_auth tests --- tests/unit/test_orgs.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 6668e4bf0..993702453 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -70,13 +70,6 @@ def test_create_repository(self): } ) - def test_create_repository_requires_auth(self): - """Show that one must be authenticated to create a repo for an org.""" - self.session.has_auth.return_value = False - - with pytest.raises(GitHubError): - self.instance.create_repository('foo') - def test_remove_repository(self): """Show that one can remove a repository from a team.""" self.instance.remove_repository('repo-name', 10) @@ -91,13 +84,6 @@ def test_remove_repository_requires_positive_team_id(self): assert self.session.delete.called is False - def test_remove_repository_requires_auth(self): - """Show that a user must be authenticated to remove a repository.""" - self.session.has_auth.return_value = False - - with pytest.raises(GitHubError): - self.instance.remove_repository('repo-name', 10) - class TestOrganizationRequiresAuth(UnitHelper): described_class = Organization @@ -122,7 +108,7 @@ class TestOrganizationRequiresAuth(UnitHelper): def setUp(self): """Set MockedSession#has_auth.return_value to False.""" - super(TestOrganizationIterator, self).setUp() + super(TestOrganizationRequiresAuth, self).setUp() self.session.has_auth.return_value = False def test_add_member_requires_auth(self): @@ -135,6 +121,16 @@ def test_add_repository_requires_auth(self): with pytest.raises(GitHubError): self.instance.add_repository('foo', 10) + def test_create_repository_requires_auth(self): + """Show that one must be authenticated to create a repo for an org.""" + with pytest.raises(GitHubError): + self.instance.create_repository('foo') + + def test_remove_repository_requires_auth(self): + """Show that a user must be authenticated to remove a repository.""" + with pytest.raises(GitHubError): + self.instance.remove_repository('repo-name', 10) + class TestOrganizationIterator(UnitIteratorHelper): described_class = Organization From 0a65c471c327988a7fbfcd57666c2110ef66f62c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 17:19:54 -0500 Subject: [PATCH 204/972] Department of redundancy department --- tests/unit/test_orgs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 993702453..c20060030 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -111,22 +111,22 @@ def setUp(self): super(TestOrganizationRequiresAuth, self).setUp() self.session.has_auth.return_value = False - def test_add_member_requires_auth(self): + def test_add_member(self): """Show that one must be authenticated to add a member to an org.""" with pytest.raises(GitHubError): self.instance.add_member('user', 10) - def test_add_repository_requires_auth(self): + def test_add_repository(self): """Show that one must be authenticated to add a repo to an org.""" with pytest.raises(GitHubError): self.instance.add_repository('foo', 10) - def test_create_repository_requires_auth(self): + def test_create_repository(self): """Show that one must be authenticated to create a repo for an org.""" with pytest.raises(GitHubError): self.instance.create_repository('foo') - def test_remove_repository_requires_auth(self): + def test_remove_repository(self): """Show that a user must be authenticated to remove a repository.""" with pytest.raises(GitHubError): self.instance.remove_repository('repo-name', 10) From 898e2465769cfd222cb06cd2fb7ebade10255062 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 17:21:21 -0500 Subject: [PATCH 205/972] Test that Organization#conceal_member requires auth --- tests/unit/test_orgs.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index c20060030..088cd64e8 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -121,6 +121,11 @@ def test_add_repository(self): with pytest.raises(GitHubError): self.instance.add_repository('foo', 10) + def test_conceal_member(self): + """Show that one must be authenticated to conceal a member.""" + with pytest.raises(GitHubError): + self.instance.conceal_member('user') + def test_create_repository(self): """Show that one must be authenticated to create a repo for an org.""" with pytest.raises(GitHubError): From 6693db04dcc666fdd0f72a943da0d05b5c951da1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 17:27:53 -0500 Subject: [PATCH 206/972] Finish migrating Organization#conceal_member unit test --- tests/test_orgs.py | 11 ----------- tests/unit/test_orgs.py | 8 ++++++++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 52d85fe39..fbf816bb1 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -41,17 +41,6 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_conceal_member(self): - self.response('', 204) - self.delete(self.api + '/public_members/user') - - self.assertRaises(github3.GitHubError, self.org.conceal_member, None) - - self.not_called() - self.login() - assert self.org.conceal_member('user') - self.mock_assertions() - def test_create_team(self): self.response('team', 201) self.post(self.api + '/teams') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 088cd64e8..09cb156b4 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -50,6 +50,14 @@ def test_add_repository(self): 'https://api.github.com/teams/10/repos/name-of-repo' ) + def test_conceal_member(self): + """Show that one can conceal an organization member.""" + self.instance.conceal_member('concealed') + + self.session.delete.assert_called_once_with( + url_for('public_members/concealed') + ) + def test_create_repository(self): """Show that one can create a repository in an organization.""" self.instance.create_repository('repo-name', 'description', team_id=1) From 7aea86a20043977f4ec8e68a017a70ca8d186bdb Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 17:50:33 -0500 Subject: [PATCH 207/972] Migrate Organization#create_team unit tests --- tests/test_orgs.py | 19 ------------------- tests/unit/test_orgs.py | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index fbf816bb1..c673927dd 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -41,25 +41,6 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_create_team(self): - self.response('team', 201) - self.post(self.api + '/teams') - self.conf = { - 'data': { - 'name': 'team', - 'repo_names': [], - 'permission': 'push' - } - } - - self.assertRaises(github3.GitHubError, self.org.create_team, None) - - self.not_called() - self.login() - assert isinstance(self.org.create_team('team', permission='push'), - github3.orgs.Team) - self.mock_assertions() - def test_edit(self): self.response('org', 200) self.patch(self.api) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 09cb156b4..8c323da06 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -78,6 +78,19 @@ def test_create_repository(self): } ) + def test_create_team(self): + """Show that one can create a team in an organization.""" + self.instance.create_team('team-name', permission='push') + + self.post_called_with( + url_for('teams'), + data={ + 'name': 'team-name', + 'repo_names': [], + 'permission': 'push' + } + ) + def test_remove_repository(self): """Show that one can remove a repository from a team.""" self.instance.remove_repository('repo-name', 10) @@ -139,6 +152,11 @@ def test_create_repository(self): with pytest.raises(GitHubError): self.instance.create_repository('foo') + def test_create_team(self): + """Show that one must be authenticated to create a team for an org.""" + with pytest.raises(GitHubError): + self.instance.create_team('foo') + def test_remove_repository(self): """Show that a user must be authenticated to remove a repository.""" with pytest.raises(GitHubError): From ccb9174d3af8ee089795a834879643d220d6c2f9 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 18:16:40 -0500 Subject: [PATCH 208/972] Migrate Organization#edit unit test --- tests/test_orgs.py | 25 ------------------------- tests/unit/test_orgs.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index c673927dd..b320a485a 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -32,37 +32,12 @@ def setUp(self): super(TestOrganization, self).setUp() self.org = github3.orgs.Organization(self.org.to_json(), self.g) - def test_repr(self): - assert repr(self.org).startswith(' Date: Wed, 23 Jul 2014 18:16:52 -0500 Subject: [PATCH 209/972] Test Organization#__repr__ --- tests/unit/test_orgs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 47b4f24ff..1febcf498 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -113,6 +113,9 @@ def test_remove_repository(self): 'https://api.github.com/teams/10/repos/repo-name' ) + def test_repr(self): + assert 'github' in repr(self.instance) + def test_remove_repository_requires_positive_team_id(self): """Show that remove_repository requires a team_id greater than 0.""" assert self.instance.remove_repository('name', -1) is False From 5e2d241b86b30cc6e4b4b88960ad1412e658d997 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 18:57:44 -0500 Subject: [PATCH 210/972] Migrate Organization#is_member unit test --- tests/test_orgs.py | 7 ------- tests/unit/test_orgs.py | 6 ++++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index b320a485a..650c84b76 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -38,13 +38,6 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_is_member(self): - self.response('', 404) - self.get(self.api + '/members/user') - - assert self.org.is_member('user') is False - self.mock_assertions() - def test_is_public_member(self): self.response('', 204) self.get(self.api + '/public_members/user') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 1febcf498..9b2da7f3f 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -105,6 +105,12 @@ def test_edit(self): } ) + def test_is_member(self): + """Show that a user can if another user is an organization member.""" + self.instance.is_member('username') + + self.session.get.assert_called_once_with(url_for('members/username')) + def test_remove_repository(self): """Show that one can remove a repository from a team.""" self.instance.remove_repository('repo-name', 10) From 20232054e9a9d1201cafbc720aaa45352c40fad5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 19:02:09 -0500 Subject: [PATCH 211/972] Migrate Organization#is_public_member unit test --- tests/test_orgs.py | 7 ------- tests/unit/test_orgs.py | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index 650c84b76..eb7c00010 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -38,13 +38,6 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_is_public_member(self): - self.response('', 204) - self.get(self.api + '/public_members/user') - - assert self.org.is_public_member('user') is True - self.mock_assertions() - def test_publicize_member(self): self.response('', 204) self.put(self.api + '/public_members/user') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 9b2da7f3f..07a016fa7 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -111,6 +111,14 @@ def test_is_member(self): self.session.get.assert_called_once_with(url_for('members/username')) + def test_is_public_member(self): + """Show that a user can if another user is a public org member.""" + self.instance.is_public_member('username') + + self.session.get.assert_called_once_with( + url_for('public_members/username') + ) + def test_remove_repository(self): """Show that one can remove a repository from a team.""" self.instance.remove_repository('repo-name', 10) From 3e60ba050971367061978530853fb3870d8903e6 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 19:10:10 -0500 Subject: [PATCH 212/972] Migrate Organization#publicize_member unit test --- tests/test_orgs.py | 11 ----------- tests/unit/test_orgs.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index eb7c00010..f093859c0 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -38,17 +38,6 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_publicize_member(self): - self.response('', 204) - self.put(self.api + '/public_members/user') - self.conf = {} - - self.assertRaises(github3.GitHubError, self.org.publicize_member, None) - - self.login() - assert self.org.publicize_member('user') - self.mock_assertions() - def test_remove_member(self): self.response('', 404) self.delete(self.api + '/members/user') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 07a016fa7..1da431b18 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -119,6 +119,14 @@ def test_is_public_member(self): url_for('public_members/username') ) + def test_publicize_member(self): + """Show that a user can publicize their own membership.""" + self.instance.publicize_member('username') + + self.session.put.assert_called_once_with( + url_for('public_members/username') + ) + def test_remove_repository(self): """Show that one can remove a repository from a team.""" self.instance.remove_repository('repo-name', 10) @@ -193,6 +201,11 @@ def test_edit(self): with pytest.raises(GitHubError): self.instance.edit('foo') + def test_publicize_member(self): + """Show that a user must be authenticated to publicize membership.""" + with pytest.raises(GitHubError): + self.instance.publicize_member('foo') + def test_remove_repository(self): """Show that a user must be authenticated to remove a repository.""" with pytest.raises(GitHubError): From d9ce08f2991c0d70e34df7047cc210cc92a81253 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 19:10:17 -0500 Subject: [PATCH 213/972] Fix docstring --- tests/unit/test_orgs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 1da431b18..e0fae1596 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -197,7 +197,7 @@ def test_create_team(self): self.instance.create_team('foo') def test_edit(self): - """Show that a user can edit an organization.""" + """Show that a user must be authenticated to edit an organization.""" with pytest.raises(GitHubError): self.instance.edit('foo') From 2b77c4f07a4527098791d49fadeaf9ad15d079d6 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 19:23:10 -0500 Subject: [PATCH 214/972] Migrate Organization#remove_member unit test --- tests/test_orgs.py | 11 ----------- tests/unit/test_orgs.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index f093859c0..d9455019c 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -38,17 +38,6 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_remove_member(self): - self.response('', 404) - self.delete(self.api + '/members/user') - - self.assertRaises(github3.GitHubError, self.org.remove_member, None) - - self.not_called() - self.login() - assert self.org.remove_member('user') is False - self.mock_assertions() - def test_team(self): self.response('team') self.get(self.github_url + 'teams/1') diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index e0fae1596..bbd9e1ef6 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -127,6 +127,14 @@ def test_publicize_member(self): url_for('public_members/username') ) + def test_remove_member(self): + """Show that one can remove a user from an organization.""" + self.instance.remove_member('username') + + self.session.delete.assert_called_once_with( + url_for('members/username') + ) + def test_remove_repository(self): """Show that one can remove a repository from a team.""" self.instance.remove_repository('repo-name', 10) @@ -206,6 +214,11 @@ def test_publicize_member(self): with pytest.raises(GitHubError): self.instance.publicize_member('foo') + def test_remove_member(self): + """Show that a user must be authenticated to remove a member.""" + with pytest.raises(GitHubError): + self.instance.remove_member('foo') + def test_remove_repository(self): """Show that a user must be authenticated to remove a repository.""" with pytest.raises(GitHubError): From 0562f3a1f7ae382421110cec85a4c8a9a85da27f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 19:23:40 -0500 Subject: [PATCH 215/972] Add missing docstring --- tests/unit/test_orgs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index bbd9e1ef6..af1c7ebb3 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -144,6 +144,7 @@ def test_remove_repository(self): ) def test_repr(self): + """Assert the Organization name is in the repr.""" assert 'github' in repr(self.instance) def test_remove_repository_requires_positive_team_id(self): From 2fe4a411ff585a21e8ad6bb4d2808c0df6861f3e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 19:27:07 -0500 Subject: [PATCH 216/972] Migrate Organization#team unit test --- tests/test_orgs.py | 13 ------------- tests/unit/test_orgs.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index d9455019c..d23ba5526 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -38,18 +38,5 @@ def test_set_type(self): o = github3.orgs.Organization(json) assert o.type == 'Organization' - def test_team(self): - self.response('team') - self.get(self.github_url + 'teams/1') - - self.assertRaises(github3.GitHubError, self.org.team, 0) - - self.login() - assert self.org.team(-1) is None - self.not_called() - - assert isinstance(self.org.team(1), github3.orgs.Team) - self.mock_assertions() - def test_equality(self): assert self.org == github3.orgs.Organization(load('org')) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index af1c7ebb3..390e9645b 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -153,6 +153,20 @@ def test_remove_repository_requires_positive_team_id(self): assert self.session.delete.called is False + def test_team(self): + """Show that a user can retrieve a team by id.""" + self.instance.team(10) + + self.session.get.assert_called_once_with( + 'https://api.github.com/teams/10' + ) + + def test_team_requires_positive_team_id(self): + """Show that team requires a team_id greater than 0.""" + self.instance.team(-1) + + assert self.session.get.called is False + class TestOrganizationRequiresAuth(UnitHelper): described_class = Organization @@ -225,6 +239,11 @@ def test_remove_repository(self): with pytest.raises(GitHubError): self.instance.remove_repository('repo-name', 10) + def test_team(self): + """Show that a user must be authenticated to retrieve a team.""" + with pytest.raises(GitHubError): + self.instance.team(10) + class TestOrganizationIterator(UnitIteratorHelper): described_class = Organization From ad7539bb5bbdf0a5d0f7d8074fce2a10d1694d12 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 19:28:42 -0500 Subject: [PATCH 217/972] Migrate equality unit test for Organizations --- tests/test_orgs.py | 3 --- tests/unit/test_orgs.py | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_orgs.py b/tests/test_orgs.py index d23ba5526..bdce7951b 100644 --- a/tests/test_orgs.py +++ b/tests/test_orgs.py @@ -37,6 +37,3 @@ def test_set_type(self): del json['type'] o = github3.orgs.Organization(json) assert o.type == 'Organization' - - def test_equality(self): - assert self.org == github3.orgs.Organization(load('org')) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 390e9645b..d77630f7c 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -105,6 +105,11 @@ def test_edit(self): } ) + def test_equality(self): + """Show that a user can compare teams.""" + team = self.create_instance_of_described_class() + assert team == self.instance + def test_is_member(self): """Show that a user can if another user is an organization member.""" self.instance.is_member('username') From 0540e08c0661707a17a48919e19f7025fdd5b3b0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 23 Jul 2014 19:29:00 -0500 Subject: [PATCH 218/972] Remove old Organization/Team test --- tests/test_orgs.py | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 tests/test_orgs.py diff --git a/tests/test_orgs.py b/tests/test_orgs.py deleted file mode 100644 index bdce7951b..000000000 --- a/tests/test_orgs.py +++ /dev/null @@ -1,39 +0,0 @@ -import github3 -from tests.utils import BaseCase, load - - -class TestTeam(BaseCase): - def __init__(self, methodName='runTest'): - super(TestTeam, self).__init__(methodName) - self.team = github3.orgs.Team(load('team')) - self.api = "https://api.github.com/teams/190009" - - def setUp(self): - super(TestTeam, self).setUp() - self.team = github3.orgs.Team(self.team.to_json(), self.g) - - def test_repr(self): - assert repr(self.team).startswith(' Date: Wed, 23 Jul 2014 19:44:10 -0500 Subject: [PATCH 219/972] Add unit test to unit/helper.py --- tests/unit/helper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index f7582b73f..1c91dc3ae 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -1,3 +1,4 @@ +"""Base classes and helpers for unit tests.""" try: from unittest import mock except ImportError: From c2016b9d9fab02dfe1e572c2390e7c96e5f0797a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 19:50:35 -0500 Subject: [PATCH 220/972] Rename the count variables to *_count --- github3/pulls.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/github3/pulls.py b/github3/pulls.py index a3e5e25b0..3eee90ef0 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -65,11 +65,11 @@ def __init__(self, pfile): #: Status of the file, e.g., 'added' self.status = pfile.get('status') #: Number of additions on this file - self.additions = pfile.get('additions') + self.additions_count = pfile.get('additions') #: Number of deletions on this file - self.deletions = pfile.get('deletions') + self.deletions_count = pfile.get('deletions') #: Number of changes made to this file - self.changes = pfile.get('changes') + self.changes_count = pfile.get('changes') #: URL to view the blob for this file self.blob_url = pfile.get('blob_url') #: URL to view the raw diff of this file @@ -108,18 +108,18 @@ def __init__(self, pull, session=None): #: Body of the pull request as plain text self.body_text = pull.get('body_text', '') #: Number of additions on this pull request - self.additions = pull.get('additions') + self.additions_count = pull.get('additions') #: Number of deletions on this pull request - self.deletions = pull.get('deletions') + self.deletions_count = pull.get('deletions') #: datetime object representing when the pull was closed self.closed_at = self._strptime(pull.get('closed_at')) #: Number of comments - self.comments = pull.get('comments') + self.comments_count = pull.get('comments') #: Comments url (not a template) self.comments_url = pull.get('comments_url') #: Number of commits - self.commits = pull.get('commits') + self.commits_count = pull.get('commits') #: GitHub.com url of commits in this pull request self.commits_url = pull.get('commits_url') #: datetime object representing when the pull was created From e436bf68f5e3913d35f496ea78bf938c580c1643 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 19:59:16 -0500 Subject: [PATCH 221/972] Update the HISTORY --- HISTORY.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index 04cf19580..4bca09d01 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -147,6 +147,22 @@ Old name New name - ``GitHub`` instances can no longer be used as context managers +- The pull request API has changed. To present a more consistent universal + API, certain attributes have been renamed. + +=============================== ========================== +Old name New attribute name +=============================== ========================== +``PullFile.additions`` ``additions_count`` +``PullFile.deletions`` ``deletions_count`` +``PullFile.changes`` ``changes_count`` +``PullRequest.additions`` ``additions_count`` +``PullRequest.comments`` ``comments_count`` +``PullRequest.commits`` ``commits_count`` +``PullRequest.deletions`` ``deletions_count`` +``PullRequest.review_comments`` ``review_comments_count`` +=============================== ========================== + 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ From 24111b0b3c8400b299bd98b9b6dd6361b5c94313 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 20:04:11 -0500 Subject: [PATCH 222/972] Update the history and the PullRequest.links attribute --- HISTORY.rst | 9 +++++++-- github3/pulls.py | 24 ++---------------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 4bca09d01..9219608b6 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -147,8 +147,13 @@ Old name New name - ``GitHub`` instances can no longer be used as context managers -- The pull request API has changed. To present a more consistent universal - API, certain attributes have been renamed. +- The pull request API has changed. + + - The ``links`` attribute now contains the raw ``_links`` attribute from the + API. + + - To present a more consistent universal API, certain attributes have been + renamed. =============================== ========================== Old name New attribute name diff --git a/github3/pulls.py b/github3/pulls.py index 3eee90ef0..0b242247f 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -137,28 +137,8 @@ def __init__(self, pull, session=None): #: Statuses URL self.statuses_url = pull.get('statuses_url') - # These are the links provided by the dictionary in the json called - # '_links'. It's structure is horrific, so to make this look a lot - # cleaner, I reconstructed what the links would be: - # - ``self`` is just the api url, e.g., - # https://api.github.com/repos/:user/:repo/pulls/:number - # - ``comments`` is just the api url for comments on the issue, e.g., - # https://api.github.com/repos/:user/:repo/issues/:number/comments - # - ``issue`` is the api url for the issue, e.g., - # https://api.github.com/repos/:user/:repo/issues/:number - # - ``html`` is just the html_url attribute - # - ``review_comments`` is just the api url for the pull, e.g., - # https://api.github.com/repos/:user/:repo/pulls/:number/comments - #: Dictionary of _links - self.links = { - 'self': self._api, - 'comments': '/'.join([self._api.replace('pulls', 'issues'), - 'comments']), - 'issue': self._api.replace('pulls', 'issues'), - 'html': self.html_url, - 'review_comments': self._api + '/comments' - } - + #: Dictionary of _links. Changed in 1.0 + self.links = pull.get('_links') #: datetime object representing when the pull was merged self.merged_at = self._strptime(pull.get('merged_at')) #: Whether the pull is deemed mergeable by GitHub From 8e623cd9fa192a2d9b439f43a5408c3f0cf7a898 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 20:42:21 -0500 Subject: [PATCH 223/972] Start working on PullRequest unit tests Rename iter_comments to review_comments --- github3/pulls.py | 4 +- tests/test_pulls.py | 2 +- tests/unit/pull_request_example | 246 ++++++++++++++++++++++++++++++++ tests/unit/test_pulls.py | 28 ++++ 4 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 tests/unit/pull_request_example create mode 100644 tests/unit/test_pulls.py diff --git a/github3/pulls.py b/github3/pulls.py index 0b242247f..7e854edbd 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -231,8 +231,8 @@ def is_merged(self): url = self._build_url('merge', base_url=self._api) return self._boolean(self._get(url), 204, 404) - def iter_comments(self, number=-1, etag=None): - """Iterate over the comments on this pull request. + def review_comments(self, number=-1, etag=None): + """Iterate over the review comments on this pull request. :param int number: (optional), number of comments to return. Default: -1 returns all available comments. diff --git a/tests/test_pulls.py b/tests/test_pulls.py index e934e23df..b8f9fa1f8 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -70,7 +70,7 @@ def test_iter_comments(self): self.response('review_comment', _iter=True) self.get(self.api + '/comments') - c = next(self.pull.iter_comments()) + c = next(self.pull.review_comments()) assert isinstance(c, github3.pulls.ReviewComment) self.mock_assertions() diff --git a/tests/unit/pull_request_example b/tests/unit/pull_request_example new file mode 100644 index 000000000..49d256eb1 --- /dev/null +++ b/tests/unit/pull_request_example @@ -0,0 +1,246 @@ +{ + "url": "https://api.github.com/repos/octocat/Hello-World/pulls/1", + "html_url": "https://github.com/octocat/Hello-World/pull/1", + "diff_url": "https://github.com/octocat/Hello-World/pulls/1.diff", + "patch_url": "https://github.com/octocat/Hello-World/pulls/1.patch", + "issue_url": "https://api.github.com/repos/octocat/Hello-World/issues/1", + "commits_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1/commits", + "review_comments_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1/comments", + "review_comment_url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/{number}", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/issues/1/comments", + "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "number": 1, + "state": "open", + "title": "new-feature", + "body": "Please pull these awesome changes", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:01:12Z", + "closed_at": "2011-01-26T19:01:12Z", + "merged_at": "2011-01-26T19:01:12Z", + "head": { + "label": "new-topic", + "ref": "new-topic", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "user": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 1296269, + "owner": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "description": "This your first repo!", + "private": false, + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "html_url": "https://github.com/octocat/Hello-World", + "clone_url": "https://github.com/octocat/Hello-World.git", + "git_url": "git://github.com/octocat/Hello-World.git", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "mirror_url": "git://git.example.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "has_issues": true, + "has_wiki": true, + "has_downloads": true, + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + } + } + }, + "base": { + "label": "master", + "ref": "master", + "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "user": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 1296269, + "owner": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "description": "This your first repo!", + "private": false, + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "html_url": "https://github.com/octocat/Hello-World", + "clone_url": "https://github.com/octocat/Hello-World.git", + "git_url": "git://github.com/octocat/Hello-World.git", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "mirror_url": "git://git.example.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "has_issues": true, + "has_wiki": true, + "has_downloads": true, + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + } + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1" + }, + "html": { + "href": "https://github.com/octocat/Hello-World/pull/1" + }, + "issue": { + "href": "https://api.github.com/repos/octocat/Hello-World/issues/1" + }, + "comments": { + "href": "https://api.github.com/repos/octocat/Hello-World/issues/1/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/{number}" + }, + "commits": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e" + } + }, + "user": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "merge_commit_sha": "e5bd3914e2e596debea16f433f57875b5b90bcd6", + "merged": false, + "mergeable": true, + "merged_by": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "comments": 10, + "commits": 3, + "additions": 100, + "deletions": 3, + "changed_files": 5 +} diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py new file mode 100644 index 000000000..8dfd2eb8a --- /dev/null +++ b/tests/unit/test_pulls.py @@ -0,0 +1,28 @@ +"""Unit tests for the github3.pulls module.""" +import json + +from .helper import UnitHelper, UnitIteratorHelper + +from github3.pulls import PullRequest + + +def get_pr_example_data(): + """Load the example data for the PullRequest object.""" + with open('./pull_request_example') as fd: + data = json.load(fd) + return data + + +class TestPullRequest(UnitHelper): + + """PullRequest unit tests.""" + + described_class = PullRequest + example_data = get_pr_example_data() + + +class TestPullRequestIterator(UnitIteratorHelper): + + """Test PullRequest methods that return Iterators.""" + + pass From c971af998d43437505e58a7bc3550d14c48c607e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 20:42:59 -0500 Subject: [PATCH 224/972] Update HISTORY --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index 9219608b6..e53bda8af 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -55,6 +55,7 @@ Old name New name ``Organization#iter_public_members`` ``Organization#public_members`` ``Organization#iter_repos`` ``Organization#repositories`` ``Organization#iter_teams`` ``Organization#teams`` +``PullRequest#iter_comments`` ``PullRequest#review_comments`` ``Team#iter_members`` ``Team#members`` ``Team#iter_repos`` ``Team#repositories`` From a50450dc23716530863aaa234f37ab8bd9935ee5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 20:54:20 -0500 Subject: [PATCH 225/972] Simplify test classes --- tests/unit/helper.py | 5 +++++ tests/unit/test_orgs.py | 3 +-- tests/unit/test_orgs_team.py | 3 +-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index 1c91dc3ae..862d9a564 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -108,6 +108,11 @@ def setUp(self): # we can assert things about the call that will be attempted to the # internet self.described_class._build_url = build_url + self.after_setup() + + def after_setup(self): + """No-op method to avoid people having to override setUp.""" + pass class UnitIteratorHelper(UnitHelper): diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index d77630f7c..36913a435 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -194,9 +194,8 @@ class TestOrganizationRequiresAuth(UnitHelper): 'type': 'Organization' } - def setUp(self): + def after_setup(self): """Set MockedSession#has_auth.return_value to False.""" - super(TestOrganizationRequiresAuth, self).setUp() self.session.has_auth.return_value = False def test_add_member(self): diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index 96047bcbb..57d040ae9 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -99,9 +99,8 @@ class TestTeamRequiresAuth(UnitHelper): } } - def setUp(self): + def after_setup(self): """Set up for test cases in TestTeamRequiresAuth.""" - super(TestTeamRequiresAuth, self).setUp() self.session.has_auth.return_value = False def test_add_member_requires_auth(self): From 48c89350b62131778fb84d258c8d78373a5787b7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 21:07:25 -0500 Subject: [PATCH 226/972] Get the full path to the example data --- tests/unit/test_pulls.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index 8dfd2eb8a..8c2284be4 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -1,5 +1,6 @@ """Unit tests for the github3.pulls module.""" import json +import os from .helper import UnitHelper, UnitIteratorHelper @@ -8,7 +9,9 @@ def get_pr_example_data(): """Load the example data for the PullRequest object.""" - with open('./pull_request_example') as fd: + directory = os.path.dirname(__file__) + example = os.path.join(directory, 'pull_request_example') + with open(example) as fd: data = json.load(fd) return data From 51f669223833b1429ba2598854273ffc475d6af0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 21:24:05 -0500 Subject: [PATCH 227/972] Create a helper function to generate url_for functions --- tests/unit/helper.py | 12 ++++++++++++ tests/unit/test_pulls.py | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index 862d9a564..e0cad6510 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -8,6 +8,18 @@ import unittest +def create_url_helper(base_url): + """A function to generate ``url_for`` helpers.""" + base_url = base_url.rstrip('/') + + def url_for(path=''): + if path: + path = '/' + path.strip('/') + return base_url + path + + return url_for + + def build_url(self, *args, **kwargs): """A function to proxy to the actual GitHubSession#build_url method.""" # We want to assert what is happening with the actual calls to the diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index 8c2284be4..678d6da09 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -2,7 +2,7 @@ import json import os -from .helper import UnitHelper, UnitIteratorHelper +from .helper import UnitHelper, UnitIteratorHelper, create_url_helper from github3.pulls import PullRequest @@ -16,6 +16,11 @@ def get_pr_example_data(): return data +url_for = create_url_helper( + 'https://api.github.com/repos/octocat/Hello-World/pulls/1' +) + + class TestPullRequest(UnitHelper): """PullRequest unit tests.""" From 7d2d606f886247ef476de16feda9f98df5d97c34 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 21:24:36 -0500 Subject: [PATCH 228/972] Rename PullRequest#iter_issue_comments to issue_comments --- github3/pulls.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/github3/pulls.py b/github3/pulls.py index 7e854edbd..a316c4975 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -267,7 +267,7 @@ def iter_files(self, number=-1, etag=None): url = self._build_url('files', base_url=self._api) return self._iter(int(number), url, PullFile, etag=etag) - def iter_issue_comments(self, number=-1, etag=None): + def issue_comments(self, number=-1, etag=None): """Iterate over the issue comments on this pull request. :param int number: (optional), number of comments to return. Default: @@ -276,7 +276,12 @@ def iter_issue_comments(self, number=-1, etag=None): endpoint :returns: generator of :class:`IssueComment `\ s """ - url = self._build_url(base_url=self.links['comments']) + comments = self.links.get('comments', {}) + url = comments.get('href') + if not url: + url = self._build_url( + 'comments', base_url=self._api.replace('pulls', 'issues') + ) return self._iter(int(number), url, IssueComment, etag=etag) @requires_auth From a6bf02479ff766c79e7be2f831b424e1798255b9 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 25 Jul 2014 21:24:54 -0500 Subject: [PATCH 229/972] Migrate PullRequest#issue_comments unit test --- tests/test_pulls.py | 11 ----------- tests/unit/test_pulls.py | 14 +++++++++++++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index b8f9fa1f8..ccdb75532 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -76,17 +76,6 @@ def test_iter_comments(self): assert repr(c).startswith(' Date: Fri, 25 Jul 2014 21:25:37 -0500 Subject: [PATCH 230/972] Add iter_issue_comments rename to HISTORY --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index e53bda8af..b4c6c0029 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -56,6 +56,7 @@ Old name New name ``Organization#iter_repos`` ``Organization#repositories`` ``Organization#iter_teams`` ``Organization#teams`` ``PullRequest#iter_comments`` ``PullRequest#review_comments`` +``PullRequest#iter_issue_comments`` ``PullRequest#issue_comments`` ``Team#iter_members`` ``Team#members`` ``Team#iter_repos`` ``Team#repositories`` From dacfd018e6fa1f18b6fa6f56a103a796b45798ad Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 26 Jul 2014 08:24:34 -0500 Subject: [PATCH 231/972] Migrate PullRequest#review_comments unit test --- tests/test_pulls.py | 10 ---------- tests/unit/test_pulls.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index ccdb75532..d238b8372 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -66,16 +66,6 @@ def test_is_merged(self): assert self.pull.is_merged() is False self.mock_assertions() - def test_iter_comments(self): - self.response('review_comment', _iter=True) - self.get(self.api + '/comments') - - c = next(self.pull.review_comments()) - assert isinstance(c, github3.pulls.ReviewComment) - self.mock_assertions() - - assert repr(c).startswith(' Date: Sat, 26 Jul 2014 08:59:14 -0500 Subject: [PATCH 232/972] Add integration test for PullRequest#issue_comments --- .../cassettes/PullRequest_issue_comments.json | 1 + tests/integration/test_pulls.py | 34 ++++--------------- 2 files changed, 8 insertions(+), 27 deletions(-) create mode 100644 tests/cassettes/PullRequest_issue_comments.json diff --git a/tests/cassettes/PullRequest_issue_comments.json b/tests/cassettes/PullRequest_issue_comments.json new file mode 100644 index 000000000..ea737c3ca --- /dev/null +++ b/tests/cassettes/PullRequest_issue_comments.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxCPm+zM5pdm9zmL3sJTJggtWAkW0SpVH/932NgUBWm4/2Sq2oQ1yPX5erTJVrj8fePtj4843vT72C5szbe0eu0yoMZuXFm3pJlWWH9gfFjzk9cVmpxZKMRolzwaS3r71MHHkBxnAoKGaaxXK+DeZTj56opvJQyQzjUq1LtSfEPlQzS60Uk5EoNCv0LBI5qYg1/gbUUbYAw/Qif7kNVut4u0t2ixVb7xb+Zhsy5se7gEbJBgY3E5W8ncSSMZMiN2pTnWc3+qyuxuRmcCKyTJxBuV3Ro4lIb2nc3FB4cfwiBZY1ETplcCyW9GkcxZV+XVRjVWN3lT7w2HAUdkuy+GVhrR1kmeD4rIlkpWiAVagiyUvNRfG6wJE1aEIeacE/6NdosFaAGGmvS2msYM1OCNTXza1ZTUrJTzS6GNdIFjF+grO/iLyxB1FfSpPTfyEojOu5Zgca5yZHE5op9jn1muk1BjUPpkjJZ6N/fAbErN9VTPjzolNRTDIeSiovk0TICUdCy4RGiNXJGWfMBOE6+cH1H1U4+f7zz1MAgRj33iu5m7mN80fJOJZjSA/25C4C6QkAJL2zixPH2NcEn20+RUh1GgpJtXh0aNwXOALVZPjVxJJmNHcS3gAASoVw82QDAIgrVbGnQvv+whuOIl3+FFUe2iPvmay5j7YEaKUK53zBmJMHe0hNulMZ6VBEqRu2Y9TE/tfsNj06STX2wISZCJ04eFGSBlITlVL7HtIHV3WGahgjqGSJs1TD6KFaOu53I9NAeiReghpb76SzY5C69WhGi2NFj27UHoJdN6/qI/14WMTcz50rBUhTvkkeVu6H3JVjlNraAfnu5tIr5gptCpL7Zc4DBwwKm8YFec4f1QX3iS1iFPb/A9bE6S3afH9cxjyWaxg1uZ7J9tBv6S7ebU/9Tiepr3O0vYJTSHQMUv9WUp2akwtTlVQyF9EtgtQhRbE1m83qlNGmrM6ZdMxgSwCKyihF1eiis+4YqHpyqptqPTEyY1TvmaCxk297CIB2G120WsIwxko0qU4CG8CQmPOMKS0KtzP2ShmyC6F5wqNnOpb76TYC1d8ULyI2pVk2RdRqHnHEMWpts4soOJmbhywBy8Adge1UMoaQdvK6ZJZRE9tpRpKhEYkPVKOBWMz9xds8ePODX/5uv9ruV8HfWElVxqMxy7f55m3RjFmu8GfGlJVKBxg7ZP3LD3AHsV/6ZghOwDYE8R/uH/CJO49/9feDlsLcGsBQqfRq+PvVbP8flyOtWZQhlm6C/vk5T7evpcemkJqKnJUoE9prln6VQXmZwdMx2q9YRGqGHpiYlfEPDN0uFsGoIIhEVWA//B0en6lG7YpX7/BhV0j0TZ+ZmqqDTVNvr2Vluko8uR4Dg4dn/s77js82bS19vcEpyaUU7WVRgSRFv1+yomX3Mta2cVTe3tgMRkA3futkt6uIWUKrTB9s8QzZMar+TJTQXTB9RtvXgQ1tWHF0y95+/gPaGeQFOhMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"6b92bcb3b829b57c62ff5818325c6477\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF7:54BE8A8:53D3B3EE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Sat, 26 Jul 2014 13:58:06 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406386686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-26T13:58:06"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"3451e43daad67c415492af752afa6c11\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF7:54BE8D0:53D3B3EE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 26 Jul 2014 13:54:30 GMT", "date": "Sat, 26 Jul 2014 13:58:06 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406386686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "recorded_at": "2014-07-26T13:58:06"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/issues/235/comments?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52U247bIBRFf8Wir0nwNRcrzcxHzLy0qSJsYxsVGwTYM6mVf++BeKIk04ucVzh7nc2Gw/cBdYqjFNXGSJ1iTCRbVMzUXbbIRYMVlUJjzaqG9Ex1OozxeTdayCNmWndUYyhsaGs0jsPAXybLAM2A1/DDLfoK+zeg7DjHYZR8ceSRO7/CuvU77iOWoQeYZAVKP+Az1GmqUDogLirWQiTXJsfiMPbXkT9DpCeGqHsfblGP8VlaLloDwbgkO3wWPwGqUiPAGkB5EK+jZFmsN+UmTOhyEwardUZpUGwikpcrEPzzjmyn2zualD8Ul4Jz8QaU+xPdPobPjfBFeaGwtnqQAsoBC1NTCBaOdLJBMW2mm3KqAR6qNgdWWI6Gi1G0mGxs1IGttxYcDW4eHLDLdK6YNEy00w3eqIEmVEVa9os8RgO1Bogb1ckndCpQ095O8GT5WTZgqVhP8qONRtGcsh7CfhB5pweiOUoKc/Jq5xOiZ4YeSNHYGS0J1/Q0Q7mixEBLYqAu9IN47idzP3oJ4jQO0nD1DXSdLP5bk4nieLBfF2C2cvdSk/an9rbEqxUtv+4vv+TVV5ZVjGdUmT3yck60hir7euf2R4THsUe754+SLSY7b4vlDty4Toa+W8Njm0vduP2HHQ+dfvwGvyTjhbMFAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"396695be68a5fa04374129eea1b3946e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF7:54BE956:53D3B3EE", "cache-control": "public, max-age=60, s-maxage=60", "date": "Sat, 26 Jul 2014 13:58:06 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406386686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/issues/235/comments?per_page=100"}, "recorded_at": "2014-07-26T13:58:06"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index 0179b9761..f2c8ca16c 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -17,31 +17,11 @@ def get_pull_request(self, repository='sigmavirus24/github3.py', num=235): assert isinstance(p, github3.pulls.PullRequest) return p - def test_create_review_comment(self): - """Show that a user can create an in-line reveiw comment on a PR.""" - self.basic_login() - cassette_name = self.cassette_name('create_review_comment') + def test_issue_comments(self): + """Show that one can iterate over a PRs issue comments.""" + cassette_name = self.cassette_name('issue_comments') with self.recorder.use_cassette(cassette_name): - p = self.get_pull_request(num=286) - comment = p.create_review_comment( - body='Testing review comments', - commit_id='4437428aefdb50913e2acabd0552bd13021dc38f', - path='github3/pulls.py', - position=6 - ) - assert isinstance(comment, github3.pulls.ReviewComment) - - -class TestReviewComment(IntegrationHelper): - - """Integration tests for the ReviewComment object.""" - - def test_reply(self): - """Show that a user can reply to an existing ReviewComment.""" - self.basic_login() - cassette_name = self.cassette_name('reply') - with self.recorder.use_cassette(cassette_name): - p = self.gh.pull_request('sigmavirus24', 'github3.py', 286) - c = next(p.review_comments()) - comment = c.reply('Replying to comments is fun.') - assert isinstance(comment, github3.pulls.ReviewComment) + p = self.get_pull_request() + for comment in p.issue_comments(): + assert isinstance(comment, + github3.issues.comment.IssueComment) From af85241190d197e4b78b484c87d78d29f90b9693 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 26 Jul 2014 09:01:13 -0500 Subject: [PATCH 233/972] Add integration test for PullRequest#review_comments --- tests/cassettes/PullRequest_review_comments.json | 1 + tests/integration/test_pulls.py | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/cassettes/PullRequest_review_comments.json diff --git a/tests/cassettes/PullRequest_review_comments.json b/tests/cassettes/PullRequest_review_comments.json new file mode 100644 index 000000000..c61b7bc3e --- /dev/null +++ b/tests/cassettes/PullRequest_review_comments.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxCPm+zM5pdm9zmL3sJTJggtWAkW0SpVH/932NgUBWm4/2Sq2oQ1yPX5erTJVrj8fePtj4843vT72C5szbe0eu0yoMZuXFm3pJlWWH9gfFjzk9cVmpxZKMRolzwaS3r71MHHkBxnAoKGaaxXK+DeZTj56opvJQyQzjUq1LtSfEPlQzS60Uk5EoNCv0LBI5qYg1/gbUUbYAw/Qif7kNVut4u0t2ixVb7xb+Zhsy5se7gEbJBgY3E5W8ncSSMZMiN2pTnWc3+qyuxuRmcCKyTJxBuV3Ro4lIb2nc3FB4cfwiBZY1ETplcCyW9GkcxZV+XVRjVWN3lT7w2HAUdkuy+GVhrR1kmeD4rIlkpWiAVagiyUvNRfG6wJE1aEIeacE/6NdosFaAGGmvS2msYM1OCNTXza1ZTUrJTzS6GNdIFjF+grO/iLyxB1FfSpPTfyEojOu5Zgca5yZHE5op9jn1muk1BjUPpkjJZ6N/fAbErN9VTPjzolNRTDIeSiovk0TICUdCy4RGiNXJGWfMBOE6+cH1H1U4+f7zz1MAgRj33iu5m7mN80fJOJZjSA/25C4C6QkAJL2zixPH2NcEn20+RUh1GgpJtXh0aNwXOALVZPjVxJJmNHcS3gAASoVw82QDAIgrVbGnQvv+whuOIl3+FFUe2iPvmay5j7YEaKUK53zBmJMHe0hNulMZ6VBEqRu2Y9TE/tfsNj06STX2wISZCJ04eFGSBlITlVL7HtIHV3WGahgjqGSJs1TD6KFaOu53I9NAeiReghpb76SzY5C69WhGi2NFj27UHoJdN6/qI/14WMTcz50rBUhTvkkeVu6H3JVjlNraAfnu5tIr5gptCpL7Zc4DBwwKm8YFec4f1QX3iS1iFPb/A9bE6S3afH9cxjyWaxg1uZ7J9tBv6S7ebU/9Tiepr3O0vYJTSHQMUv9WUp2akwtTlVQyF9EtgtQhRbE1m83qlNGmrM6ZdMxgSwCKyihF1eiis+4YqHpyqptqPTEyY1TvmaCxk297CIB2G120WsIwxko0qU4CG8CQmPOMKS0KtzP2ShmyC6F5wqNnOpb76TYC1d8ULyI2pVk2RdRqHnHEMWpts4soOJmbhywBy8Adge1UMoaQdvK6ZJZRE9tpRpKhEYkPVKOBWMz9xds8ePODX/5uv9ruV8HfWElVxqMxy7f55m3RjFmu8GfGlJVKBxg7ZP3LD3AHsV/6ZghOwDYE8R/uH/CJO49/9feDlsLcGsBQqfRq+PvVbP8flyOtWZQhlm6C/vk5T7evpcemkJqKnJUoE9prln6VQXmZwdMx2q9YRGqGHpiYlfEPDN0uFsGoIIhEVWA//B0en6lG7YpX7/BhV0j0TZ+ZmqqDTVNvr2Vluko8uR4Dg4dn/s77js82bS19vcEpyaUU7WVRgSRFv1+yomX3Mta2cVTe3tgMRkA3futkt6uIWUKrTB9s8QzZMar+TJTQXTB9RtvXgQ1tWHF0y95+/gPaGeQFOhMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"6b92bcb3b829b57c62ff5818325c6477\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF6:40E1FFE:53D3B494", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Sat, 26 Jul 2014 14:00:52 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406386686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-26T14:00:52"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1aW2/ruBH+K4KfWtSxLMl3HJzteeoFRbtosy+LBRxKomwisqRKlLM5Qv57vyElW1J87Ng0+hTACWyJ83E4wxlyLtWgzOPBarCVMitWts0yMdoIuS39UZDu7JxnaWEXYrNje5GXhTux9VtvlL3aWRnHhe1608FwIMLByplO3PF0shwCbhevu8gt1HN4NVwoouh2gBGRg6mMyWBrAKPoaXFFUfIezlWSUgCNqJJy5/N8sILghoNCMsmhgCBOCx5iLilkTA++haH1bx5zVvARKwouC4tJmQu/xPjhoCwIohrE6UYkGO5vRAxUWavCmznefDIcsD2TLO+zrh4WtaIJKUgTyROpdF7amvgnQG3yGoDUO5iNndkknLtLn0VsESwc7s29KHDD8ZhH/jIgts7tJpqpsFucnt8mrYFRGsfpC6j7K+lu1+4E9oEKjOnvItncgACqyk7llkOQWMIbCUYU8jpmFEUF8ynkWoSEAdXnOQ+vYqimATsvCTiplIUqsNIvglxkUqTJdYx1KIGU5huWiO/seiRQFgBQTuOqVSkKUPI9NuF1pJqksrNc7FnwSqLIecDFHoK9Aa5HCzT5mpE5/kL2BjELydcs3JHNRSwu+Ntw4KfhK0Y8brn19//8659WyEkTPnaNxaxcm7AlkiAu8caCiWUxlxxPojTfKTFb+AgycGXnI8si43/qWv/T0fytF3hoYMfYS1YaWU/fiO6JCB+3orDwCbacZTy3MIWFjWuxLItFoCeTW5ZYO/asGSx4xnL4IHD6X/goae0FO86N5eZrzdYf/vg0+i3/LaG/f3C25z8ahZVZWcwCPqRvARyYVaQ7nibc2jIs0oIRKcaEHFpwZ9YOWicpvFsxyEksYRqUNEaxP4IWgpyD43DNJOTujp3Jw3j6MHYfx7OVM8bnV4wps7A/Zv7gzh4dbzWdrDw1RjvdHoz36ExWEwfumYbseL55N9OJIWvodSfkutgy8LRgkReF7iIKuBf4i3DhTnwvmLsTN5x7wWTuzsNZ4HsLTADhik3CsccSHKeYUMTQAoTVPNDAF6zigwe1XYMpK9kL/qLYvmx018AT2jv88+7gI/ANo3alz0+y9HswfzyalXBq7ulYxjY1knqDYU9n48BZOtMpCxYeh9rnjhf601mAz5xxxhzXDaYu7QaYLU5aHOvM53Qva87AVe1HHrQtPtBVQAk5wqDT7/ROvGLuzyvFiRvw55Xi80rx/79SkEPU/p/uFzhB2z6hHT6tQlxy4jQ7+ILjb23/cx54obfENX28cF3XdzgPF8to5rgzb7JwfOZNZ8vFhCKPvv2358FrCgHcyXjhjW8MKzTx+7AicCYLcEFsLd0pny1dZ77wOXfCpceCaE6sXQ4retyeDy16g68KLzrR680hxgkUkzCjF1IbhBodpPuFG13YdrAC9V4dcnTQrg07OsTXhx4d8vuEHz2OOuELxHM5BNH+olI26s2d8dxxhoOE7ShyOSZsABXhjrmuX/T2DCV9KK1D+qDgsp1daA/9dAWUJFGpjI4EP13BBzMPn67gZK71xJa6JRuhEiGUUlTpiRtTsbBxncVQlz84kZ9f5RYReiz8nOWvOnpHyjCPWEBpBJWQoDzDX4T8a+lb337+294jd5PmzwdOzh7iZ0PAGskoGiNWKC595q9GOERf2fhfZ/ECpCaZnyKFkl5KT55dI6LPFlDV+UmxruRsZ8S4AgDQNk2fjYAUAJ0CKiv+kSTb+YXXEXhzlB7De3NojQBemyyL0cIPIJXy/6QVmEOCXJsRbINR2fqb0jbbGGESPbEXp74RDi4PtgKpbMQTOvMt16bcESphdECRyzBmlTAOoDLnZopRbBLIAfKuaaGqlmjMkk3JNma8HkCgdbq1b9j3i+WS82Z5RAEkFYhU7cnYyR1xiFMdCKBwZaT6FswRVB1dJnnHdmFEiYASvEZ81hCdbX8HWNqnfeh7pEYbjMo++mTt9Os3JtKtvX4zRzetq6qRhqLWGHb1J1Rxt3W2GKUOozouuCUIu6KczNtoNKooYUvgqk5gxLFGABTLgy3qVybCrRoMXWJSdcKI2AwR2sUpC404PYAAUKvRhFeN0N5jqq/ABFIBtBEPRRUj2CNKGztJpYjq2poRfAeo+qlAyZAPGWpC2HJSBAL7GHdt0qKqDhjNpRGwDOQICLEuIRhhNhiVrevb/Sqd+zD2HhzUzpar6WI1VeW101U6NWYyxYfGZGWx7ZbgmkKeS4U6GgIPWO8XfEMbC/43LSw/yHJQ8wMIi6LpD8HvPx/JVufJUDhM+gb68Tn3/WPpMilY3aKGmuGagGiMunUOq/Sy1xHqoSHCLxRKixHSYTatTHzHUOR8vc6FIEjLBFVTZ4nHL9TeQkdv+2FzkTgEfTQ1K9baTAcrmZcUVeLJ0Q20Hr6IZ3GI+FTM1aDP5lTczPO0bkfR5c4040mNfWBjpgPHYrAimtYI8I13Ddv1KkIesTKWa315BttNCvwNufN1LBIEK6ioFTxGrawabHXNzLDhCdCUYT4BeFmXqm9K9TkBRYn1BMyt7UWAbI7U+6EeK6OA7xWOTWc5NJGdmeQ+c7y/atTCwq3uPjNAp81FjHTbRAum4NcXkmnrU1vKWm/SwZfs673bU74Eaci/dntUvmD1ePjjThVNpNpV6rF3bFrpctTpXKknG32xs6/oYEkgD93Ccpnm5m6WcwI62dhCzMHZKr1J/jv1ttxbaV11/VhPSkN3VE0zb0cpI9KEVsPJ9zdLvrfKk8KGoHVrT3OiqV/Mp97LuhGnebAm+6Njt0yeE9yfD6RrH31fxxbMzyJJ79A6kdH+LJJ8FkmoDdasXdO4Xnq8IqFO+u5Cg6sxDVDXAhfxeBgK1QyLC+eCCiNo39Q/0QkRoJmSGgQjatvD8Lf/AYasQqRSLwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"3451e43daad67c415492af752afa6c11\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "55", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF6:40E2041:53D3B494", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 26 Jul 2014 13:54:30 GMT", "date": "Sat, 26 Jul 2014 14:00:52 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406386686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "recorded_at": "2014-07-26T14:00:52"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235/comments?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1ZbW/bNhD+K4T2YS0qW+9vRtp1wICtwDAMW4oBqweFok42UVnSSMptZuS/7yjJjuI6aZy6HTokCWBL5D13PN4dH17ebIxWlMbMWCrVyJll0YZPF1wt22zK6pUloKmlJfliRddctNL1rX7UmzaXVtOWpbRw3goqJS3Hdf0wij3DNHhuzLaPppHzokiXbfUWFb18SSaO7ZsReebYoZkQfJFDQSDn6omEsjCJoou0oit4/ktdgX4UC1CpVsMVl8vh9WhGVueX/dt5RbY/AlQrKiJbxkDKoi1xbBjW+rgCkVIpQclBbdWuMhDPJ45JAE3oAJ/O5tVkizg39O8rFKQKSL0GQdQSSA9C6JrykmYlkKLWA1wSASVQCdN59eyTMQg5R10S3YLubahaoi+HrRh2aautudQzaonOqitjVuEmmUYt+IJXtEyvBxzfNHqnpnq7jCC0mZM4QUBZ7EHmxZHj5VkQMvyLKFCKG8oCN0b0HdpY3o9YRhMvcaIgz8LCD2zwQ+YGbpTkXhZ7LI7zIvEzlG8lCGO2McoajULV4wAbosf17dizTQPdigGQ7kVp91IOkarRWF0pDMIuaFurF/4OoRZiAOiWyBw/9oIwj5MicQMIE9eJ4gzAyROPsiLSpt2VDlrTzXRAiaValXv2jTJob2lFXZb1O0TZX9HNvPtQkbWTRJX9d14tHoiCkhurxuBFx+KSrrSjuFTHG9VJbbAmSIVBpHEkboyA/GjDBjk0612FFm26oO4A20wywRsdzccbeEMa0WqxoBX/hz4MDaUlgnRV8egVdlIoDWtdLY8W78U2ViP4mrJL7RoBDPganf1AyD15RFSXDWCevNb5ia7HIpnSfKVztKClhCvT0LUWZ/wM6ltd4LAIqq4KsiWtFkBU3Ze+vGYTqQQG2nRXuEh+iUWbM4KlsREg0Q2krsjFjxg9F5K8w2OHUHJR8BLkBaFVTi66Kj28aCgXU7SKCcD6m6dUoR2u7fgTO5jY7rlrz9xk5od/4py2yQ/M8c5tf2aHM8/Xc+6ft/tnnuV6wTc5l6yVEqMyFaOTT5+JqYC/W8CUuLOY3OdsRUVoaVry6q3UBVMfkPpzKQA/T3tq4+ZqlxyAv6Wc3d8tCD32ywEVD+Ad2jdXQ0SmveXGWfPihJF5xuocXujwPEOWg193QdqPdIE5DHXx2r++DtrtWBe6Z1bzAjdTJ1Cq4L2O3hPaqq3cmdcZ1ll0bQvp8+fKPDnli70Q17WjfPh4gPIFZoiMLzCdWDM+ViJrIueYI7/1HOnJ64qrn6BsQGjO1dEleE9XTQkppjIlz8lmRO7m+pyeG7MtxerK6ZO5YTlz46l5Y+I2zfXs+S5jRiFdM1UzqizUXtaTP2pR5nj4dMxNWmtnak/tuYGYIw7XUz6N+GaDSx/omMLlSKvFhVj6K1YBfUzcQsuQfB3gZI+U7JGSPVKyWw+2A7T4kZJtKdnvA/WiTQN4OdJULMPbKZZIppkWzfGGjWylp2hAvv/1lSZuleZnFOlFd23FOsiWSNo6EvcRsuU5M9v9r8hWf+Z8nWRL2/6ZyNYA/cXI1ulj7gBLOr0SdP+JWVDgB4HujAwsqHs8wIIeG19HN8/+142vbMFLbDqqIXK80PEi5IAPanr1wh82vULbCf08cpOMFjRmsQNe5BXMzW0biixh+rr88abXyNK7L86jiUc1u7ZyD2907SF8SpNrB/VJDa4dyumaW9eQ47YYbuHRja0d0rEMaid4fENrJ3qaZtbIkhuNMHTHvRtZP2CX/3ai03eMopn/UaKznXN3ctz1n5RDXaXtsfI1Ep3e9s9CdHbQX4zodGFygJv04XP117/kWBFpSRsAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"cce8195ada4ef54c0fd310451406d058\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "54", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF6:40E2062:53D3B494", "cache-control": "public, max-age=60, s-maxage=60", "date": "Sat, 26 Jul 2014 14:00:52 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406386686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235/comments?per_page=100"}, "recorded_at": "2014-07-26T14:00:52"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index f2c8ca16c..ecec9801a 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -18,10 +18,18 @@ def get_pull_request(self, repository='sigmavirus24/github3.py', num=235): return p def test_issue_comments(self): - """Show that one can iterate over a PRs issue comments.""" + """Show that one can iterate over a PR's issue comments.""" cassette_name = self.cassette_name('issue_comments') with self.recorder.use_cassette(cassette_name): p = self.get_pull_request() for comment in p.issue_comments(): assert isinstance(comment, github3.issues.comment.IssueComment) + + def test_review_comments(self): + """Show that one can iterate over a PR's review comments.""" + cassette_name = self.cassette_name('review_comments') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request() + for comment in p.review_comments(): + assert isinstance(comment, github3.pulls.ReviewComment) From 0d7bd0ca6e715dd77cb5c0481fa8f1d11f890b98 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 26 Jul 2014 16:40:42 -0500 Subject: [PATCH 234/972] Use helper factory --- tests/unit/test_orgs.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/unit/test_orgs.py b/tests/unit/test_orgs.py index 36913a435..2a339903d 100644 --- a/tests/unit/test_orgs.py +++ b/tests/unit/test_orgs.py @@ -3,14 +3,9 @@ from github3 import GitHubError from github3.orgs import Organization -from .helper import UnitHelper, UnitIteratorHelper +from .helper import UnitHelper, UnitIteratorHelper, create_url_helper - -def url_for(path=''): - """Simple function to generate URLs with the base Org URL.""" - if path: - path = '/' + path.strip('/') - return 'https://api.github.com/orgs/hapy' + path +url_for = create_url_helper('https://api.github.com/orgs/hapy') class TestOrganization(UnitHelper): From e9141946f370477054df5b077b962dcde13f503d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 26 Jul 2014 18:11:02 -0500 Subject: [PATCH 235/972] Use url_for factory in Team unit tests --- tests/unit/test_orgs_team.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/unit/test_orgs_team.py b/tests/unit/test_orgs_team.py index 57d040ae9..a7d005529 100644 --- a/tests/unit/test_orgs_team.py +++ b/tests/unit/test_orgs_team.py @@ -3,14 +3,9 @@ from github3 import GitHubError from github3.orgs import Team -from .helper import UnitHelper, UnitIteratorHelper +from .helper import UnitHelper, UnitIteratorHelper, create_url_helper - -def url_for(path=''): - """Simple function to generate URLs with the base Org URL.""" - if path: - path = '/' + path.strip('/') - return 'https://api.github.com/teams/10' + path +url_for = create_url_helper('https://api.github.com/teams/10') class TestTeam(UnitHelper): From f57f13d66fda873ee8aaeb2bc647abfafb95d07b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 26 Jul 2014 18:13:58 -0500 Subject: [PATCH 236/972] Rename PullRequest#iter_commits -> commits --- HISTORY.rst | 1 + github3/pulls.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index b4c6c0029..826eebc98 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -56,6 +56,7 @@ Old name New name ``Organization#iter_repos`` ``Organization#repositories`` ``Organization#iter_teams`` ``Organization#teams`` ``PullRequest#iter_comments`` ``PullRequest#review_comments`` +``PullRequest#iter_commits`` ``PullRequest#commits`` ``PullRequest#iter_issue_comments`` ``PullRequest#issue_comments`` ``Team#iter_members`` ``Team#members`` ``Team#iter_repos`` ``Team#repositories`` diff --git a/github3/pulls.py b/github3/pulls.py index a316c4975..e51ce2082 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -243,7 +243,7 @@ def review_comments(self, number=-1, etag=None): url = self._build_url('comments', base_url=self._api) return self._iter(int(number), url, ReviewComment, etag=etag) - def iter_commits(self, number=-1, etag=None): + def commits(self, number=-1, etag=None): """Iterates over the commits on this pull request. :param int number: (optional), number of commits to return. Default: From 4cd2f47d4610a6e93e7fcb0e64d8e938f015a9f1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 26 Jul 2014 18:14:36 -0500 Subject: [PATCH 237/972] Migrate PullRequest#commits unit test --- tests/test_pulls.py | 7 ------- tests/unit/test_pulls.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index d238b8372..8873d0856 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -66,13 +66,6 @@ def test_is_merged(self): assert self.pull.is_merged() is False self.mock_assertions() - def test_iter_comits(self): - self.response('commit', _iter=True) - self.get(self.api + '/commits') - - assert isinstance(next(self.pull.iter_commits()), github3.git.Commit) - self.mock_assertions() - def test_iter_files(self): self.response('pull_file', _iter=True) self.get(self.api + '/files') diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index 0a5a190af..0c78cd8cc 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -36,6 +36,17 @@ class TestPullRequestIterator(UnitIteratorHelper): described_class = PullRequest example_data = get_pr_example_data() + def test_commits(self): + """Show that a user can retrieve the commits in a Pull Request.""" + i = self.instance.commits() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('commits'), + params={'per_page': 100}, + headers={} + ) + def test_issue_comments(self): """Show that a user can retrieve the issue-like comments on a PR.""" i = self.instance.issue_comments() From 735ff9418454e554a44e8d5a1324885239838038 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 26 Jul 2014 18:16:03 -0500 Subject: [PATCH 238/972] Add integration test for PullRequest#commits --- tests/cassettes/PullRequest_commits.json | 1 + tests/integration/test_pulls.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/PullRequest_commits.json diff --git a/tests/cassettes/PullRequest_commits.json b/tests/cassettes/PullRequest_commits.json new file mode 100644 index 000000000..94cc1ff21 --- /dev/null +++ b/tests/cassettes/PullRequest_commits.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YQXOrNhDHv4qHax3LmCS2ubz21Pb2Dq+XXjwChNEEECMJe/yYfPf+JQEGd2onUWcynhhrf/prtSt21QU8C+JoG663YbgMalqxIA6OXBdtEq2aS7AM8rYsD/0Pih8reuKyVZtnMhslzjWTQdwFpTjyGozpUFDMNJvn9S5aLwN6oprKQytLjCu0blRMiHuoVo7aKiZTUWtW61UqKtISZ/wNqKPsAYYZpOHzLnp5zXb7fL95Ya/7TbjdJYyF2T6iab6Fwc1EDe8ncWTMpMiN2kJX5Y0+p8ua3AzORVmKMyi3K3o0ERktjZsthdfHL1Jg2RGhCwbHYknvxlFc6c+LslYddlfpA88MR2G3JMs+Lay3gywTHO8dkawRFtgmKpW80VzUnxc4swZNyCOt+U/6NRqsFSBG2uelWCtYsxMC9fPmzqwjjeQnml6MayRLGT/B2V9E3tiDqC+Nyem/EBTG9VyzA80qk6M5LRV7XwZ2eo1B9sESKfnR6J+fARkbdxUTfr/oQtSLkieSyssiF3LBkdAypylidXHGGbNAuC5+5/qPNln89v3PUwSBGPc2Krmbudb5s2ScyzGkB3tyF4H0BACS3tjFi2PsO4LPPp9SpDpNhKRaPDo07gucgToy/WpiSTNaeQm3AIAKIfw8aQEAcaVa9qHQvr9wy1FkyJ+6rRJ35H0ka+6jHQFaqcI5XzPm5cER0pHhVEY61Gnhhx0YHXH/2d2mRy+pxh6YpBSJFwcvSmIhHVEFde8hffBVZ6iGMYNKlntLNYwRqqXnfluZBjIi8RLU2HovnQODdL1HS1ofW3r0o44Q7Lp5VR/pz4dFzP3cuVKANOWb5Enrf8hdOUapqx2Q734uvWKuUFuQ3C9zHjhgUthYF1QVf1QX3Cf2iFnY/w9YE6e3aPP9cRnzWK5hdOR6JrtDv6f7eLc/9QedpLvO0fcKXiExMEj3S0N1YU4uTNVQyXxE9wjSJRTF1mq16gpGbVldMemZwY4AFJVpgarRR2c3MFD1VFTbaj03MjNU76WgmZdvRwiAbht9tDrCNMYaNKleAi1gSqx4yZQWtd8Ze6VM2bXQPOfpRzqW++k2A3XfFK9TtqRluUTUap5yxDFqbbOLKDiZn4ccAcvAHYHrVEqGkPbyumSO0RHXaaaSoRHJDlSjgdisw83TOnoKox/hPn7ZxS/R31hJ22SzMc9P6+3Txo55fsGfGdO0qphg3JDXH5soDsN4bYfgBOxDEP/h/gGfuPP4V38/aSnMrQEMlSquhr9ezeL/uBzpzdISsXQT9B+f83T7WnpsCqmFqFiDMqG/ZhlXGTWXFTydof3KRKpW6IGJWRn/iaG7zSaaFQSpaGvsR7jH4zPVqF3x6p0+HAqJsekzU1N1cGkaxFq2pqvEk+sxMHl45m987Phc09bTX7c4JbmUor8sqpGk6PcbVvfsUcaraxxVEBubyQjoxm+D7H4VGctpW+qDK54hO0PVX4oGumumz2j7BrChTSuOYdm7938Aa35eTjoTAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"fc047fe29b6386bec333103077d1c10b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF6:4968D4E:53D4369D", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Sat, 26 Jul 2014 23:15:42 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406420142"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-26T23:15:42"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e17a9348afa87a81a1386aa1c7d36b10\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF6:4968D65:53D4369E", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 26 Jul 2014 23:00:44 GMT", "date": "Sat, 26 Jul 2014 23:15:42 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406420142"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "recorded_at": "2014-07-26T23:15:42"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235/commits?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1ZS2/bRhD+KwueWsARl1w+dUnTS4GiaIHUvTQOhH0MxW35KncpwxX83zNLWrYlNIpoxblUAg8El/P6dmb2G+rD1jMl95ZelErBc5YHaaxEUkQxhSiRYRymuWIiYzLLVJFHwrvyZFvX2nrLrccHW7a9u2t4DajlR2j+4rVuyE+6EtBbfBtqritcEuvp0Q/SLGQ9LEANuKq4dXIhDaI3NH5Dw2uaLGm2DKI/vfudKQuvaaMGY/jaefFOKfIeKuAGFtwYsIZwa3stBgs3zU1zXQL5+ffffiUKjMTHulkTTvpJguhGVgOuEMSnq8ACPinavuZWtw3BS1tz00x6F4QcM0ZutS1RdaWNJW1B3o3OoNB1qQ3RqEaWwDvoCRogFt3iXVdpOZmyJW9Izf+e3DPQ8R5RRj//GQD1bTS/aXZhasR2Nfn03fcLF+QvwDfwCMPeOgZEuopLuHJ3EmEipq2hbYCUHLEiAz5xHml7ddMgaqSGZoz+AFWURjCIauXg3hjdXmA22B5wH3YpKdIkZhHNooxiWkayyIM4L6SS+IsZBHGUxVGaBCg49C7FSms7s/R93unFGhEcxAL3wu+ha41v9LrmG90PJoz8aZUtujt36zu7xj/ZHibmmQanEjL+zKpDrFayHRosPnqeEy9woLR1tdqP+xnIn4N3MvSCQM2BrVmbOjc83wkgugZz6ampVe1aN89aFy5q5S1ZErA0whc33PL+0M3xoXnIPyyIXraNRdVjKg7+JPwWVa37BwVOp5fQIIlUGuaCFzyTWQAsZYUMFaVQiFx+KcmdJUzhhyaLbx/frmcvFm1VtbcofRjJfhXtG/AfpdDUdI/t5gUaUGrrt9jCEEgM4d4Bg11vnjOjxBZL2diVVk6HwU3oQc1y6EEG3blt0JPt2DhGZYNw/b5zbWqeY3uSqKnt17zR/44Nb54mlHTJOfayWVGNEigJG5ffs0Qnka3f9XrD5Z2DogcJeoPAvkDdgSxqs3edO3f/wI13MONhs+IK6YO3LHhl4JAAXOrxWcO91OOlHr99PSKXHI/J5YfHwSGjLMplmhUMT8UwiIDlQlGViCyBnFEqcuCxYFjgZ5CmxwP9dGvHD8Av8ZVT7dx/vL/aQREnVAZIUmMuMwaCZWnAlIgTiVfKgfMgDGUcZgjFFM/rzFDsmkZLHKNC+noz1IGNpxnqPR4Mvf3M/ICE3+A8hWOTxBkFZ65Dyp/nIuYFzZMiDaSIpQwERAUTFK9UsFAWyo2K0XnJ9ET5T7Z3Htt2BncZPDNJvj7ln+HAWSU0w86OfR9nJ8fnuLn4Xij/hfL7F8p/QCMvlP8yguPhehnBx681e99U/P/pCP4flP/0/wq+BuU/3dpZfOXkb7FI+T9+ApiQGrY4GQAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a03a9497c00fc41202072b83a0a26128\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF6:4968D77:53D4369E", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 26 Jul 2014 23:00:44 GMT", "date": "Sat, 26 Jul 2014 23:15:42 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406420142"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235/commits?per_page=100"}, "recorded_at": "2014-07-26T23:15:42"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index ecec9801a..fe6a7e4b1 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -17,6 +17,14 @@ def get_pull_request(self, repository='sigmavirus24/github3.py', num=235): assert isinstance(p, github3.pulls.PullRequest) return p + def test_commits(self): + """Show that one can iterate over a PR's commits.""" + cassette_name = self.cassette_name('commits') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request() + for commit in p.commits(): + assert isinstance(commit, github3.git.Commit) + def test_issue_comments(self): """Show that one can iterate over a PR's issue comments.""" cassette_name = self.cassette_name('issue_comments') From de3eee0304960cb793098c0c3a5eb5d02b6bd700 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 12:28:30 -0500 Subject: [PATCH 239/972] Fix #262. Send proper query string --- github3/github.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/github3/github.py b/github3/github.py index 5e49a9fc5..1d9a0d72f 100644 --- a/github3/github.py +++ b/github3/github.py @@ -586,10 +586,10 @@ def notifications(self, all=False, participating=False, number=-1, :class:`Thread ` """ params = None - if all: - params = {'all': all} - elif participating: - params = {'participating': participating} + if all in (True, False): + params = {'all': str(all).lower()} + elif participating in (True, False): + params = {'participating': str(participating).lower()} url = self._build_url('notifications') return self._iter(int(number), url, Thread, params, etag=etag) From 56a1427462a0fa5cd5561ccf9b7dbc553a4fb77f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 12:30:43 -0500 Subject: [PATCH 240/972] Fix up unit tests for GitHub#notifications --- github3/github.py | 8 ++++---- tests/unit/test_github.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/github3/github.py b/github3/github.py index 1d9a0d72f..f9eb8f6ff 100644 --- a/github3/github.py +++ b/github3/github.py @@ -586,10 +586,10 @@ def notifications(self, all=False, participating=False, number=-1, :class:`Thread ` """ params = None - if all in (True, False): - params = {'all': str(all).lower()} - elif participating in (True, False): - params = {'participating': str(participating).lower()} + if all is True: + params = {'all': 'true'} + elif participating is True: + params = {'participating': 'true'} url = self._build_url('notifications') return self._iter(int(number), url, Thread, params, etag=etag) diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index 7c59e59d9..fe645d0ab 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -348,7 +348,7 @@ def test_notifications_participating_in(self): self.session.get.assert_called_once_with( url_for('notifications'), - params={'per_page': 100, 'participating': True}, + params={'per_page': 100, 'participating': 'true'}, headers={} ) @@ -359,7 +359,7 @@ def test_notifications_all(self): self.session.get.assert_called_once_with( url_for('notifications'), - params={'per_page': 100, 'all': True}, + params={'per_page': 100, 'all': 'true'}, headers={} ) From fd43fe1190836774c978a61f9097901289d41363 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 14:00:28 -0500 Subject: [PATCH 241/972] Add integration test for GitHub#notifications --- tests/cassettes/GitHub_unread_notifications.json | 1 + tests/integration/test_github.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/GitHub_unread_notifications.json diff --git a/tests/cassettes/GitHub_unread_notifications.json b/tests/cassettes/GitHub_unread_notifications.json new file mode 100644 index 000000000..ad98d8f47 --- /dev/null +++ b/tests/cassettes/GitHub_unread_notifications.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/notifications?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "nil", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "4956", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF8:8F5354D:53D54C2C", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 26 Jul 2014 22:48:35 GMT", "date": "Sun, 27 Jul 2014 18:59:56 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406487642"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/notifications?per_page=100"}, "recorded_at": "2014-07-27T18:59:56"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 41e067ef4..54f637bf2 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -188,6 +188,14 @@ def test_meta(self): m = self.gh.meta() assert isinstance(m, dict) + def test_notifications(self): + """Test the ability to retrieve unread notifications.""" + self.basic_login() + cassette_name = self.cassette_name('unread_notifications') + with self.recorder.use_cassette(cassette_name): + for notification in self.gh.notifications(): + assert isinstance(notification, github3.notifications.Thread) + def test_octocat(self): """Test the ability to use the octocat endpoint.""" cassette_name = self.cassette_name('octocat') From 91accae5d855c73e2031676f50efb68c643fc947 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 14:06:21 -0500 Subject: [PATCH 242/972] Add integration test around GitHub#notifications(all=True) --- tests/cassettes/GitHub_all_notifications.json | 1 + tests/integration/test_github.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/cassettes/GitHub_all_notifications.json diff --git a/tests/cassettes/GitHub_all_notifications.json b/tests/cassettes/GitHub_all_notifications.json new file mode 100644 index 000000000..491a021df --- /dev/null +++ b/tests/cassettes/GitHub_all_notifications.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/notifications?per_page=100&all=true"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "nil", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "4967", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:334C:8FE206E:53D54D70", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sun, 27 Jul 2014 19:03:21 GMT", "date": "Sun, 27 Jul 2014 19:05:20 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406491241"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/notifications?per_page=100&all=true"}, "recorded_at": "2014-07-27T19:05:20"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 54f637bf2..8bb2024a4 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -195,6 +195,24 @@ def test_notifications(self): with self.recorder.use_cassette(cassette_name): for notification in self.gh.notifications(): assert isinstance(notification, github3.notifications.Thread) + assert notification.unread is True + + def test_notifications_all(self): + """Test the ability to retrieve read notifications as well.""" + self.basic_login() + cassette_name = self.cassette_name('all_notifications') + with self.recorder.use_cassette(cassette_name): + read_notifications = [] + unread_notifications = [] + for notification in self.gh.notifications(all=True): + assert isinstance(notification, github3.notifications.Thread) + if notification.unread: + unread_notifications.append(notification) + else: + read_notifications.append(notification) + + assert len(read_notifications) > 0 + assert len(unread_notifications) > 0 def test_octocat(self): """Test the ability to use the octocat endpoint.""" From 5923ade12bbfbca50a5a0a5b3f20db3b690b500f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 21:17:25 -0500 Subject: [PATCH 243/972] Rename PullRequest#iter_files to PullRequest#files Migrate the unit tests --- github3/pulls.py | 2 +- tests/test_pulls.py | 10 ---------- tests/unit/test_pulls.py | 11 +++++++++++ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/github3/pulls.py b/github3/pulls.py index e51ce2082..c10a171d3 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -255,7 +255,7 @@ def commits(self, number=-1, etag=None): url = self._build_url('commits', base_url=self._api) return self._iter(int(number), url, Commit, etag=etag) - def iter_files(self, number=-1, etag=None): + def files(self, number=-1, etag=None): """Iterate over the files associated with this pull request. :param int number: (optional), number of files to return. Default: diff --git a/tests/test_pulls.py b/tests/test_pulls.py index 8873d0856..33e308b34 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -66,16 +66,6 @@ def test_is_merged(self): assert self.pull.is_merged() is False self.mock_assertions() - def test_iter_files(self): - self.response('pull_file', _iter=True) - self.get(self.api + '/files') - - f = next(self.pull.iter_files()) - assert isinstance(f, github3.pulls.PullFile) - self.mock_assertions() - - assert repr(f).startswith(' Date: Sun, 27 Jul 2014 21:21:01 -0500 Subject: [PATCH 244/972] Add integration test for PullRequest#files Update HISTORY to include the rename --- HISTORY.rst | 1 + tests/cassettes/PullRequest_files.json | 1 + tests/integration/test_pulls.py | 8 ++++++++ 3 files changed, 10 insertions(+) create mode 100644 tests/cassettes/PullRequest_files.json diff --git a/HISTORY.rst b/HISTORY.rst index 826eebc98..4a504eff9 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -57,6 +57,7 @@ Old name New name ``Organization#iter_teams`` ``Organization#teams`` ``PullRequest#iter_comments`` ``PullRequest#review_comments`` ``PullRequest#iter_commits`` ``PullRequest#commits`` +``PullRequest#iter_files`` ``PullRequest#files`` ``PullRequest#iter_issue_comments`` ``PullRequest#issue_comments`` ``Team#iter_members`` ``Team#members`` ``Team#iter_repos`` ``Team#repositories`` diff --git a/tests/cassettes/PullRequest_files.json b/tests/cassettes/PullRequest_files.json new file mode 100644 index 000000000..797547461 --- /dev/null +++ b/tests/cassettes/PullRequest_files.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxEvLJZWZOu3ubw+5lL5EBE6wGjGyTKI36v+9rDAQy2ny0V2pFCe16/LpcZapcezz2An+7mG8Xi6lX0Jx5gXfkOq1Cf1ZevKmXVFl2aP+h+DGnJy4rtVyR0ShxLpj0gtrLxJEXYAyHgmKmWa7mO38+9eiJaioPlcwwLtW6VAEh9qGaWWqlmIxEoVmhZ5HISUWs8TegjrIFGKYXLVY7f72Jd/tkv1yzzX652O5Cxhbx3qdRsoXBzUQlbyexZMykyI3aVOfZjT6rqzG5GZyILBNnUG5X9Ggi0lsaNzcUXhy/SIFlTYROGRyLJX0aR3GlXxfVWNXYXaUPPDYchd2SLH5ZWGsHWSY4PmsiWSkaYBWqSPJSc1G8LnBkDZqQR1rwD/o1GqwVIEba61IaK1izEwL1dXNrVpNS8hONLsY1kkWMn+DsLyJv7EHUl9Lk9N8ICuN6rtmBxrnJ0YRmin1OvWZ6jUHNgylS8tnoH58BMet3FRP+vOhUFJOMh5LKyyQRcsKR0DKhEWJ1csYZM0G4Tn7n+o8qnPz4+efJh0CMe++V3M3cxvmjZBzLMaQHe3IXgfQEAJLe2cWJY+xrgs82nyKkOg2FpFo8OjTuCxyBajL8aWJJM5o7CW8AAKVCuHmyAQDElarYU6F9f+ENR5Euf4oqD+2R90zW3EdbArRShXO+YMzJgz2kJt2pjHQootQN2zFqYr81u02PTlKNPTBhJkInDl6UpIHURKXUvof0wVWdoRrGCCpZ4izVMHqolo773cg0kB6Jl6DG1jvp7Bikbj2a0eJY0aMbtYdg182r+kg/HhYx93PnSgHSlG+Sh5X7IXflGKW2dkC+u7n0irlCm4LkfpnzwAGDwqZxQZ7zR3XBfWKLGIX9/4A1cXqLNr8flzGP5RpGTa5nsj30W7qLd9tTv9NJ6uscba/gFBIdg9S/lVSn5uTCVCWVzEV0iyB1SFFszWazOmW0KatzJh0z2BKAojJKUTW66Kw7BqqenOqmWk+MzBjVeyZo7OTbHgKg3UYXrZYwjLESTaqTwAYwJOY8Y0qLwu2MvVKG7EJonvDomY7lfrqNQPU3xYuITWmWTRG1mkcccYxa2+wiCk7m5iFLwDJwR2A7lYwhpJ28Lpll1MR2mpFkaETiA9VoIJbzxfJt7r8t/L8W+2C9C9b+P1hJVcajMau3+fZt2YxZrfFnxpSVSgcYO2Rrhsw3wXJjhuAEbEMQ33D/gE/cefzS3w9aCnNrAEOl0qvh96tZ8B+XI61ZlCGWboL++TlPt6+lx6aQmoqclSgT2muWfpV+eZnB0zHar1hEaoYemJiV8Q8M3S2X/qggiERVYD8Wezw+U43aFa/e4cOukOibPjM1VQebpl6gZWW6Sjy5HgODh2f+zvuOzzZtLX2zxSnJpRTtZVGBJEW/X7KiZfcyMNB2a4GxGYyAbjzoZLeriFlCq0wfbPEM2TGq/kyU0F0wfUbb14ENbVhxdMveff4LgclzRjoTAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d48273f7559998589fe53c93969a5488\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:223E:3E25D02:53D5B324", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Mon, 28 Jul 2014 02:19:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-28T02:19:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a8e07d7f75c7a69abeb2742460e940de\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:223E:3E25D14:53D5B324", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 28 Jul 2014 01:14:14 GMT", "date": "Mon, 28 Jul 2014 02:19:16 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "recorded_at": "2014-07-28T02:19:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235/files?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA71V247bNhD9FUJ5WBvRWqIutmVkk2z70DwEfQgSFKhtKBRJrVjIoiBSSTYL/3uHlOTb2tgtmsQwZIucyxnyzJnlg6MK4iwc7HM/m80iFueY8yTElASzyMfzDE8DTpLIpzENYuq4Ti5KXpENB687oYs2C72G11LBs+RE8Ul9D1ZKE90qsNlIJnLBGawRxoQWsoLlwHUYmPdvvuvQglR3vNvJSpmlbVOCd6F1rRae12WaULnxlLjbkC+iaVUQ9esh5PSMlxdPfYoTHMeEzkOehfMZDlkWTyl8Z4QTgoOAxsF8cDwHvSFf/3t2cPohyamsNK+0OkFAajE5OIPuwC+dxBDjYpFvGp7fPPeo4OJqomkBt/H2LboOAneKXsJzjuCVlkQp9KG7+dEfQr9rs99lw8eLVYXMh/EcpamohE7TkeJl7qKeJy5SXCmgw82fsto7GCfV1rwZ9VGNXZmPJ7sop/7jPpX1BNNJCqeFboY8kzuuR1dApyswfGlBwefFAr0XSiOZo4UtYvH5Vimu0Sv78/ozktk/nGqFctkgXQg1xDsIYrOBLwezG7S0niPRA7aOAonqGEhnfuWi5Xq8PkAOgD59eG+d2rqUhHGGOtvT8rpVQ5DTIvc7ptahVFPrb5Ldm1p1wQc4aGReGFe0EbVpxLGzdQc9YD5lEQ79OOJJTrKY+lOS8ZxOMx9HcZJECYlBE2bHeqC50spr4bI98ze1NIXn83UBTy8Kg9n6FcrwjCJ+vkI8A8QPVYqn8v0fxcCxUQx44gPJ+Aj8GGTjExDmHS+h53eywb+RTV3ylBFNgOUPB2xeOcD8lbMYeGylcrRyPLxyxu6RYaE3pdk11qtzs0RSLSnRHmQv5fVfsinZMMaU9wVP/Im/ciDmTjZWTt+TEHEJqHYbptkuIut8BoAnPoIZePgwSxfMDNkOeX8ak++iPobTGZbQmn2NqpCNPmzqc/ZmNveRB6k5Z9YTLNX3dW9N6roUcF4gFt4FLEp8t8bYD6LHJTH5tTLallLZVtrYRcFjK9pwAMhSYi1WTuDj8NoProPZR5wswngRBn+fA9zWQJcn/U4ubbs+5sxeQ89yzBvu/4Rq3UEOZOslb0/N3u3hjbnU7SOi7jlgR2xiGibCLvb3M/aJhjFM2AL5e/6/QLdaNyJrNUe2t/uqzTi20tyVYSeyabodJ806MMhONlEBUyrKhxEHM7CSGplx/dhDqMHcBj11XvprF92aAWmmcI9yh6YgcFR26pkT1DtYuxF2FtaBBzrChpzt+l+mz/442woAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"8d7256aba181c83e7fb5a60ba68ee1b6\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:223E:3E25D1E:53D5B324", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 28 Jul 2014 01:14:14 GMT", "date": "Mon, 28 Jul 2014 02:19:17 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235/files?per_page=100"}, "recorded_at": "2014-07-28T02:19:17"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index fe6a7e4b1..207b256c5 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -25,6 +25,14 @@ def test_commits(self): for commit in p.commits(): assert isinstance(commit, github3.git.Commit) + def test_files(self): + """Show that one can iterate over a PR's files.""" + cassette_name = self.cassette_name('files') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request() + for pr_file in p.files(): + assert isinstance(pr_file, github3.pulls.PullFile) + def test_issue_comments(self): """Show that one can iterate over a PR's issue comments.""" cassette_name = self.cassette_name('issue_comments') From 3de26e31b23677049d4af6702dbc981166de029c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 21:35:33 -0500 Subject: [PATCH 245/972] PEP257 Updates --- github3/pulls.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/github3/pulls.py b/github3/pulls.py index c10a171d3..8f81a69dd 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -23,7 +23,6 @@ class PullDestination(GitHubCore): """The :class:`PullDestination ` object. See also: http://developer.github.com/v3/pulls/#get-a-single-pull-request - """ def __init__(self, dest, direction): @@ -52,10 +51,12 @@ def _repr(self): class PullFile(GitHubObject): + """The :class:`PullFile ` object. See also: http://developer.github.com/v3/pulls/#list-pull-requests-files """ + def __init__(self, pfile): super(PullFile, self).__init__(pfile) #: SHA of the commit @@ -82,6 +83,7 @@ def _repr(self): class PullRequest(GitHubCore): + """The :class:`PullRequest ` object. Two pull request instances can be checked like so:: @@ -96,6 +98,7 @@ class PullRequest(GitHubCore): See also: http://developer.github.com/v3/pulls/ """ + def __init__(self, pull, session=None): super(PullRequest, self).__init__(pull, session) self._api = pull.get('url', '') @@ -192,7 +195,7 @@ def _update_(self, pull): @requires_auth def close(self): - """Closes this Pull Request without merging. + """Close this Pull Request without merging. :returns: bool """ @@ -218,13 +221,16 @@ def create_review_comment(self, body, commit_id, path, position): return ReviewComment(json, self) if json else None def diff(self): - """Return the diff""" + """Return the diff. + + :returns: bytestring representation of the diff. + """ resp = self._get(self._api, headers={'Accept': 'application/vnd.github.diff'}) return resp.content if self._boolean(resp, 200, 404) else None def is_merged(self): - """Checks to see if the pull request was merged. + """Check to see if the pull request was merged. :returns: bool """ @@ -232,7 +238,7 @@ def is_merged(self): return self._boolean(self._get(url), 204, 404) def review_comments(self, number=-1, etag=None): - """Iterate over the review comments on this pull request. + r"""Iterate over the review comments on this pull request. :param int number: (optional), number of comments to return. Default: -1 returns all available comments. @@ -244,7 +250,7 @@ def review_comments(self, number=-1, etag=None): return self._iter(int(number), url, ReviewComment, etag=etag) def commits(self, number=-1, etag=None): - """Iterates over the commits on this pull request. + r"""Iterate over the commits on this pull request. :param int number: (optional), number of commits to return. Default: -1 returns all available commits. @@ -256,7 +262,7 @@ def commits(self, number=-1, etag=None): return self._iter(int(number), url, Commit, etag=etag) def files(self, number=-1, etag=None): - """Iterate over the files associated with this pull request. + r"""Iterate over the files associated with this pull request. :param int number: (optional), number of files to return. Default: -1 returns all available files. @@ -268,7 +274,7 @@ def files(self, number=-1, etag=None): return self._iter(int(number), url, PullFile, etag=etag) def issue_comments(self, number=-1, etag=None): - """Iterate over the issue comments on this pull request. + r"""Iterate over the issue comments on this pull request. :param int number: (optional), number of comments to return. Default: -1 returns all available comments. From 397f9ee036f5beca137cecc8e33bb97ffc831d81 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 21:44:23 -0500 Subject: [PATCH 246/972] Last few PEP257 fixes --- github3/pulls.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/github3/pulls.py b/github3/pulls.py index 8f81a69dd..893bcdae0 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -307,7 +307,10 @@ def merge(self, commit_message=''): return json['merged'] def patch(self): - """Return the patch""" + """Return the patch. + + :returns: bytestring representation of the patch + """ resp = self._get(self._api, headers={'Accept': 'application/vnd.github.patch'}) return resp.content if self._boolean(resp, 200, 404) else None @@ -354,8 +357,10 @@ def update(self, title=None, body=None, state=None): class ReviewComment(BaseComment): - """The :class:`ReviewComment ` object. This is used to - represent comments on pull requests. + + """The :class:`ReviewComment ` object. + + This is used to represent comments on pull requests. Two comment instances can be checked like so:: @@ -369,6 +374,7 @@ class ReviewComment(BaseComment): See also: http://developer.github.com/v3/pulls/comments/ """ + def __init__(self, comment, session=None): super(ReviewComment, self).__init__(comment, session) From 4bd808c0291ee71dff08a8ba4ed08d61c834d7ac Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 21:54:55 -0500 Subject: [PATCH 247/972] Add integration test for PullRequest#diff --- tests/cassettes/PullRequest_diff.json | 1 + tests/integration/test_pulls.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/PullRequest_diff.json diff --git a/tests/cassettes/PullRequest_diff.json b/tests/cassettes/PullRequest_diff.json new file mode 100644 index 000000000..c93d93abf --- /dev/null +++ b/tests/cassettes/PullRequest_diff.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxAulOwmV2TrN7m8PsZS+RAROsBoxskyiN+r/vawwEstp8tFdqRQntevy6XGWq3Hg88cJgs1puVqu5V9KCeaF34Dqro2BRnb25l9Z5vu/+ofihoEcua+WvyWSUOJVMemHj5eLASzDGQ0Ex0/jr5TZYzj16pJrKfS1zjMu0rlRIiH2oFpZaKyZjUWpW6kUsClITa/wNqIPsAIbpxav1Nnh9S7a7dOe/sredv9psI8ZWyS6gcbqBwdVEFe8msWTMpMiV2kwX+ZU+q6s1uRqcijwXJ1CuV3RvIjJYGje3FF4evkiBZUOEzhgciyV9GkdxpZ8X1Vo12F2l9zwxHIXdkix5WlhnB1kmOD4bIlklWmAdqVjySnNRPi9wYg2akAda8g/6NRqsFSBG2vNSWitYsyMC9Xlza9aQSvIjjc/GNZLFjB/h7C8ir+xB1OfK5PRfCArjeq7ZniaFydGU5op9zr12eo1B7YM5UvLR6J+eAQkbdhUT/jzrTJSznEeSyvMsFXLGkdAypTFidXbCGTNDuM5+cP1HHc2+//zzGEAgxr0PSm5mbuv8STJO5RjSnT25iUB6AgBJ7+zsxDH2DcFnl08xUp1GQlIt7h0atwVOQA0Z/zSxpBktnIS3AIAyIdw82QIA4krV7KHQvr3wlqNInz9lXUT2yHska26jLQFaqcI5XzLm5MEB0pD+VEY6lHHmhu0ZDbHf2t2mByepxh6YKBeREwcvStJCGqIyat9Deu+qzlANYwKVLHWWahgDVEvH/W5lGsiAxEtQY+uddPYM0nQezWl5qOnBjTpAsOvmVX2gH3eLmNu5c6EAaco3yaPa/ZC7cIxSWzsg391cesFcoG1BcrvMueOAUWHTuqAo+L264DaxQ0zC/n/Amji9Rpvf98uY+3INoyGXM9ke+h3dxbvdqd/rJM1ljq5XcAqJnkGa3yqqM3NyYaqKSuYiukOQJqIothaLRZMx2pbVBZOOGWwJQFEZZ6gaXXQ2PQNVT0F1W62nRmaC6j0XNHHy7QAB0G6ji1ZLGMdYhSbVSWALGBMLnjOlRel2xl4oY3YpNE95/EjHcjvdJqDmm+JlzOY0z+eIWs1jjjhGrW12EQUnc/OQJWAZuCOwnUrOENJOXpfMMhpiO81YMjQiyZ5qNBD+cuW/LIOXVfBrtQtft+Fr8DdWUlfJZMz6Zbl58dsx61f8mTFVrbIRxg7Z/lr64Xod+u0QnIBdCOIb7h/wiTuPf/X3o5bC3BrAUKnsYvj7xSz8j8uRzizOEUtXQf/4nMfr19J9U0jNRMEqlAndNcuwyqA6L+DpBO1XImK1QA9MzMr4B4ZufT+YFASxqEvsx2qHxyeqUbvi1Tt+2BcSQ9NnpqZqb9PUC7WsTVeJJ5djYPTwxN/50PHZpq2jv21wSnIpRXdZVCJJ0e9XrOzYgwwMtN1aaGxGI6AbD3rZ3SoSltI613tbPEN2gqo/FxV0l0yf0Pb1YEMbVxz9sref/wBk1SLmOhMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"bc64c224f5f8498f8196587a829d8938\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7B32:9FA0EC6:53D5BB65", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Mon, 28 Jul 2014 02:54:29 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-28T02:54:29"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"dab3f1e0b1be7a005ccca507d9b881a3\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "55", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7B32:9FA0F48:53D5BB65", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 28 Jul 2014 01:14:14 GMT", "date": "Mon, 28 Jul 2014 02:54:29 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "recorded_at": "2014-07-28T02:54:29"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index 207b256c5..3fff476be 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -25,6 +25,15 @@ def test_commits(self): for commit in p.commits(): assert isinstance(commit, github3.git.Commit) + def test_diff(self): + """Show that one can retrieve a bytestring diff of a PR.""" + cassette_name = self.cassette_name('diff') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request() + diff = p.diff() + assert isinstance(diff, bytes) + assert len(diff) > 0 + def test_files(self): """Show that one can iterate over a PR's files.""" cassette_name = self.cassette_name('files') From ad66ee4649e3000089d3d0b0f3f9e50fdea4bfd4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 21:57:26 -0500 Subject: [PATCH 248/972] Add integration test for PullRequest#is_merged --- tests/cassettes/PullRequest_is_merged.json | 1 + tests/integration/test_pulls.py | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 tests/cassettes/PullRequest_is_merged.json diff --git a/tests/cassettes/PullRequest_is_merged.json b/tests/cassettes/PullRequest_is_merged.json new file mode 100644 index 000000000..61ebaecab --- /dev/null +++ b/tests/cassettes/PullRequest_is_merged.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxgKTzcZmd0+ze5jB72UtkwASrASPbJEqj/u/7GgOBrDZJt1dqRQntevy6XGWq3Hg88fbhxl9ufH/ulbRg3t47cp3VUbioLt7cS+s8P3T/UPxY0BOXtQpWZDJKnEsmvX3j5eLISzDGQ0Ex0wSr5TZczj16oprKQy1zjMu0rtSeEPtQLSy1VkzGotSs1ItYFKQm1vgbUEfZAQzTi/3VNly/JttdugvW7HUX+JttxJif7EIapxsY3ExU8W4SS8ZMityozXSR3+izulqTm8GpyHNxBuV2RY8mIoOlcXNL4eXxixRYNkTojMGxWNKHcRRX+vOiWqsGu6v0gSeGo7BbkiWfFtbZQZYJjo+GSFaJFlhHKpa80lyUnxc4sQZNyCMt+Tv9Gg3WChAj7fNSWitYsxMC9fPm1qwhleQnGl+MaySLGT/B2V9E3tiDqC+Vyem/EBTG9VyzA00Kk6MpzRX7mHvt9BqD2gdzpOSz0T89AxI27Com/HnRmShnOY8klZdZKuSMI6FlSmPE6uyMM2aGcJ394PqPOpp9//nnKYRAjHsblNzN3Nb5k2ScyjGkB3tyF4H0BACS3tjFiWPsG4LPLp9ipDqNhKRaPDo07gucgBoy/mliSTNaOAlvAQBlQrh5sgUAxJWq2VOhfX/hLUeRPn/KuojskfdM1txHWwK0UoVzvmTMyYMDpCH9qYx0KOPMDdszGmK/tbtNj05SjT0wUS4iJw5elKSFNERl1L6H9MFVnaEaxgQqWeos1TAGqJaO+93KNJABiZegxtY76ewZpOk8mtPyWNOjG3WAYNfNq/pI3x8WMfdz50oB0pRvkke1+yF35RiltnZAvru59Iq5QtuC5H6Z88ABo8KmdUFR8Ed1wX1ih5iE/f+ANXF6iza/H5cxj+UaRkOuZ7I99Du6i3e7U7/XSZrrHF2v4BQSPYM0v1VUZ+bkwlQVlcxFdIcgTURRbC0WiyZjtC2rCyYdM9gSgKIyzlA1uuhsegaqnoLqtlpPjcwE1XsuaOLk2wECoN1GF62WMI6xCk2qk8AWMCYWPGdKi9LtjL1SxuxSaJ7y+JmO5X66TUDNN8XLmM1pns8RtZrHHHGMWtvsIgpO5uYhS8AycEdgO5WcIaSdvC6ZZTTEdpqxZGhEkgPVaCCCpR+8LMMXP/zl7/br7X4d/o2V1FUyGbN6WW5egnbMao0/M6aqVTbC2CHbX8tgv16BZIbgBOxCEN9w/4BP3Hn8q78ftRTm1gCGSmVXw9+vZvv/uBzpzOIcsXQT9M/Pebp9LT02hdRMFKxCmdBdswyrDKvLAp5O0H4lIlYL9MDErIy/Y+g2CMJJQRCLusR++Ds8PlON2hWv3vHDvpAYmj4zNVUHm6beXsvadJV4cj0GRg/P/I0PHZ9t2jr66wanJJdSdJdFJZIU/X7Fyo49yMBA263tjc1oBHTjQS+7W0XCUlrn+mCLZ8hOUPXnooLukukz2r4ebGjjiqNf9vbjH8Cshcw6EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"103c261a609253cc5113039f6ab21f0e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "54", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF9:2EE6AA1:53D5BBD8", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Mon, 28 Jul 2014 02:56:25 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-28T02:56:25"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"42d9e03172ef97d5dbb406c4702c5c0e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "53", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF9:2EE6AAD:53D5BBD9", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 28 Jul 2014 01:14:14 GMT", "date": "Mon, 28 Jul 2014 02:56:25 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "recorded_at": "2014-07-28T02:56:25"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235/merge"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "52", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:7DF9:2EE6AB9:53D5BBD9", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "60", "x-served-by": "c436b2b44345c72ff906059f604991e7", "access-control-allow-credentials": "true", "date": "Mon, 28 Jul 2014 02:56:25 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406517556"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235/merge"}, "recorded_at": "2014-07-28T02:56:25"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index 3fff476be..ecb9c1af5 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -42,6 +42,13 @@ def test_files(self): for pr_file in p.files(): assert isinstance(pr_file, github3.pulls.PullFile) + def test_is_merged(self): + """Show that one can check if a PR was merged.""" + cassette_name = self.cassette_name('is_merged') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request() + assert p.is_merged() is True + def test_issue_comments(self): """Show that one can iterate over a PR's issue comments.""" cassette_name = self.cassette_name('issue_comments') From 31fdb05b44f2fb0bb2a121bc9e7011d55234b6c0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 27 Jul 2014 22:01:18 -0500 Subject: [PATCH 249/972] Add integration test for PullRequest#patch --- tests/cassettes/PullRequest_patch.json | 1 + tests/integration/test_pulls.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/PullRequest_patch.json diff --git a/tests/cassettes/PullRequest_patch.json b/tests/cassettes/PullRequest_patch.json new file mode 100644 index 000000000..8478b68f1 --- /dev/null +++ b/tests/cassettes/PullRequest_patch.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxgKTzcZmd0+ze5jB72UtkwASrASPbJEqj/u/7GgOBrDZJt1dqRQntevy6XGWq3Hg88fbhxl9ufH/ulbRg3t47cp3VUbioLt7cS+s8P3T/UPxY0BOXtQpWZDJKnEsmvX3j5eLISzDGQ0Ex0wSr5TZczj16oprKQy1zjMu0rtSeEPtQLSy1VkzGotSs1ItYFKQm1vgbUEfZAQzTi/3VNly/JttdugvW7HUX+JttxJif7EIapxsY3ExU8W4SS8ZMityozXSR3+izulqTm8GpyHNxBuV2RY8mIoOlcXNL4eXxixRYNkTojMGxWNKHcRRX+vOiWqsGu6v0gSeGo7BbkiWfFtbZQZYJjo+GSFaJFlhHKpa80lyUnxc4sQZNyCMt+Tv9Gg3WChAj7fNSWitYsxMC9fPm1qwhleQnGl+MaySLGT/B2V9E3tiDqC+Vyem/EBTG9VyzA00Kk6MpzRX7mHvt9BqD2gdzpOSz0T89AxI27Com/HnRmShnOY8klZdZKuSMI6FlSmPE6uyMM2aGcJ394PqPOpp9//nnKYRAjHsblNzN3Nb5k2ScyjGkB3tyF4H0BACS3tjFiWPsG4LPLp9ipDqNhKRaPDo07gucgBoy/mliSTNaOAlvAQBlQrh5sgUAxJWq2VOhfX/hLUeRPn/KuojskfdM1txHWwK0UoVzvmTMyYMDpCH9qYx0KOPMDdszGmK/tbtNj05SjT0wUS4iJw5elKSFNERl1L6H9MFVnaEaxgQqWeos1TAGqJaO+93KNJABiZegxtY76ewZpOk8mtPyWNOjG3WAYNfNq/pI3x8WMfdz50oB0pRvkke1+yF35RiltnZAvru59Iq5QtuC5H6Z88ABo8KmdUFR8Ed1wX1ih5iE/f+ANXF6iza/H5cxj+UaRkOuZ7I99Du6i3e7U7/XSZrrHF2v4BQSPYM0v1VUZ+bkwlQVlcxFdIcgTURRbC0WiyZjtC2rCyYdM9gSgKIyzlA1uuhsegaqnoLqtlpPjcwE1XsuaOLk2wECoN1GF62WMI6xCk2qk8AWMCYWPGdKi9LtjL1SxuxSaJ7y+JmO5X66TUDNN8XLmM1pns8RtZrHHHGMWtvsIgpO5uYhS8AycEdgO5WcIaSdvC6ZZTTEdpqxZGhEkgPVaCCCpR+8LMMXP/zl7/br7X4d/o2V1FUyGbN6WW5egnbMao0/M6aqVTbC2CHbX8tgv16BZIbgBOxCEN9w/4BP3Hn8q78ftRTm1gCGSmVXw9+vZvv/uBzpzOIcsXQT9M/Pebp9LT02hdRMFKxCmdBdswyrDKvLAp5O0H4lIlYL9MDErIy/Y+g2CMJJQRCLusR++Ds8PlON2hWv3vHDvpAYmj4zNVUHm6beXsvadJV4cj0GRg/P/I0PHZ9t2jr66wanJJdSdJdFJZIU/X7Fyo49yMBA263tjc1oBHTjQS+7W0XCUlrn+mCLZ8hOUPXnooLukukz2r4ebGjjiqNf9vbjH8Cshcw6EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"103c261a609253cc5113039f6ab21f0e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "51", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF6:60A0AE6:53D5BCEB", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Mon, 28 Jul 2014 03:00:59 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-28T03:00:59"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"42d9e03172ef97d5dbb406c4702c5c0e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "50", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF6:60A0B3A:53D5BCEB", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 28 Jul 2014 01:14:14 GMT", "date": "Mon, 28 Jul 2014 03:00:59 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406517556"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/235"}, "recorded_at": "2014-07-28T03:00:59"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index ecb9c1af5..b6f9d1360 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -58,6 +58,15 @@ def test_issue_comments(self): assert isinstance(comment, github3.issues.comment.IssueComment) + def test_patch(self): + """Show that a user can get the patch from a PR.""" + cassette_name = self.cassette_name('patch') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request() + patch = p.patch() + assert isinstance(patch, bytes) + assert len(patch) > 0 + def test_review_comments(self): """Show that one can iterate over a PR's review comments.""" cassette_name = self.cassette_name('review_comments') From af35e185818a3152ddd4f980613feea7e99e07c6 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 06:47:41 -0500 Subject: [PATCH 250/972] Migrate the PullRequest#diff unit test --- tests/test_pulls.py | 12 ------------ tests/unit/test_pulls.py | 8 ++++++++ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index 33e308b34..c2d84de2c 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -43,18 +43,6 @@ def test_close(self): up.assert_called_once_with( self.pull.title, self.pull.body, 'closed') - def test_diff(self): - self.response('archive') - self.get(self.api) - self.conf = { - 'headers': { - 'Accept': 'application/vnd.github.diff' - } - } - - assert self.pull.diff() != '' - self.mock_assertions() - def test_is_merged(self): self.response('', 204) self.get(self.api + '/merge') diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index 665db54e4..bc0498603 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -28,6 +28,14 @@ class TestPullRequest(UnitHelper): described_class = PullRequest example_data = get_pr_example_data() + def test_diff(self): + """Show that a user can request the diff of a Pull Request.""" + self.instance.diff() + + self.session.get.assert_called_once_with( + url_for(), + headers={'Accept': 'application/vnd.github.diff'} + ) class TestPullRequestIterator(UnitIteratorHelper): From 804000fa1c8fc7bd4ea78d65115ae068f89d6cf5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 06:50:50 -0500 Subject: [PATCH 251/972] Test that PullRequest#close requires authentication --- tests/unit/test_pulls.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index bc0498603..50bb75ae8 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -1,9 +1,11 @@ """Unit tests for the github3.pulls module.""" import json import os +import pytest from .helper import UnitHelper, UnitIteratorHelper, create_url_helper +from github3 import GitHubError from github3.pulls import PullRequest @@ -37,6 +39,24 @@ def test_diff(self): headers={'Accept': 'application/vnd.github.diff'} ) + +class TestPullRequestRequiresAuthentication(UnitHelper): + + """PullRequest unit tests that demonstrate which methods require auth.""" + + described_class = PullRequest + example_data = get_pr_example_data() + + def after_setup(self): + """Make it appear as if the user has not authenticated.""" + self.session.has_auth.return_value = False + + def test_close(self): + """Show that you must be authenticated to close a Pull Request.""" + with pytest.raises(GitHubError): + self.instance.close() + + class TestPullRequestIterator(UnitIteratorHelper): """Test PullRequest methods that return Iterators.""" From 7a8b93fa3c49cbdbf37e01418923c2e5b0ef404b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 17:59:35 -0500 Subject: [PATCH 252/972] Add PullRequest#is_merged unit test --- tests/test_pulls.py | 11 ----------- tests/unit/test_pulls.py | 6 ++++++ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index c2d84de2c..bf5e120e6 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -43,17 +43,6 @@ def test_close(self): up.assert_called_once_with( self.pull.title, self.pull.body, 'closed') - def test_is_merged(self): - self.response('', 204) - self.get(self.api + '/merge') - - assert self.pull.is_merged() - self.mock_assertions() - - self.response('', 404) - assert self.pull.is_merged() is False - self.mock_assertions() - def test_merge(self): self.response('merge', 200) self.put(self.api + '/merge') diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index 50bb75ae8..fd1e1025b 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -39,6 +39,12 @@ def test_diff(self): headers={'Accept': 'application/vnd.github.diff'} ) + def test_is_merged(self): + """Show that a user can request the merge status of a PR.""" + self.instance.is_merged() + + self.session.get.assert_called_once_with(url_for('merge')) + class TestPullRequestRequiresAuthentication(UnitHelper): From e3acc98ea2b194745b059ec8bef12f0d547fc8a5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 19:33:54 -0500 Subject: [PATCH 253/972] Migrate unit tests for PullRequest#merge --- github3/pulls.py | 2 ++ tests/test_pulls.py | 16 ---------------- tests/unit/test_pulls.py | 11 +++++++++++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/github3/pulls.py b/github3/pulls.py index 893bcdae0..55a4a6a80 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -303,6 +303,8 @@ def merge(self, commit_message=''): data = dumps({'commit_message': commit_message}) url = self._build_url('merge', base_url=self._api) json = self._json(self._put(url, data=data), 200) + if not json: + return False self.merge_commit_sha = json['sha'] return json['merged'] diff --git a/tests/test_pulls.py b/tests/test_pulls.py index bf5e120e6..ac344f890 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -43,22 +43,6 @@ def test_close(self): up.assert_called_once_with( self.pull.title, self.pull.body, 'closed') - def test_merge(self): - self.response('merge', 200) - self.put(self.api + '/merge') - self.conf = {'data': None} - - self.assertRaises(github3.GitHubError, self.pull.merge) - - self.not_called() - self.login() - assert self.pull.merge() - self.mock_assertions() - - self.conf['data'] = {'commit_message': 'Merged'} - assert self.pull.merge('Merged') - self.mock_assertions() - def test_patch(self): self.response('archive', 200) self.get(self.api) diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index fd1e1025b..2688dbde3 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -45,6 +45,12 @@ def test_is_merged(self): self.session.get.assert_called_once_with(url_for('merge')) + def test_merge(self): + """Show that a user can merge a Pull Request.""" + self.instance.merge() + + self.session.put.assert_called_once_with(url_for('merge'), data=None) + class TestPullRequestRequiresAuthentication(UnitHelper): @@ -62,6 +68,11 @@ def test_close(self): with pytest.raises(GitHubError): self.instance.close() + def test_merge(self): + """Show that you must be authenticated to merge a Pull Request.""" + with pytest.raises(GitHubError): + self.instance.merge() + class TestPullRequestIterator(UnitIteratorHelper): From 43c2fc8ee6f2043e3c0596440d061d46e0ea6c51 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 20:42:24 -0500 Subject: [PATCH 254/972] Migrate PullRequest#patch unit test --- tests/test_pulls.py | 8 -------- tests/unit/test_pulls.py | 9 +++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index ac344f890..a948db2ec 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -43,14 +43,6 @@ def test_close(self): up.assert_called_once_with( self.pull.title, self.pull.body, 'closed') - def test_patch(self): - self.response('archive', 200) - self.get(self.api) - self.conf = {'headers': {'Accept': 'application/vnd.github.patch'}} - - assert self.pull.patch() != '' - self.mock_assertions() - def test_reopen(self): self.assertRaises(github3.GitHubError, self.pull.reopen) diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index 2688dbde3..e8ec88b31 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -51,6 +51,15 @@ def test_merge(self): self.session.put.assert_called_once_with(url_for('merge'), data=None) + def test_patch(self): + """Show that a user can fetch the patch from a Pull Request.""" + self.instance.patch() + + self.session.get.assert_called_once_with( + url_for(), + headers={'Accept': 'application/vnd.github.patch'} + ) + class TestPullRequestRequiresAuthentication(UnitHelper): From 96249fdf5519eb1fb96ad80f8199df208e1e3ce5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 21:20:25 -0500 Subject: [PATCH 255/972] Migrate PullRequest#reopen unit tests --- tests/test_pulls.py | 9 --------- tests/unit/test_pulls.py | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index a948db2ec..d1aadd58d 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -43,15 +43,6 @@ def test_close(self): up.assert_called_once_with( self.pull.title, self.pull.body, 'closed') - def test_reopen(self): - self.assertRaises(github3.GitHubError, self.pull.reopen) - - self.login() - with mock.patch.object(github3.pulls.PullRequest, 'update') as up: - self.pull.reopen() - up.assert_called_once_with( - self.pull.title, self.pull.body, 'open') - def test_update(self): self.response('pull', 200) self.patch(self.api) diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index e8ec88b31..59cbf8ef2 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -60,6 +60,19 @@ def test_patch(self): headers={'Accept': 'application/vnd.github.patch'} ) + def test_reopen(self): + """Show that a user can reopen a Pull Request that was closed.""" + self.instance.reopen() + + self.patch_called_with( + url_for(), + data={ + 'title': self.instance.title, + 'body': self.instance.body, + 'state': 'open' + } + ) + class TestPullRequestRequiresAuthentication(UnitHelper): @@ -82,6 +95,11 @@ def test_merge(self): with pytest.raises(GitHubError): self.instance.merge() + def test_reopen(self): + """Show that you must be authenticated to reopen a Pull Request.""" + with pytest.raises(GitHubError): + self.instance.reopen() + class TestPullRequestIterator(UnitIteratorHelper): From 5e3c14219fa799fdb0d195579ea7d45c9f868732 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 21:22:10 -0500 Subject: [PATCH 256/972] Migrate PullRequest#close unit test --- tests/test_pulls.py | 11 ----------- tests/unit/test_pulls.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index d1aadd58d..a1a90889c 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -32,17 +32,6 @@ def test_dest(self): def test_repr(self): assert repr(self.pull).startswith(' Date: Mon, 28 Jul 2014 21:32:41 -0500 Subject: [PATCH 257/972] Migrate PullRequest#update unit test --- tests/test_pulls.py | 14 -------------- tests/unit/test_pulls.py | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/tests/test_pulls.py b/tests/test_pulls.py index a1a90889c..6af45f603 100644 --- a/tests/test_pulls.py +++ b/tests/test_pulls.py @@ -32,20 +32,6 @@ def test_dest(self): def test_repr(self): assert repr(self.pull).startswith(' Date: Mon, 28 Jul 2014 21:34:45 -0500 Subject: [PATCH 258/972] Remove deprecated attribute --- HISTORY.rst | 3 +++ github3/pulls.py | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 4a504eff9..756c65ed3 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -156,6 +156,9 @@ Old name New name - The ``links`` attribute now contains the raw ``_links`` attribute from the API. + - The ``merge_commit_sha`` attribute has been removed since it was deprecated + in the GitHub API. + - To present a more consistent universal API, certain attributes have been renamed. diff --git a/github3/pulls.py b/github3/pulls.py index 55a4a6a80..f479098d5 100644 --- a/github3/pulls.py +++ b/github3/pulls.py @@ -148,8 +148,7 @@ def __init__(self, pull, session=None): self.mergeable = pull.get('mergeable', False) #: Whether it would be a clean merge or not self.mergeable_state = pull.get('mergeable_state', '') - #: SHA of the merge commit. DEPRECATED - self.merge_commit_sha = pull.get('merge_commit_sha', '') + user = pull.get('merged_by') #: :class:`User ` who merged this pull self.merged_by = User(user, self) if user else None @@ -305,7 +304,6 @@ def merge(self, commit_message=''): json = self._json(self._put(url, data=data), 200) if not json: return False - self.merge_commit_sha = json['sha'] return json['merged'] def patch(self): From a1f44c93566ed5081270913a7cd48534ff8e6987 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 21:36:04 -0500 Subject: [PATCH 259/972] Remove old test file --- tests/test_pulls.py | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 tests/test_pulls.py diff --git a/tests/test_pulls.py b/tests/test_pulls.py deleted file mode 100644 index 6af45f603..000000000 --- a/tests/test_pulls.py +++ /dev/null @@ -1,41 +0,0 @@ -import github3 -from tests.utils import BaseCase, load, mock - - -class TestPullRequest(BaseCase): - def __init__(self, methodName='runTest'): - super(TestPullRequest, self).__init__(methodName) - self.pull = github3.pulls.PullRequest(load('pull')) - self.api = ("https://api.github.com/repos/sigmavirus24/github3.py/" - "pulls/18") - - def setUp(self): - super(TestPullRequest, self).setUp() - self.pull = github3.pulls.PullRequest(self.pull.to_json(), self.g) - - def test_equality(self): - p = github3.pulls.PullRequest(load('pull')) - assert self.pull == p - p._uniq = 'foo' - assert self.pull != p - - def test_hashing(self): - p = github3.pulls.PullRequest(load('pull')) - s = set() - s.add(p) - s.add(p) - assert len(s) == 1 - - def test_dest(self): - assert repr(self.pull.base).startswith(' Date: Mon, 28 Jul 2014 21:44:20 -0500 Subject: [PATCH 260/972] Add PullRequest#close integration test --- tests/cassettes/PullRequest_close.json | 1 + tests/integration/test_pulls.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/PullRequest_close.json diff --git a/tests/cassettes/PullRequest_close.json b/tests/cassettes/PullRequest_close.json new file mode 100644 index 000000000..dbf00177c --- /dev/null +++ b/tests/cassettes/PullRequest_close.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxEtKdhMvsnGb3NofZy14iAwasBoxskyiN+r/vawwEstp8tFdqRQntevy6XGWq3Hg89gJ/u1puV6u5V9KCeYGXcp3Vob+ozt7cS+o8P3T/UDwt6JHLWq03ZDJKnEomvaDxcpHyEozxUFDMNOvNcucv5x49Uk3loZY5xmVaVyogxD5UC0utFZORKDUr9SISBamJNf4GVCo7gGF60Wqz81/f4t0+2a9f2dt+vdruQsZW8d6nUbKFwdVEFe8msWTMpMiV2kwX+ZU+q6s1uRqciDwXJ1CuV3RvIjJYGje3FF6mX6TAsiFCZwyOxZI+jaO40s+Laq0a7K7SBx4bjsJuSRY/LayzgywTHJ8NkawSLbAOVSR5pbkonxc4sQZNyJSW/IN+jQZrBYiR9ryU1grW7IhAfd7cmjWkkvxIo7NxjWQR40c4+4vIK3sQ9bkyOf0XgsK4nmt2oHFhcjShuWKfc6+dXmNQ+2COlHw0+qdnQMyGXcWEP886E+Us56Gk8jxLhJxxJLRMaIRYnZ1wxswQrrMfXP9Rh7PvP/88+hCIce+DkpuZ2zp/koxTOYZ0Z09uIpCeAEDSOzs7cYx9Q/DZ5VOEVKehkFSLe4fGbYETUEPGP00saUYLJ+EtAKBMCDdPtgCAuFI1eyi0by+85SjS509ZF6E98h7JmttoS4BWqnDOl4w5eXCANKQ/lZEOZZS5YXtGQ+y3drdp6iTV2AMT5iJ04uBFSVpIQ1RG7XtIH1zVGaphTKCSJc5SDWOAaum4361MAxmQeAlqbL2Tzp5Bms6jOS3TmqZu1AGCXTev6pR+3C1ibufOhQKkKd8kD2v3Q+7CMUpt7YB8d3PpBXOBtgXJ7TLnjgNGhU3rgqLg9+qC28QOMQn7/wFr4vQabX7fL2PuyzWMhlzOZHvod3QX73anfq+TNJc5ul7BKSR6Bml+q6jOzMmFqSoqmYvoDkGakKLYWiwWTcZoW1YXTDpmsCUARWWUoWp00dn0DFQ9BdVttZ4YmTGq91zQ2Mm3AwRAu40uWi1hHGMVmlQngS1gTCx4zpQWpdsZe6GM2aXQPOHRIx3L7XSbgJpvipcRm9M8nyNqNY844hi1ttlFFJzMzUOWgGXgjsB2KjlDSDt5XTLLaIjtNCPJ0IjEB6rRQKyXq/XL0n9Z+b9W++B1F7z6f2MldRVPxmxeltuXdTtm84o/M6aqVTbC2CH7X8t14L8Fy60ZghOwC0F8w/0DPnHn8a/+ftRSmFsDGCqVXQx/v5gF/3E50plFOWLpKugfn/N4/Vq6bwqpmShYhTKhu2YZVulX5wU8HaP9ikWkFuiBiVkZ/8DQ3XrtTwqCSNQl9mO1x+MT1ahd8eodP+wLiaHpM1NTdbBp6gVa1qarxJPLMTB6eOLvfOj4bNPW0d+2OCW5lKK7LCqRpOj3K1Z27EEGBtpuLTA2oxHQjQe97G4VMUtoneuDLZ4hO0bVn4vKRA6TBXSbiwlzm9V1ynYFJqr61Zjzwn5HA10yfUKv2KsxEsZlSu+r3ec/5mQUim8TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0cc49ac71084a77c875bc3b1f35f7489\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4956", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF9:3DE2BB1:53D70A60", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Tue, 29 Jul 2014 02:43:44 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-29T02:43:44"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a8993152cb7f554817fe09d3bb721f99\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4955", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF9:3DE2BC8:53D70A60", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Sat, 05 Jul 2014 17:13:07 GMT", "date": "Tue, 29 Jul 2014 02:43:44 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "recorded_at": "2014-07-29T02:43:44"}, {"request": {"body": {"string": "{\"body\": \"if you like it, i will do the same with `issue`, `iter_repo_issues` and `pull_request`\", \"state\": \"closed\", \"title\": \"removed duplicate documentation\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "161", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PATCH", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0302eff3c50473b3d4e83aed3476e57b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4954", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7DF9:3DE2BD2:53D70A60", "cache-control": "private, max-age=60, s-maxage=60", "date": "Tue, 29 Jul 2014 02:43:44 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "recorded_at": "2014-07-29T02:43:44"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index b6f9d1360..b77a55f0d 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -17,6 +17,14 @@ def get_pull_request(self, repository='sigmavirus24/github3.py', num=235): assert isinstance(p, github3.pulls.PullRequest) return p + def test_close(self): + """Show that one can close an open Pull Request.""" + self.basic_login() + cassette_name = self.cassette_name('close') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request(num=241) + assert p.close() is True + def test_commits(self): """Show that one can iterate over a PR's commits.""" cassette_name = self.cassette_name('commits') From b851ede423ade3de42032733aa0bca82b9f3a170 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 21:45:07 -0500 Subject: [PATCH 261/972] Add integration test for PullRequest#reopen --- tests/cassettes/PullRequest_reopen.json | 1 + tests/integration/test_pulls.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/PullRequest_reopen.json diff --git a/tests/cassettes/PullRequest_reopen.json b/tests/cassettes/PullRequest_reopen.json new file mode 100644 index 000000000..736eb5672 --- /dev/null +++ b/tests/cassettes/PullRequest_reopen.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxEvLJZXZOs3ubw+xlL5EBE6wGjGyTKI36v+9rDASy2ny0V2pFCe16/LpcZapcezz2An+7mG8Xi6lX0Jx5gXfkOq1Cf1ZevKmXVFl2aP+h+DGnJy4rtVyR0ShxLpj0gtrLxJEXYAyHgmKmWa7mO38+9eiJaioPlcwwLtW6VAEh9qGaWWqlmIxEoVmhZ5HISUWs8TegjrIFGKYXLVY7f72Jd/tkv1yzzX652O5Cxhbx3qdRsoXBzUQlbyexZMykyI3aVOfZjT6rqzG5GZyILBNnUG5X9Ggi0lsaNzcUXhy/SIFlTYROGRyLJX0aR3GlXxfVWNXYXaUPPDYchd2SLH5ZWGsHWSY4PmsiWSkaYBWqSPJSc1G8LnBkDZqQR1rwD/o1GqwVIEba61IaK1izEwL1dXNrVpNS8hONLsY1kkWMn+DsLyJv7EHUl9Lk9F8ICuN6rtmBxrnJ0YRmin1OvWZ6jUHNgylS8tnoH58BMet3FRP+vOhUFJOMh5LKyyQRcsKR0DKhEWJ1csYZM0G4Tn5w/UcVTr7//PPkQyDGvfdK7mZu4/xRMo7lGNKDPbmLQHoCAEnv7OLEMfY1wWebTxFSnYZCUi0eHRr3BY5ANRn+NLGkGc2dhDcAgFIh3DzZAADiSlXsqdC+v/CGo0iXP0WVh/bIeyZr7qMtAVqpwjlfMObkwR5Sk+5URjoUUeqG7Rg1sd+a3aZHJ6nGHpgwE6ETBy9K0kBqolJq30P64KrOUA1jBJUscZZqGD1US8f9bmQaSI/ES1Bj6510dgxStx7NaHGs6NGN2kOw6+ZVfaQfD4uY+7lzpQBpyjfJw8r9kLtyjFJbOyDf3Vx6xVyhTUFyv8x54IBBYdO4IM/5o7rgPrFFjML+f8CaOL1Fm9+Py5jHcg2jJtcz2R76Ld3Fu+2p3+kk9XWOtldwComOQerfSqpTc3JhqpJK5iK6RZA6pCi2ZrNZnTLalNU5k44ZbAlAURmlqBpddNYdA1VPTnVTrSdGZozqPRM0dvJtDwHQbqOLVksYxliJJtVJYAMYEnOeMaVF4XbGXilDdiE0T3j0TMdyP91GoPqb4kXEpjTLpohazSOOOEatbXYRBSdz85AlYBm4I7CdSsYQ0k5el8wyamI7zUgyNCLxgWo0EMv5Yvk2998W/q/FPljvgrX/N1ZSlfFozOptvn1bNmNWa/yZMWWl0gHGDtn/mi8DfxPMt2YITsA2BPEN9w/4xJ3Hv/r7QUthbg1gqFR6Nfz9ahb8x+VIaxZliKWboH9+ztPta+mxKaSmImclyoT2mqVfpV9eZvB0jPYrFpGaoQcmZmX8A0N3y6U/KggiURXYj8Uej89Uo3bFq3f4sCsk+qbPTE3VwaapF2hZma4ST67HwODhmb/zvuOzTVtL32xxSnIpRXtZVCBJ0e+XrGjZvYyNbRyVFxibwQjoxv862e0qYpbQKtMHWzxDdoyqPxOliRwmc+g2FxPmNqvtlO0KTFR1qzHnhf2OBrpg+oxesVNjJAzLlM5Xu89/AFeAsOtvEwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"264744c8c493ac76aadadacfdb31cf39\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4953", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:334C:C2EB9EA:53D70A8F", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Tue, 29 Jul 2014 02:44:32 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-29T02:44:32"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0302eff3c50473b3d4e83aed3476e57b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4952", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:334C:C2EBA2F:53D70A90", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Tue, 29 Jul 2014 02:43:44 GMT", "date": "Tue, 29 Jul 2014 02:44:32 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "recorded_at": "2014-07-29T02:44:32"}, {"request": {"body": {"string": "{\"body\": \"if you like it, i will do the same with `issue`, `iter_repo_issues` and `pull_request`\", \"state\": \"open\", \"title\": \"removed duplicate documentation\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "159", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PATCH", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"767f4662f7df8d7b4c729c4699f60196\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4951", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:334C:C2EBA55:53D70A90", "cache-control": "private, max-age=60, s-maxage=60", "date": "Tue, 29 Jul 2014 02:44:32 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "recorded_at": "2014-07-29T02:44:32"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index b77a55f0d..37756608a 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -75,6 +75,14 @@ def test_patch(self): assert isinstance(patch, bytes) assert len(patch) > 0 + def test_reopen(self): + """Show that one can reopen an open Pull Request.""" + self.basic_login() + cassette_name = self.cassette_name('reopen') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request(num=241) + assert p.reopen() is True + def test_review_comments(self): """Show that one can iterate over a PR's review comments.""" cassette_name = self.cassette_name('review_comments') From d6bc497ce7c87460ba04202fa542c611bc88576a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 28 Jul 2014 21:47:11 -0500 Subject: [PATCH 262/972] Add integration test for PullRequest#update --- tests/cassettes/PullRequest_update.json | 1 + tests/integration/test_pulls.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/cassettes/PullRequest_update.json diff --git a/tests/cassettes/PullRequest_update.json b/tests/cassettes/PullRequest_update.json new file mode 100644 index 000000000..4651a5c17 --- /dev/null +++ b/tests/cassettes/PullRequest_update.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+jOBCG/0rEddNxgHTn4zI7p9m9zWH2spfIgAlWA0a2SZRG/d/3NQYCWW0+2iu1ooR2PX5drjJVbjyeeLtw7S/Xvj/3Slowb+cduM7qKFxUZ2/upXWe77t/KH4o6JHLWgUrMhklTiWT3q7xcnHgJRjjoaCYaYLVchMu5x49Uk3lvpY5xmVaV2pHiH2oFpZaKyZjUWpW6kUsClITa/wNqIPsAIbpxf5qE76+JZttug1e2ds28NebiDE/2YY0TtcwuJqo4t0kloyZFLlSm+kiv9JndbUmV4NTkefiBMr1iu5NRAZL4+aWwsvDFymwbIjQGYNjsaRP4yiu9POiWqsGu6v0nieGo7BbkiVPC+vsIMsEx2dDJKtEC6wjFUteaS7K5wVOrEET8kBL/kG/RoO1AsRIe15KawVrdkSgPm9uzRpSSX6k8dm4RrKY8SOc/UXklT2I+lyZnP4LQWFczzXb06QwOZrSXLHPuddOrzGofTBHSj4a/dMzIGHDrmLCn2ediXKW80hSeZ6lQs44ElqmNEaszk44Y2YI19kPrv+oo9n3n38eQwjEuPdByc3MbZ0/ScapHEO6syc3EUhPACDpnZ2dOMa+Ifjs8ilGqtNISKrFvUPjtsAJqCHjnyaWNKOFk/AWAFAmhJsnWwBAXKmaPRTatxfechTp86esi8geeY9kzW20JUArVTjnS8acPDhAGtKfykiHMs7csD2jIfZbu9v04CTV2AMT5SJy4uBFSVpIQ1RG7XtI713VGaphTKCSpc5SDWOAaum4361MAxmQeAlqbL2Tzp5Bms6jOS0PNT24UQcIdt28qg/0424Rczt3LhQgTfkmeVS7H3IXjlFqawfku5tLL5gLtC1Ibpc5dxwwKmxaFxQFv1cX3CZ2iEnY/w9YE6fXaPP7fhlzX65hNORyJttDv6O7eLc79XudpLnM0fUKTiHRM0jzW0V1Zk4uTFVRyVxEdwjSRBTF1mKxaDJG27K6YNIxgy0BKCrjDFWji86mZ6DqKahuq/XUyExQveeCJk6+HSAA2m100WoJ4xir0KQ6CWwBY2LBc6a0KN3O2AtlzC6F5imPH+lYbqfbBNR8U7yM2Zzm+RxRq3nMEceotc0uouBkbh6yBCwDdwS2U8kZQtrJ65JZRkNspxlLhkYk2VONBiJY+sHLMnzxw1/+dve62b2Gf2MldZVMxqxeluuXoB2zesWfGVPVKhth7JDtr2VghviBGYITsAtBfMP9Az5x5/Gv/n7UUphbAxgqlV0Mf7+Y7f7jcqQzi3PE0lXQPz7n8fq1dN8UUjNRsAplQnfNMqwyrM4LeDpB+5WIWC3QAxOzMv6BoZsgCCcFQSzqEvvhb/H4RDVqV7x6xw/7QmJo+szUVO1tmno7LWvTVeLJ5RgYPTzxdz50fLZp6+hva5ySXErRXRaVSFL0+xUrO/YgAwNtt7YzNqMR0I0HvexuFQlLaZ3rvS2eITtB1Z+LykQOkwV0m4sJc5vVdcp2BSaq+tWY88J+RwNdMn1Cr9irMRLGZUrvq83nPzEfKglvEwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"32f2aded5a9487503501a74172b23cd7\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4947", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:334B:A2A76F4:53D70B0C", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 19:45:45 GMT", "date": "Tue, 29 Jul 2014 02:46:37 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-07-29T02:46:37"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e2f8f7bcdf1b7c1fc293ecb318661fd8\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4946", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:334B:A2A772E:53D70B0D", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Tue, 29 Jul 2014 02:44:32 GMT", "date": "Tue, 29 Jul 2014 02:46:37 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "recorded_at": "2014-07-29T02:46:37"}, {"request": {"body": {"string": "{\"title\": \"removed duplicate documentation\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "44", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PATCH", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e81d250fe15da46d1d64d9f8d9fe1f62\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4945", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:334B:A2A775A:53D70B0D", "cache-control": "private, max-age=60, s-maxage=60", "date": "Tue, 29 Jul 2014 02:46:37 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406604823"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls/241"}, "recorded_at": "2014-07-29T02:46:37"}], "recorded_with": "betamax/0.3.2"} \ No newline at end of file diff --git a/tests/integration/test_pulls.py b/tests/integration/test_pulls.py index 37756608a..0a702f94c 100644 --- a/tests/integration/test_pulls.py +++ b/tests/integration/test_pulls.py @@ -90,3 +90,11 @@ def test_review_comments(self): p = self.get_pull_request() for comment in p.review_comments(): assert isinstance(comment, github3.pulls.ReviewComment) + + def test_update(self): + """Show that one can update an open Pull Request.""" + self.basic_login() + cassette_name = self.cassette_name('update') + with self.recorder.use_cassette(cassette_name): + p = self.get_pull_request(num=241) + assert p.update(p.title) is True From c49b12467284bae51de6d0499de43f184af62dcc Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 29 Jul 2014 22:13:56 -0500 Subject: [PATCH 263/972] Rename and remove some Gist attributes --- HISTORY.rst | 8 ++++++++ github3/gists/gist.py | 8 ++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 756c65ed3..3ee187470 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -175,6 +175,14 @@ Old name New attribute name ``PullRequest.review_comments`` ``review_comments_count`` =============================== ========================== +- The Gist API has changed. + + - The ``forks`` and ``files`` attributes that used to keep count of the + number of ``forks`` and ``files`` have been **removed**. + + - The ``comments`` attribute which provided the number of comments on a + gist, has been **renamed** to ``comments_count``. + 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ diff --git a/github3/gists/gist.py b/github3/gists/gist.py index b29b38487..32913416a 100644 --- a/github3/gists/gist.py +++ b/github3/gists/gist.py @@ -42,7 +42,7 @@ class Gist(GitHubCore): def __init__(self, data, session=None): super(Gist, self).__init__(data, session) #: Number of comments on this gist - self.comments = data.get('comments', 0) + self.comments_count = data.get('comments', 0) #: Unique id for this gist. self.id = '{0}'.format(data.get('id', '')) @@ -59,8 +59,6 @@ def __init__(self, data, session=None): self.public = data.get('public') self._forks = data.get('forks', []) - #: The number of forks of this gist. - self.forks = len(self._forks) #: Git URL to pull this gist, e.g., git://gist.github.com/1.git self.git_pull_url = data.get('git_pull_url', '') @@ -80,14 +78,12 @@ def __init__(self, data, session=None): self.owner = User(owner, self) if owner else None self._files = [GistFile(data['files'][f]) for f in data['files']] - #: Number of files in this gist. - self.files = len(self._files) #: History of this gist, list of #: :class:`GistHistory ` self.history = [GistHistory(h, self) for h in data.get('history', [])] - ## New urls + # New urls #: Comments URL (not a template) self.comments_url = data.get('comments_url', '') From 7c5664f3c4f5cd59d7452a12a13fba21b5c0e183 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 29 Jul 2014 22:30:14 -0500 Subject: [PATCH 264/972] Fix integration test that was broken as a result of the last commit --- tests/integration/test_github.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 8bb2024a4..5d9a61ced 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -34,7 +34,6 @@ def test_create_gist(self): ) assert isinstance(g, github3.gists.Gist) - assert g.files == 1 assert g.is_public() is True def test_create_issue(self): From 8db521f2567ef7226910738da6597b8b06cfc43d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 29 Jul 2014 22:30:36 -0500 Subject: [PATCH 265/972] Rename Gist#iter_comments to Gist#comments --- github3/gists/gist.py | 2 +- tests/cassettes/Gist_comments.json | 1 + tests/integration/test_gists.py | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 tests/cassettes/Gist_comments.json diff --git a/github3/gists/gist.py b/github3/gists/gist.py index 32913416a..ed401e5d4 100644 --- a/github3/gists/gist.py +++ b/github3/gists/gist.py @@ -184,7 +184,7 @@ def is_starred(self): url = self._build_url('star', base_url=self._api) return self._boolean(self._get(url), 204, 404) - def iter_comments(self, number=-1, etag=None): + def comments(self, number=-1, etag=None): """List comments on this gist. :param int number: (optional), number of comments to iterate over. diff --git a/tests/cassettes/Gist_comments.json b/tests/cassettes/Gist_comments.json new file mode 100644 index 000000000..53b65cf57 --- /dev/null +++ b/tests/cassettes/Gist_comments.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/gists/3342247"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"66f359ceda608b324d21d4f858f7cce7\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2F43:E3A68:53D8667C", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 29 Jul 2014 08:22:50 GMT", "date": "Wed, 30 Jul 2014 03:29:00 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406694481"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/3342247"}, "recorded_at": "2014-07-30T03:29:01"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/gists/3342247/comments?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"2728dd7b4354a02304b0a5240e404c25\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2F43:E3AC8:53D8667C", "cache-control": "public, max-age=60, s-maxage=60", "date": "Wed, 30 Jul 2014 03:29:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406694481"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/3342247/comments?per_page=100"}, "recorded_at": "2014-07-30T03:29:02"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index 2e1ef20b1..77e5cbc80 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -4,6 +4,15 @@ class TestGist(IntegrationHelper): + def test_comments(self): + """Show that a user can iterate over the comments on a gist.""" + cassette_name = self.cassette_name('comments') + with self.recorder.use_cassette(cassette_name): + gist = self.gh.gist(3342247) + assert gist is not None + for comment in gist.comments(): + assert isinstance(comment, github3.gists.comment.GistComment) + def test_iter_commits(self): cassette_name = self.cassette_name('commits') with self.recorder.use_cassette(cassette_name, From 9d12167f2c4b038290f85ff730544104923d9112 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 29 Jul 2014 22:31:23 -0500 Subject: [PATCH 266/972] Update HISTORY for Gist#comments --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index 3ee187470..e8c622142 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -33,6 +33,7 @@ Old name New name ``github3.iter_user_repos`` ``github3.repositories_by`` ``github3.iter_starred`` ``github3.starred_by`` ``github3.iter_subscriptions`` ``github3.subscriptions_for`` +``Gist#iter_comments`` ``Gist#comments`` ``GitHub#iter_all_repos`` ``GitHub#all_repositories`` ``GitHub#iter_all_users`` ``GitHub#all_users`` ``GitHub#iter_authorizations`` ``GitHub#authorizations`` From efa2fe1d7ccfe65a28bb8698a3dc2adfa6628caf Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 29 Jul 2014 22:35:09 -0500 Subject: [PATCH 267/972] Add docstrings to Gist integration tests @esacteksab would be so proud --- tests/integration/test_gists.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index 77e5cbc80..90107fcb9 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -1,9 +1,14 @@ +# -*- coding: utf-8 -*- +"""Integration tests for methods implemented on Gist.""" from .helper import IntegrationHelper import github3 class TestGist(IntegrationHelper): + + """Gist integration tests.""" + def test_comments(self): """Show that a user can iterate over the comments on a gist.""" cassette_name = self.cassette_name('comments') @@ -14,6 +19,7 @@ def test_comments(self): assert isinstance(comment, github3.gists.comment.GistComment) def test_iter_commits(self): + """Show that a user can iterate over the commits in a gist.""" cassette_name = self.cassette_name('commits') with self.recorder.use_cassette(cassette_name, preserve_exact_body_bytes=True): @@ -23,6 +29,7 @@ def test_iter_commits(self): assert isinstance(commit, github3.gists.history.GistHistory) def test_iter_forks(self): + """Show that a user can iterate over the forks of a gist.""" cassette_name = self.cassette_name('forks') with self.recorder.use_cassette(cassette_name, preserve_exact_body_bytes=True): From 32c0632526905d008ddb6985f79bd39bc268e707 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 29 Jul 2014 22:48:22 -0500 Subject: [PATCH 268/972] Remove old Gist#iter_comments unit test --- tests/test_gists.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index 9e745643a..73ed7e165 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -91,16 +91,6 @@ def test_is_starred(self): assert self.gist.is_starred() self.mock_assertions() - def test_iter_comments(self): - self.response('gist_comment', _iter=True) - self.get(self.api + '/comments') - self.conf = {'params': {'per_page': 100}} - - c = next(self.gist.iter_comments()) - - assert isinstance(c, gists.comment.GistComment) - self.mock_assertions() - def test_iter_commits(self): self.response('gist_history', _iter=True) self.get(self.api + '/commits') From 5be33d6f26b61ee21910f0f05771d792f4329ba2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 29 Jul 2014 22:48:38 -0500 Subject: [PATCH 269/972] Create an example data factory --- tests/unit/helper.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index e0cad6510..4d79f7a77 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -5,6 +5,7 @@ import mock import github3 import json +import os.path import unittest @@ -20,6 +21,19 @@ def url_for(path=''): return url_for +def create_example_data_helper(example_filename): + """A function to generate example data helpers.""" + directory = os.path.dirname(__file__) + example = os.path.join(directory, 'pull_request_example') + + def data_helper(): + with open(example) as fd: + data = json.load(fd) + return data + + return data_helper + + def build_url(self, *args, **kwargs): """A function to proxy to the actual GitHubSession#build_url method.""" # We want to assert what is happening with the actual calls to the From 58d64603b7aa168e77b6f76edd51bb3091c6e4e7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 29 Jul 2014 22:51:44 -0500 Subject: [PATCH 270/972] Begin unit testing Gists Currently the gist does some odd things that may need to be fixed to properly unittest the methods on this class. --- tests/unit/gist_example_data | 103 +++++++++++++++++++++++++++++++++++ tests/unit/test_gists.py | 32 +++++++++++ 2 files changed, 135 insertions(+) create mode 100644 tests/unit/gist_example_data create mode 100644 tests/unit/test_gists.py diff --git a/tests/unit/gist_example_data b/tests/unit/gist_example_data new file mode 100644 index 000000000..023e84385 --- /dev/null +++ b/tests/unit/gist_example_data @@ -0,0 +1,103 @@ +{ + "url": "https://api.github.com/gists/b4c7ac7be6e591d0d155", + "forks_url": "https://api.github.com/gists/e0db40cc9d6f3e41f200/forks", + "commits_url": "https://api.github.com/gists/9718be7b23c5c6c7c955/commits", + "id": "1", + "description": "description of gist", + "public": true, + "owner": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "user": null, + "files": { + "ring.erl": { + "size": 932, + "raw_url": "https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl", + "type": "text/plain", + "language": "Erlang", + "truncated": false, + "content": "contents of gist" + } + }, + "comments": 0, + "comments_url": "https://api.github.com/gists/1b5c3f1e2ce99c5be5de/comments/", + "html_url": "https://gist.github.com/1", + "git_pull_url": "git://gist.github.com/1.git", + "git_push_url": "git@gist.github.com:1.git", + "created_at": "2010-04-14T02:15:15Z", + "updated_at": "2011-06-20T11:34:15Z", + "forks": [ + { + "user": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "url": "https://api.github.com/gists/162b7c2b3aedd7bdd5f1", + "id": 1, + "created_at": "2011-04-14T16:00:49Z", + "updated_at": "2011-04-14T16:00:49Z" + } + ], + "history": [ + { + "url": "https://api.github.com/gists/9051afb61a66575905e7", + "version": "57a7f021a713b1c5a6a199b54cc514735d2d462f", + "user": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "change_status": { + "deletions": 0, + "additions": 180, + "total": 180 + }, + "committed_at": "2010-04-14T02:15:15Z" + } + ] +} diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py new file mode 100644 index 000000000..a90d24a9b --- /dev/null +++ b/tests/unit/test_gists.py @@ -0,0 +1,32 @@ +"""Unit tests for the github3.gists module.""" +import github3 +import pytest + +from .helper import (create_example_data_helper, create_url_helper, + UnitIteratorHelper) + +gist_example_data = create_example_data_helper('gist_example_data') + +url_for = create_url_helper( + 'https://api.github.com/gists/b4c7ac7be6e591d0d155' +) + + +class TestGistIterators(UnitIteratorHelper): + + """Test Gist methods that return Iterators.""" + + described_class = github3.gists.Gist + example_data = gist_example_data() + + @pytest.mark.xfail + def test_comments(self): + """Show a user can iterate over the comments on a gist.""" + i = self.instance.comments() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('comments'), + params={'per_page': 100}, + headers={} + ) From 9053cf4d86e8ebfbc57a250e15a5c2e784068cda Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 07:31:11 -0500 Subject: [PATCH 271/972] Fix my case of the stupids from last night --- tests/unit/helper.py | 2 +- tests/unit/test_gists.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit/helper.py b/tests/unit/helper.py index 4d79f7a77..17b32953a 100644 --- a/tests/unit/helper.py +++ b/tests/unit/helper.py @@ -24,7 +24,7 @@ def url_for(path=''): def create_example_data_helper(example_filename): """A function to generate example data helpers.""" directory = os.path.dirname(__file__) - example = os.path.join(directory, 'pull_request_example') + example = os.path.join(directory, example_filename) def data_helper(): with open(example) as fd: diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index a90d24a9b..d2350294e 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -1,6 +1,5 @@ """Unit tests for the github3.gists module.""" import github3 -import pytest from .helper import (create_example_data_helper, create_url_helper, UnitIteratorHelper) @@ -19,7 +18,6 @@ class TestGistIterators(UnitIteratorHelper): described_class = github3.gists.Gist example_data = gist_example_data() - @pytest.mark.xfail def test_comments(self): """Show a user can iterate over the comments on a gist.""" i = self.instance.comments() From 58f3066b4555c66eca02d3b0747c95f3b22f3012 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 20:15:49 -0500 Subject: [PATCH 272/972] Rename Gist#iter_commits to Gist#commits --- github3/gists/gist.py | 6 +++--- tests/integration/test_gists.py | 4 ++-- tests/test_gists.py | 9 --------- tests/unit/test_gists.py | 12 ++++++++++++ 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/github3/gists/gist.py b/github3/gists/gist.py index ed401e5d4..d0eba0cd8 100644 --- a/github3/gists/gist.py +++ b/github3/gists/gist.py @@ -185,7 +185,7 @@ def is_starred(self): return self._boolean(self._get(url), 204, 404) def comments(self, number=-1, etag=None): - """List comments on this gist. + """Iterate over comments on this gist. :param int number: (optional), number of comments to iterate over. Default: -1 will iterate over all comments on the gist @@ -198,8 +198,8 @@ def comments(self, number=-1, etag=None): url = self._build_url('comments', base_url=self._api) return self._iter(int(number), url, GistComment, etag=etag) - def iter_commits(self, number=-1, etag=None): - """Iter over the commits on this gist. + def commits(self, number=-1, etag=None): + """Iterate over the commits on this gist. These commits will be requested from the API and should be the same as what is in ``Gist.history``. diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index 90107fcb9..06717b871 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -18,14 +18,14 @@ def test_comments(self): for comment in gist.comments(): assert isinstance(comment, github3.gists.comment.GistComment) - def test_iter_commits(self): + def test_commits(self): """Show that a user can iterate over the commits in a gist.""" cassette_name = self.cassette_name('commits') with self.recorder.use_cassette(cassette_name, preserve_exact_body_bytes=True): gist = self.gh.gist(1834570) assert gist is not None - for commit in gist.iter_commits(): + for commit in gist.commits(): assert isinstance(commit, github3.gists.history.GistHistory) def test_iter_forks(self): diff --git a/tests/test_gists.py b/tests/test_gists.py index 73ed7e165..998758c47 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -91,15 +91,6 @@ def test_is_starred(self): assert self.gist.is_starred() self.mock_assertions() - def test_iter_commits(self): - self.response('gist_history', _iter=True) - self.get(self.api + '/commits') - self.conf = {'params': {'per_page': 100}} - - h = next(self.gist.iter_commits()) - assert isinstance(h, gists.history.GistHistory) - self.mock_assertions() - def test_iter_files(self): gist_file = next(self.gist.iter_files()) assert gist_file == self.gist._files[0] diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index d2350294e..3673d6df0 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -28,3 +28,15 @@ def test_comments(self): params={'per_page': 100}, headers={} ) + + def test_commits(self): + """Show a user can iterate over the commits on a gist.""" + i = self.instance.commits() + self.get_next(i) + + + self.session.get.assert_called_once_with( + url_for('commits'), + params={'per_page': 100}, + headers={} + ) From 16b292a90361c162dcea4cbe7f2412dc1dd59a8d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 20:19:12 -0500 Subject: [PATCH 273/972] Update HISTORY for Gist#commits --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index e8c622142..659a21f47 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -34,6 +34,7 @@ Old name New name ``github3.iter_starred`` ``github3.starred_by`` ``github3.iter_subscriptions`` ``github3.subscriptions_for`` ``Gist#iter_comments`` ``Gist#comments`` +``Gist#iter_commits`` ``Gist#commits`` ``GitHub#iter_all_repos`` ``GitHub#all_repositories`` ``GitHub#iter_all_users`` ``GitHub#all_users`` ``GitHub#iter_authorizations`` ``GitHub#authorizations`` From 603462f961df981c887517a4a527ba5728f2219a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 20:22:51 -0500 Subject: [PATCH 274/972] Rename Gist#iter_files to Gist#files --- github3/gists/gist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github3/gists/gist.py b/github3/gists/gist.py index d0eba0cd8..46fb25712 100644 --- a/github3/gists/gist.py +++ b/github3/gists/gist.py @@ -222,7 +222,7 @@ def commits(self, number=-1, etag=None): url = self._build_url('commits', base_url=self._api) return self._iter(int(number), url, GistHistory) - def iter_files(self): + def files(self): """Iterator over the files stored in this gist. :returns: generator of :class`GistFile ` From 3ce1c313c3609cc3325e0ec854ce42c45d68b23a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 20:35:52 -0500 Subject: [PATCH 275/972] Migrate unit test for Gist#files --- tests/test_gists.py | 6 ------ tests/unit/test_gists.py | 8 +++++++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index 998758c47..8203e46a7 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -91,12 +91,6 @@ def test_is_starred(self): assert self.gist.is_starred() self.mock_assertions() - def test_iter_files(self): - gist_file = next(self.gist.iter_files()) - assert gist_file == self.gist._files[0] - assert isinstance(gist_file, gists.file.GistFile) - assert repr(gist_file).startswith(' 0 + + assert self.session.get.called is False From 7a7f7e3f1c247963c288f0547e4a19e165bdbb26 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 20:36:23 -0500 Subject: [PATCH 276/972] Update HISTORY with changes to Gist#files --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index 659a21f47..fb158d948 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -35,6 +35,7 @@ Old name New name ``github3.iter_subscriptions`` ``github3.subscriptions_for`` ``Gist#iter_comments`` ``Gist#comments`` ``Gist#iter_commits`` ``Gist#commits`` +``Gist#iter_files`` ``Gist#files`` ``GitHub#iter_all_repos`` ``GitHub#all_repositories`` ``GitHub#iter_all_users`` ``GitHub#all_users`` ``GitHub#iter_authorizations`` ``GitHub#authorizations`` From 0fec498d060d17d1f9062916d50c72c476d3612a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 20:42:49 -0500 Subject: [PATCH 277/972] Rename Gist#iter_forks to Gist#forks --- HISTORY.rst | 1 + github3/gists/gist.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index fb158d948..980763b2d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -36,6 +36,7 @@ Old name New name ``Gist#iter_comments`` ``Gist#comments`` ``Gist#iter_commits`` ``Gist#commits`` ``Gist#iter_files`` ``Gist#files`` +``Gist#iter_forks`` ``Gist#forks`` ``GitHub#iter_all_repos`` ``GitHub#all_repositories`` ``GitHub#iter_all_users`` ``GitHub#all_users`` ``GitHub#iter_authorizations`` ``GitHub#authorizations`` diff --git a/github3/gists/gist.py b/github3/gists/gist.py index 46fb25712..d8f1efbcf 100644 --- a/github3/gists/gist.py +++ b/github3/gists/gist.py @@ -230,7 +230,7 @@ def files(self): """ return iter(self._files) - def iter_forks(self, number=-1, etag=None): + def forks(self, number=-1, etag=None): """Iterator of forks of this gist. .. versionchanged:: 0.9 From f658e89fc86b61b6ddf1dea64062f60dc7ea207a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 20:43:02 -0500 Subject: [PATCH 278/972] Update tests for Gist#forks --- tests/integration/test_gists.py | 4 ++-- tests/unit/test_gists.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index 06717b871..a5c5d7c41 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -28,12 +28,12 @@ def test_commits(self): for commit in gist.commits(): assert isinstance(commit, github3.gists.history.GistHistory) - def test_iter_forks(self): + def test_forks(self): """Show that a user can iterate over the forks of a gist.""" cassette_name = self.cassette_name('forks') with self.recorder.use_cassette(cassette_name, preserve_exact_body_bytes=True): gist = self.gh.gist(1834570) assert gist is not None - for commit in gist.iter_forks(): + for commit in gist.forks(): assert isinstance(commit, github3.gists.gist.Gist) diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index b65db6b59..a56781916 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -46,3 +46,14 @@ def test_files(self): assert len(files) > 0 assert self.session.get.called is False + + def test_forks(self): + """Show that a user can iterate over a gist's forks.""" + i = self.instance.forks() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('forks'), + params={'per_page': 100}, + headers={} + ) From 0277c414b856f9b7662641f51e313738433fb69a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 21:44:53 -0500 Subject: [PATCH 279/972] Add integration test for GitHub#create_comment --- tests/cassettes/Gist_create_comment.json | 1 + tests/integration/test_gists.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/cassettes/Gist_create_comment.json diff --git a/tests/cassettes/Gist_create_comment.json b/tests/cassettes/Gist_create_comment.json new file mode 100644 index 000000000..0cabdfd10 --- /dev/null +++ b/tests/cassettes/Gist_create_comment.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/gists/f396190a0d0047be791b"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1Y247iRhD9FcsvgOLB7Ru+SKv9hShKXjIzQn0zdGLalm+zsyz/nqq2hwECk4XVSnkACbC7XaeruqpOVXtrd3VhZ/a6basmc11aqflKteuOzXm5cVeqaRs3D9KFlxJKBCFhzGScesx27Lys/26WN8q7RhpQYJmNam/HGeUBSQkw5IKuYNOy6oriRF2079Dec9I4D+gDQrO+HWHdbm5ZH3daFbKxsy0o0bR4482rV7zHa003Egw/mnLs9rXCUVpVheK0VaV2vzxUr+261ABYUL3q6Aqf+PVtrKYvl23rGlnzUrdStyYwGrXa0F7VXeOHZ+PDBTh3wfLQ5zQScRB6AWPMpx73WZynvuA0CWgUSxmLyMTZ3i7HbtRXUM1LUrCj7jToL8G3OS0aiQFj1ADVq7JRaFljfbKmvmOFjrVwrMSxPDJ70k9ayNza0GqZA8R0quD+i2P1tOjkbJY9aQs+KrfMOPxae7hxDudr2Xa1tibZxPplEB3kxnEDNoy8/U4m879KpaewMH7N4o4ldbeRNdgxnRDzoZQxziezmb3D2BrM9+c1u+BWM3XBrXXHXo+d+tsw8hNcSqKIBHkYBAHJvXQhchpzEoUp91IWeST384Smecr3Lh0VH10aBR+7dEM5OPN4j570oaMfjx39jI4GqXkDgd5OJ5PZHHZ9/gIcthw8K0rrW+9Y6ht6CPy9B5srzYtOyM+WGpzX49KDp3FAaoF//ZOGK+NUazKxd+CvqmOQVe8RWUuM0CXFoPSJFz4Q7yHwfidBFpCMRH+Cc7pKnH8mhDjPIh+fEbLhtaowpAEIBpDbINQh9T1AgBS0Mw0k9j5xM/vukR27fNEIvLWLcqVw4cPcBiWQVv2QJAFxbNrTltanq5rBZuTRU6bo3EH4c//JA7RVPWIYtuZemATRQiQQMn4kF6nvxQmT0hNpQHke48Z9VJ9wseaIjEDiLM/uS9qJdXlZFOULoJwadVwI/70QFLBREpYcrpVe3YgCklu3bNcS9hZM2uFGYem9Gs5IbU3yLZVAnAZ8U0NwXrmP7igHamF87LZuLavSAHZsH6bXK3gkDWhlvaJafTUV6no0kMYeAlW7XthIgbTsMceu3qBBbOtWteopf8WtqSWXqofNvhHyRB4QxzL+B+Y+1sVWLqnYYJqaaghcNPRR2eMzBD54vayhMXjcjmxxT+rr2OOe1Del4T2p3w5MZ+rELUndQ0EaugA4bSU+y5kvA04lZ14qSeCniZ+H8YJwmAv9WEgO7DCchC41IkkWhthk8DX0/nIJ9N525kzRli2FI6AfQ3kXYmiosfnGfqSQhpftLAWm+bCCmMJz/iTw3SbsnDtv3ZsR90wO3ZuRw7cUZzbof9KMvPPWIglSxtIcjolCeKkPp0JOUwI0FsFIwOBVUsS5SP+Tt94OUJd4C94RHNAW3B2wFvkB1vpuA3bPu38AzZr/9kYTAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"f65b4b92180e20e798e82877d229d085\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4950", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0444:105A761:53D9A6A1", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Thu, 31 Jul 2014 02:07:51 GMT", "date": "Thu, 31 Jul 2014 02:14:57 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406774636"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/f396190a0d0047be791b"}, "recorded_at": "2014-07-31T02:14:58"}, {"request": {"body": {"string": "{\"body\": \"```ruby\\n mac.split('').map.with_index do |v, i|\\n positions.include?(i) ? ':' + v : v\\n end\\n ```\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "156", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "POST", "uri": "https://api.github.com/gists/f396190a0d0047be791b/comments"}, "response": {"body": {"string": "{\"url\":\"https://api.github.com/gists/f396190a0d0047be791b/comments/1273063\",\"id\":1273063,\"user\":{\"login\":\"sigmavirus24\",\"id\":240830,\"avatar_url\":\"https://avatars.githubusercontent.com/u/240830?v=1\",\"gravatar_id\":\"c148356d89f925e692178bee1d93acf7\",\"url\":\"https://api.github.com/users/sigmavirus24\",\"html_url\":\"https://github.com/sigmavirus24\",\"followers_url\":\"https://api.github.com/users/sigmavirus24/followers\",\"following_url\":\"https://api.github.com/users/sigmavirus24/following{/other_user}\",\"gists_url\":\"https://api.github.com/users/sigmavirus24/gists{/gist_id}\",\"starred_url\":\"https://api.github.com/users/sigmavirus24/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/sigmavirus24/subscriptions\",\"organizations_url\":\"https://api.github.com/users/sigmavirus24/orgs\",\"repos_url\":\"https://api.github.com/users/sigmavirus24/repos\",\"events_url\":\"https://api.github.com/users/sigmavirus24/events{/privacy}\",\"received_events_url\":\"https://api.github.com/users/sigmavirus24/received_events\",\"type\":\"User\",\"site_admin\":false},\"created_at\":\"2014-07-31T02:14:57Z\",\"updated_at\":\"2014-07-31T02:14:57Z\",\"body_html\":\"
            mac.split('').map.with_index do |v, i|\\n              positions.include?(i) ? ':' + v : v\\n            end\\n            ```\\n
\",\"body_text\":\"mac.split('').map.with_index do |v, i|\\n positions.include?(i) ? ':' + v : v\\n end\\n ```\",\"body\":\"```ruby\\n mac.split('').map.with_index do |v, i|\\n positions.include?(i) ? ':' + v : v\\n end\\n ```\"}", "encoding": "utf-8"}, "headers": {"content-length": "2373", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7269f9243c3750db3c4325413a76724a\"", "location": "https://api.github.com/gists/f396190a0d0047be791b/comments/1273063", "access-control-allow-credentials": "true", "status": "201 Created", "x-ratelimit-remaining": "4949", "x-github-media-type": "github.v3; param=full; 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": "48A0C4D3:0444:105A7CA:53D9A6A1", "cache-control": "private, max-age=60, s-maxage=60", "date": "Thu, 31 Jul 2014 02:14:58 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406774636"}, "status": {"message": "Created", "code": 201}, "url": "https://api.github.com/gists/f396190a0d0047be791b/comments"}, "recorded_at": "2014-07-31T02:14:58"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index a5c5d7c41..cf77fbadc 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -18,6 +18,20 @@ def test_comments(self): for comment in gist.comments(): assert isinstance(comment, github3.gists.comment.GistComment) + def test_create_comment(self): + """Show that a user can comment on a gist.""" + self.basic_login() + cassette_name = self.cassette_name('create_comment') + with self.recorder.use_cassette(cassette_name): + gist = self.gh.gist('f396190a0d0047be791b') + assert gist is not None + c = gist.create_comment("""```ruby + mac.split('').map.with_index do |v, i| + positions.include?(i) ? ':' + v : v + end + ```""") + assert isinstance(c, github3.gists.comment.GistComment) + def test_commits(self): """Show that a user can iterate over the commits in a gist.""" cassette_name = self.cassette_name('commits') From c982ba861d1f352677e8f96ab76e31172794ad1a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 22:03:23 -0500 Subject: [PATCH 280/972] Add integration test for Gist#delete --- tests/cassettes/Gist_delete.json | 1 + tests/integration/test_gists.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/cassettes/Gist_delete.json diff --git a/tests/cassettes/Gist_delete.json b/tests/cassettes/Gist_delete.json new file mode 100644 index 000000000..4fb8c8dcd --- /dev/null +++ b/tests/cassettes/Gist_delete.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "{\"files\": {\"filename.py\": {\"content\": \"# -*- coding: utf-8 -*-\"}}, \"description\": \"Title\", \"public\": true}", "encoding": "utf-8"}, "headers": {"Content-Length": "106", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "POST", "uri": "https://api.github.com/gists"}, "response": {"body": {"string": "{\"url\":\"https://api.github.com/gists/d842f429f59500ce30bc\",\"forks_url\":\"https://api.github.com/gists/d842f429f59500ce30bc/forks\",\"commits_url\":\"https://api.github.com/gists/d842f429f59500ce30bc/commits\",\"id\":\"d842f429f59500ce30bc\",\"git_pull_url\":\"https://gist.github.com/d842f429f59500ce30bc.git\",\"git_push_url\":\"https://gist.github.com/d842f429f59500ce30bc.git\",\"html_url\":\"https://gist.github.com/d842f429f59500ce30bc\",\"files\":{\"filename.py\":{\"filename\":\"filename.py\",\"type\":\"application/x-python\",\"language\":\"Python\",\"raw_url\":\"https://gist.githubusercontent.com/sigmavirus24/d842f429f59500ce30bc/raw/7c68785e9d0b64e1fe46403c4316a9fe1ea36eeb/filename.py\",\"size\":23,\"truncated\":false,\"content\":\"# -*- coding: utf-8 -*-\"}},\"public\":true,\"created_at\":\"2014-07-31T03:03:02Z\",\"updated_at\":\"2014-07-31T03:03:02Z\",\"description\":\"Title\",\"comments\":0,\"user\":null,\"comments_url\":\"https://api.github.com/gists/d842f429f59500ce30bc/comments\",\"owner\":{\"login\":\"sigmavirus24\",\"id\":240830,\"avatar_url\":\"https://avatars.githubusercontent.com/u/240830?v=1\",\"gravatar_id\":\"c148356d89f925e692178bee1d93acf7\",\"url\":\"https://api.github.com/users/sigmavirus24\",\"html_url\":\"https://github.com/sigmavirus24\",\"followers_url\":\"https://api.github.com/users/sigmavirus24/followers\",\"following_url\":\"https://api.github.com/users/sigmavirus24/following{/other_user}\",\"gists_url\":\"https://api.github.com/users/sigmavirus24/gists{/gist_id}\",\"starred_url\":\"https://api.github.com/users/sigmavirus24/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/sigmavirus24/subscriptions\",\"organizations_url\":\"https://api.github.com/users/sigmavirus24/orgs\",\"repos_url\":\"https://api.github.com/users/sigmavirus24/repos\",\"events_url\":\"https://api.github.com/users/sigmavirus24/events{/privacy}\",\"received_events_url\":\"https://api.github.com/users/sigmavirus24/received_events\",\"type\":\"User\",\"site_admin\":false},\"forks\":[],\"history\":[{\"user\":{\"login\":\"sigmavirus24\",\"id\":240830,\"avatar_url\":\"https://avatars.githubusercontent.com/u/240830?v=1\",\"gravatar_id\":\"c148356d89f925e692178bee1d93acf7\",\"url\":\"https://api.github.com/users/sigmavirus24\",\"html_url\":\"https://github.com/sigmavirus24\",\"followers_url\":\"https://api.github.com/users/sigmavirus24/followers\",\"following_url\":\"https://api.github.com/users/sigmavirus24/following{/other_user}\",\"gists_url\":\"https://api.github.com/users/sigmavirus24/gists{/gist_id}\",\"starred_url\":\"https://api.github.com/users/sigmavirus24/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/sigmavirus24/subscriptions\",\"organizations_url\":\"https://api.github.com/users/sigmavirus24/orgs\",\"repos_url\":\"https://api.github.com/users/sigmavirus24/repos\",\"events_url\":\"https://api.github.com/users/sigmavirus24/events{/privacy}\",\"received_events_url\":\"https://api.github.com/users/sigmavirus24/received_events\",\"type\":\"User\",\"site_admin\":false},\"version\":\"9ad42df347d4216eeed0192fd9cb7a96c0a8b2e2\",\"committed_at\":\"2014-07-31T03:03:02Z\",\"change_status\":{\"total\":1,\"additions\":1,\"deletions\":0},\"url\":\"https://api.github.com/gists/d842f429f59500ce30bc/9ad42df347d4216eeed0192fd9cb7a96c0a8b2e2\"}]}", "encoding": "utf-8"}, "headers": {"content-length": "3121", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"6e2ca7b3e002098c28bf83f23fd0a774\"", "location": "https://api.github.com/gists/d842f429f59500ce30bc", "access-control-allow-credentials": "true", "status": "201 Created", "x-ratelimit-remaining": "4957", "x-github-media-type": "github.v3; param=full; 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": "48A0C4D3:2B9C:136C679:53D9B1E6", "cache-control": "private, max-age=60, s-maxage=60", "date": "Thu, 31 Jul 2014 03:03:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406779215"}, "status": {"message": "Created", "code": 201}, "url": "https://api.github.com/gists"}, "recorded_at": "2014-07-31T03:03:03"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/gists/d842f429f59500ce30bc"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4956", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:2B9C:136C6F9:53D9B1E6", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "access-control-allow-credentials": "true", "date": "Thu, 31 Jul 2014 03:03:02 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406779215"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/gists/d842f429f59500ce30bc"}, "recorded_at": "2014-07-31T03:03:03"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index cf77fbadc..fabd63719 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -42,6 +42,21 @@ def test_commits(self): for commit in gist.commits(): assert isinstance(commit, github3.gists.history.GistHistory) + def test_delete(self): + """Show that a user can delete a gist.""" + self.basic_login() + cassette_name = self.cassette_name('delete') + with self.recorder.use_cassette(cassette_name): + gist = self.gh.create_gist( + 'Title', { + 'filename.py': { + 'content': '# -*- coding: utf-8 -*-' + } + } + ) + assert isinstance(gist, github3.gists.Gist) + assert gist.delete() is True + def test_forks(self): """Show that a user can iterate over the forks of a gist.""" cassette_name = self.cassette_name('forks') From afff98aa3e54c2faacf27c44c5afbc39f78b0abd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 22:06:54 -0500 Subject: [PATCH 281/972] Add integration test for Gist#edit --- tests/cassettes/Gist_edit.json | 1 + tests/integration/test_gists.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/cassettes/Gist_edit.json diff --git a/tests/cassettes/Gist_edit.json b/tests/cassettes/Gist_edit.json new file mode 100644 index 000000000..7a8d3e358 --- /dev/null +++ b/tests/cassettes/Gist_edit.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/gists/6647085"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1WTXObMBT8Kx16dSLxYQzMdHrstYf00kzGI4SMNcXASILUYfzfuxI4td00CT7nxod2tXpv39MbvE5VXuZtjWl1Rghr5W0pzbbLb3mzI6XURpM4jlY0WXoLb9OoX3r9fghxAABBtpNmFnSCACwLKPwrAvrWbVdVFzqs1lPtE8B+AscI0ttZoK3ZvXMXGxtZCe1lg3uo2U7ctvvTV5zh9M/CM/tW4CNr20pyZmRTk9837d5smxp0FavLjpV2xffjN8Ue/6+/00LxpjaiNi53WpY71kvV6SA6ppCAgRQ8pjSlImEbn/M83OSBv/TDlObLuKABZwkP4iDk5Fyulk8Qk0C36mroFcjKhlVa2Oy6bSH18/HxcFh4bZfjZF4GgF2khAWtmV0XUD+8oelN4N/RMFsmWRj9xKG7tnhzTSE0V7K18QLRN2T90500lZhcBh3IAgUX4uFlNYwy2s/+mGNd6z9HtvCax9pyDV7VlNLuehrbyaBBRJMQ27KeGaYuN3If9WTPy0x1ZAR/7b/41qpq4nC+536UhEhMkm7SYCniNPBXSS6EX6Qh45uVjdprJWw302dmAOJFYz9X/cXpNk1VNY9guTzUea/4dyNU/4TEluOzrMsrWYAcSGO2ArHFkQ42ULY7zaZzqMG1trUsLI9GbhScOTOOZMJBlvXHYSBKtI0j7PJnj84XeIYGW6NKVssn1yHmswFtLWylzQc7FNCif7t6Xsj/CBtIq2TP+N6GRgkuZI9gX0l5gQfj1EZ/2HJH6KURa1bsbJm67oQ+NF5C2f0DjI+sNwp9+X6YGsRHUc/rHh9FfVUZfhT1caZ8oU9cU9Q9LqRxBBBpkQaUxckq5jQKWBzThNLQL3BPYsyIeUrTKOcFusM4U74yhSztFMK3mL3EGu3ddG6iM41hmJJ93O5FIV0fdm+FqMT0RtFnXr0/zkZp8m7Nh4fDHyJP7tukCwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"b2938072ca18da0aa70195d0c99e1129\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4952", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B9A:E1FC44:53D9B2B7", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Thu, 31 Jul 2014 03:01:14 GMT", "date": "Thu, 31 Jul 2014 03:06:31 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406779215"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/6647085"}, "recorded_at": "2014-07-31T03:06:32"}, {"request": {"body": {"string": "{\"files\": {\"filename.py\": {\"content\": \"# New content\"}, \"new_file.py\": {\"content\": \"# New file content\"}}, \"description\": \"Updated description\"}", "encoding": "utf-8"}, "headers": {"Content-Length": "144", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PATCH", "uri": "https://api.github.com/gists/6647085"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1XwY6bMBD9lRW9Jmsbg7GRqv5B1UN76aqKjG0SqwQQmKS7Uf69Y2C7JJutwl7aQ25geM/j55nn8SHomiJIg41zdZsiJGt7v7Zu02X3qtqitW1dixiLEszjYBHkVfOzXV0PQT0AgEC2tW4WdIQA2GqI8CUIiG9Vd0VxFoePdRr7CPBDwDGA2s0s0MZtr5zFa2ML0wbpoX8o5dbc14/TV1jD9MsicI+1gUFZ14VV0tmqRL+W9aPbVCXQFbJcd3Lt//jyPNbI/dvxd61pVFU6U7p+71q73sqdbbo2jJ63EAEDMsKwSBksNNVZIo0iPFI8xnGmciy5kSJnoUwEOg23tU8QDKEQeNOVELCBbcll0Rq/vf28EOuHu89mf/f8flwEpdmvPNFrNaZf/p0alGYhYTmnRkisVCYSpjRNcsNklhvOMeZJkmmKTsMd1eDXqOGX/yIJaFJ3GWx5kIKQXrzGeDFX0usXYkKXWCxD8hXTNOYpjb5DNnS1PvknWuJkSft/MEsp8f9o06rG1j6RgOjbgLibjg51CBsFeYqBFDImSEsopZcPc4rbV2hPtgiqfem5DkFRra2ffpp9YwmHEeYUppU76WRzPlE/2I4FfJ7LHRrAn3YfiS/mZuTonUGRiNOYaS5yEcaGiZAkPDOGaEGlyhMv399Mzk/WnpQLIC6W/h9fPFtdXhVFtQeW80WduunricAfRyRMOTzbcv1OFkAeUOU2BrSFJR29UN6/Z9P1qENv/iurPU8Le9NAis7UEY04CMvnx/GAGlNXPWGX/UnW+QGeoIGtataytE+9h85nA7RPYR/afHCPArTZ+UqYLdAAO6C6sTupHr00jVHG7kDsd1Ke4YFxPGi++XIH6a0zK6m3vkx7+wZDGo7p9OEHJD7setXAyfVwGA3iVtTz3ONW1O8qw1tRP3fdF86J9xT1Dg6koRdgRhCiWAg9HpcZ5oZGitJQx5KFimjCGBaxSii4w9B1T9uRS62G2kB3alZg767re15XOQn3CGgOpda29+EgDX1PUpjxjYDP/PX8OLlsoKtjPi5uRnXrPtCForl1H9P78AWB/pPu48WojNAixJJxuIThKJRgTHABo0RDQw8XI6YEFlGm9EWjOrs3xf5O9JZRkROjgreJUeF5RnV1zMcfx98UgZEJbxEAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"fa53cf0028fb0237a651184f60618cf3\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4951", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B9A:E1FC84:53D9B2B7", "cache-control": "private, max-age=60, s-maxage=60", "date": "Thu, 31 Jul 2014 03:06:31 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406779215"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/6647085"}, "recorded_at": "2014-07-31T03:06:32"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index fabd63719..272e656d3 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -57,6 +57,22 @@ def test_delete(self): assert isinstance(gist, github3.gists.Gist) assert gist.delete() is True + def test_edit(self): + """Show that a user can edit the contents of a gist.""" + self.basic_login() + cassette_name = self.cassette_name('edit') + with self.recorder.use_cassette(cassette_name): + gist = self.gh.gist(6647085) + assert gist is not None + assert gist.edit('Updated description', files={ + 'filename.py': { + 'content': '# New content', + }, + 'new_file.py': { + 'content': '# New file content', + }, + }) is True + def test_forks(self): """Show that a user can iterate over the forks of a gist.""" cassette_name = self.cassette_name('forks') From 8a14f3f63c4a4bb7085c6851f11e0a8fa8c8e1e5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 22:15:25 -0500 Subject: [PATCH 282/972] Add integration test for Gist#fork --- tests/cassettes/Gist_fork.json | 1 + tests/integration/test_gists.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/cassettes/Gist_fork.json diff --git a/tests/cassettes/Gist_fork.json b/tests/cassettes/Gist_fork.json new file mode 100644 index 000000000..694b7c4f8 --- /dev/null +++ b/tests/cassettes/Gist_fork.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/gists/8de9b9b0ae2e45383d85"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1XXW+bMBT9K8xPqUQLmISvqdp/qLaXNVVkjCFWiUHGJGkR/333Qto1WdouPDcPUcA+x/fz+KYjrS5JQtbG1E3iOKyWN4U06za94dXGKWRjGifKRJzGqcsEFfOFH/lZtCA2ySv92Kwm4p0BDSxwzEaa6TwHPDDJDBx5x1bwaVW3ZXliLvr31t9zaFwH9pGhWU9nWJvNlPMx0rIUDUk6MKIx+ODdmL3BF/ig2EaA58drNjFPNb42Ym+cumRSAVHJVNGyAt4rCIZNNNu970/bCM0rZYQyQzE0RmzFY8lSJR/P1oQDdA7NmJsxToOUhrmIaRyJPMxZwGiU+vMgigLuxp7wh9r664tNGvkMdnmUgum6VZwZAQnNWdkIrJLBDvAHrLIakyWJ5klyx78v1VLlytqAg7Mrq1sqCz6lMNbeurXuYI8Su9lCXsFGXBm/ofislSWVpSEgYubalue2r2jcV2upTKm+zZak65fEtvZXI7Rfqp70vU3qNi0lJwkYiwZqgQavGNpIXW9+7YbX3vyn5ydemHjxb4h+W2cf7KEu7slEw7WsjawUEB36AzyH9LvAACl5yR0WPi5M7sAXAjik2ikk7khZFVAoCXmba1jH1qJhGAU2YVtmmD49dHjZHFrptHBaZ8D+2N56wFXoA8XQr9T3OQ1j7npUpIyHMWWMRe4ij4OApzzEsH2kUHhWc1SagDjbaa+iduJbXpVltQOWU5+OpfDfg0DCDkg4cvwtVTGRBZCdU5m1gNCCSz0GCsX3YroB1Q3dtZIZ8jSQGg2leWEcIagDDszC6ug7R4u6Ggjb9LVILzfwCA1slS6Yks8MS/5yNkDjLYKmXQ4eUIAGXfu0kc7kf4R1DmjFlvEnDI0WXMgtBHsi5QkeGA8y/gs7H0XSiBXLNtikgzSCEI03aXL/AIUPWa/0E0nuu4NWfLU0iMw7082ZlH619JQm/Grpl4H5TElNaektXEfjBBBmUey7OZ/Hi1B4qUsjP/DTORWBOxcRS+dpEItY4Dw+TsKfDSF8jSPPCsTdtMNMaSrD4C9ADFd7lslBhYenTMAUNT65oDIf3h7v/09w/tuB/qH/AxWm/ZGODAAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"63ecc08581c85ca5ace520b7ff23273f\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4934", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:338A:133BBED:53D9B489", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Wed, 30 Jul 2014 23:18:26 GMT", "date": "Thu, 31 Jul 2014 03:14:17 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406779215"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/8de9b9b0ae2e45383d85"}, "recorded_at": "2014-07-31T03:14:18"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "POST", "uri": "https://api.github.com/gists/8de9b9b0ae2e45383d85/forks"}, "response": {"body": {"string": "{\"url\":\"https://api.github.com/gists/333767d04fc2ab362406\",\"forks_url\":\"https://api.github.com/gists/333767d04fc2ab362406/forks\",\"commits_url\":\"https://api.github.com/gists/333767d04fc2ab362406/commits\",\"id\":\"333767d04fc2ab362406\",\"git_pull_url\":\"https://gist.github.com/333767d04fc2ab362406.git\",\"git_push_url\":\"https://gist.github.com/333767d04fc2ab362406.git\",\"html_url\":\"https://gist.github.com/333767d04fc2ab362406\",\"files\":{\"gistfile1.txt\":{\"filename\":\"gistfile1.txt\",\"type\":\"text/plain\",\"language\":null,\"raw_url\":\"https://gist.githubusercontent.com/sigmavirus24/333767d04fc2ab362406/raw/2da0dac26b27fe9298ef7fa6a28b346886c091e3/gistfile1.txt\",\"size\":122}},\"public\":true,\"created_at\":\"2014-07-31T03:14:18Z\",\"updated_at\":\"2014-07-31T03:14:18Z\",\"description\":\"\",\"comments\":0,\"user\":null,\"comments_url\":\"https://api.github.com/gists/333767d04fc2ab362406/comments\",\"owner\":{\"login\":\"sigmavirus24\",\"id\":240830,\"avatar_url\":\"https://avatars.githubusercontent.com/u/240830?v=1\",\"gravatar_id\":\"c148356d89f925e692178bee1d93acf7\",\"url\":\"https://api.github.com/users/sigmavirus24\",\"html_url\":\"https://github.com/sigmavirus24\",\"followers_url\":\"https://api.github.com/users/sigmavirus24/followers\",\"following_url\":\"https://api.github.com/users/sigmavirus24/following{/other_user}\",\"gists_url\":\"https://api.github.com/users/sigmavirus24/gists{/gist_id}\",\"starred_url\":\"https://api.github.com/users/sigmavirus24/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/sigmavirus24/subscriptions\",\"organizations_url\":\"https://api.github.com/users/sigmavirus24/orgs\",\"repos_url\":\"https://api.github.com/users/sigmavirus24/repos\",\"events_url\":\"https://api.github.com/users/sigmavirus24/events{/privacy}\",\"received_events_url\":\"https://api.github.com/users/sigmavirus24/received_events\",\"type\":\"User\",\"site_admin\":false}}", "encoding": "utf-8"}, "headers": {"content-length": "1826", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"631b6b5b81e4358cd134f73e4d35a07d\"", "location": "https://api.github.com/gists/333767d04fc2ab362406", "access-control-allow-credentials": "true", "status": "201 Created", "x-ratelimit-remaining": "4933", "x-github-media-type": "github.v3; param=full; 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": "48A0C4D3:338A:133BC30:53D9B489", "cache-control": "private, max-age=60, s-maxage=60", "date": "Thu, 31 Jul 2014 03:14:18 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406779215"}, "status": {"message": "Created", "code": 201}, "url": "https://api.github.com/gists/8de9b9b0ae2e45383d85/forks"}, "recorded_at": "2014-07-31T03:14:18"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index 272e656d3..922bc4f41 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -73,6 +73,17 @@ def test_edit(self): }, }) is True + def test_fork(self): + """Show that a user can fork another user's gist.""" + self.basic_login() + cassette_name = self.cassette_name('fork') + with self.recorder.use_cassette(cassette_name): + gist = self.gh.gist('8de9b9b0ae2e45383d85') + assert gist is not None + forked = gist.fork() + assert isinstance(forked, github3.gists.Gist) + assert str(forked.owner) == 'sigmavirus24' + def test_forks(self): """Show that a user can iterate over the forks of a gist.""" cassette_name = self.cassette_name('forks') From fa13d443b9bb00b1473da54bfd0f71f285c78f47 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 22:19:36 -0500 Subject: [PATCH 283/972] Remove Gist#is_public --- HISTORY.rst | 3 +++ github3/gists/gist.py | 8 -------- tests/integration/test_github.py | 2 +- tests/test_gists.py | 3 --- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 980763b2d..e78ed40b0 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -187,6 +187,9 @@ Old name New attribute name - The ``comments`` attribute which provided the number of comments on a gist, has been **renamed** to ``comments_count``. + - The ``is_public`` method has been removed since it just returned the + ``Gist.public`` attribute. + 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ diff --git a/github3/gists/gist.py b/github3/gists/gist.py index d8f1efbcf..29dcf4ea3 100644 --- a/github3/gists/gist.py +++ b/github3/gists/gist.py @@ -166,14 +166,6 @@ def fork(self): json = self._json(self._post(url), 201) return Gist(json, self) if json else None - def is_public(self): - """Check to see if this gist is public or not. - - :returns: bool -- True if public, False if private - - """ - return self.public - @requires_auth def is_starred(self): """Check to see if this gist is starred by the authenticated user. diff --git a/tests/integration/test_github.py b/tests/integration/test_github.py index 5d9a61ced..c1ad506cd 100644 --- a/tests/integration/test_github.py +++ b/tests/integration/test_github.py @@ -34,7 +34,7 @@ def test_create_gist(self): ) assert isinstance(g, github3.gists.Gist) - assert g.is_public() is True + assert g.public is True def test_create_issue(self): """Test the ability of a GitHub instance to create a new issue.""" diff --git a/tests/test_gists.py b/tests/test_gists.py index 8203e46a7..b485dc680 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -77,9 +77,6 @@ def test_fork(self): assert isinstance(self.gist.fork(), gists.Gist) self.mock_assertions() - def test_is_public(self): - assert self.gist.is_public() == self.gist.public - def test_is_starred(self): self.response('', 204) self.get(self.api + '/star') From b4835e1c2ca766769e8901585e3df9b6400b39b6 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 22:23:18 -0500 Subject: [PATCH 284/972] Add integration test for Gist#is_starred --- tests/cassettes/Gist_is_starred.json | 1 + tests/integration/test_gists.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Gist_is_starred.json diff --git a/tests/cassettes/Gist_is_starred.json b/tests/cassettes/Gist_is_starred.json new file mode 100644 index 000000000..6b4e2f4ac --- /dev/null +++ b/tests/cassettes/Gist_is_starred.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/gists/1834570"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d39e80b70eefea20ec0e920a9af40e51\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4932", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:338A:1373F7C:53D9B68C", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Wed, 30 Jul 2014 14:32:08 GMT", "date": "Thu, 31 Jul 2014 03:22:53 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406779215"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/1834570"}, "recorded_at": "2014-07-31T03:22:53"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/gists/1834570/star"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "access-control-allow-credentials": "true", "x-ratelimit-remaining": "4931", "x-github-media-type": "github.v3; param=full; format=json", "content-security-policy": "default-src 'none'", "x-content-type-options": "nosniff", "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": "48A0C4D3:338A:1373FEF:53D9B68D", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "server": "GitHub.com", "last-modified": "Wed, 30 Jul 2014 14:32:08 GMT", "x-ratelimit-limit": "5000", "etag": "\"70ef4686023745672cf0bd2f7ba79189\"", "x-served-by": "132026e9262a0093e437f99db5f1e499", "cache-control": "private, max-age=60, s-maxage=60", "date": "Thu, 31 Jul 2014 03:22:53 GMT", "x-frame-options": "deny", "access-control-allow-origin": "*", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406779215"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/gists/1834570/star"}, "recorded_at": "2014-07-31T03:22:53"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index 922bc4f41..c3effb5d6 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -93,3 +93,12 @@ def test_forks(self): assert gist is not None for commit in gist.forks(): assert isinstance(commit, github3.gists.gist.Gist) + + def test_is_starred(self): + """Show that a user can check if they've starred a gist.""" + self.basic_login() + cassette_name = self.cassette_name('is_starred') + with self.recorder.use_cassette(cassette_name): + gist = self.gh.gist(1834570) + assert gist is not None + assert gist.is_starred() is True From 43245968184601165e6ac7c3b625a58e75328c53 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 22:25:29 -0500 Subject: [PATCH 285/972] Add integration test for Gist#star --- tests/cassettes/Gist_star.json | 1 + tests/integration/test_gists.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Gist_star.json diff --git a/tests/cassettes/Gist_star.json b/tests/cassettes/Gist_star.json new file mode 100644 index 000000000..f1666f926 --- /dev/null +++ b/tests/cassettes/Gist_star.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/gists/8de9b9b0ae2e45383d85"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1X23KjOBD9FUZPSZUnCAlz25qaf5iafdn1lEsIYauCBQXCSYbi37clnCw45GIyj8mDK0I6R92t7qNWh9q6QAnaa101ieuySt7spN636Q0vD+5ONrpxo0zEaZxiJojw1zSiWbRGK5SX9W2zXYh3LRpYYJuD1Mt5Tnhgkhk48oKt4NO2aovizFzj39jfObSZB/aBodkvZ9jrw5L9TaRlIRqUdGBEo83Au9H32nwwA8UOAjyfzq2QfqjMZy3utVsVTCogKpjatWwH3xUEY4VqdveyP20jal4qLZS2ydBocRS3BUuVvJ3NCRfoXJIxnDFOgpSEuYhJHIk8zFnASJRSP4iigOPYE9Tm1v++rFAjf4NdHiFget0qzrSAA81Z0QiTJdYO8AeschqdJUnNk+QH/2ujNipXzgEcvLp2uo1y4K8Q2rl3vjk/YI0Sd1dreQ0LzczwC8nnbB2pnBoCIq7wyvFw+4Q266paKl2oL1cb1PUbtHLurwdov1E96vsVqtq0kBwlYKwxsBbG4C0zNhLs+V9x+NXzf3o08cLEi/+B6LdV9nwN9X5iWOMnXmTWZKLhtay0LBUQneoDPIfjx8AAR/J4dibxzcTiCnwkgE3KO2WIO1SUO0iUBI3PGuZNaZEwjIIVYkemWX2+qf3YnErpPHFa12K/H795wLWrTxS2XgmlnIQxxx4RKeNhTBhjEV7ncRDwlIcmbK8plNmrmaQmIGYr7UnUznzLy6Io74Dl3KepFD7fCCTshIQth/+l2i1kAWTnlnovILTgUm8CZcT3YjqL6mx1bWVmeBo4mhpS88I4QlAtDswy2dF3bi2q0hK26VOSXm7gBA1sZb1jSv5mJuUvZwO0uUWMaZeDLQrQoGtvFtLM+Q+wzgWtODL+YEJTCy7kEYK9kPIMD4wnGf/bVL4RSS22LDuYIrXSCEI03KTJv93rlTLc5ZTSMAgz7OecsJQGxMcB8A7CMqp/uTuwo6zbhvgwbevfxxEFDVomABY8qwDc8yO6DrIozmOyFkFMvDBKhfCymDKev1cBpga/oQDTxZcpwAj7AQV4zvIhBRjTfUwBxkx/UAEmtGP9WKQAY7aLFWAMXqAAY/gfUoCpRRMFeZcC2Jv0hcqebUzOmo63G5P+F9yqcKWU9QOySmMbkc9+AeL+wtNp5r747BeW3PCf/cLja3wmpZb0C0fodYfnRQiXLsU59+N1KLwUk4gGNPWJCLAvIpb6aRCLWJjH/vDMfuuFw/fmPbWFe0O39sGqS80KlMTQNmSZtC2eHWUCnmjDCEML82prOjQuc09z990O9L/6/wCY5OC46xAAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"1a3a837f1e7a4807ce4f6e280a0e8969\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4930", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6940:E5EE9C:53D9B707", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Thu, 31 Jul 2014 03:14:18 GMT", "date": "Thu, 31 Jul 2014 03:24:56 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406779215"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/8de9b9b0ae2e45383d85"}, "recorded_at": "2014-07-31T03:24:56"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "PUT", "uri": "https://api.github.com/gists/8de9b9b0ae2e45383d85/star"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4929", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:6940:E5EF19:53D9B708", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "access-control-allow-credentials": "true", "date": "Thu, 31 Jul 2014 03:24:56 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406779215"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/gists/8de9b9b0ae2e45383d85/star"}, "recorded_at": "2014-07-31T03:24:57"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index c3effb5d6..80cbf309d 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -102,3 +102,12 @@ def test_is_starred(self): gist = self.gh.gist(1834570) assert gist is not None assert gist.is_starred() is True + + def test_star(self): + """Show that a user can star a gist.""" + self.basic_login() + cassette_name = self.cassette_name('star') + with self.recorder.use_cassette(cassette_name): + gist = self.gh.gist('8de9b9b0ae2e45383d85') + assert gist is not None + assert gist.star() is True From ae15256b66c1978d81de0ddf5281171d08610632 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 30 Jul 2014 22:26:52 -0500 Subject: [PATCH 286/972] Add integration test for Gist#unstar --- tests/cassettes/Gist_unstar.json | 1 + tests/integration/test_gists.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Gist_unstar.json diff --git a/tests/cassettes/Gist_unstar.json b/tests/cassettes/Gist_unstar.json new file mode 100644 index 000000000..a8b81c508 --- /dev/null +++ b/tests/cassettes/Gist_unstar.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/gists/8de9b9b0ae2e45383d85"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1X23KjOBD9FUZPSZUnCAlz25qaf5iafdn1lEsIYauCBQXCSYbi37clnCw45GIyj8mDK0I6R92t7qNWh9q6QAnaa101ieuySt7spN636Q0vD+5ONrpxo0zEaZxiJojw1zSiWbRGK5SX9W2zXYh3LRpYYJuD1Mt5Tnhgkhk48oKt4NO2aovizFzj39jfObSZB/aBodkvZ9jrw5L9TaRlIRqUdGBEo83Au9H32nwwA8UOAjyfzq2QfqjMZy3utVsVTCogKpjatWwH3xUEY4VqdveyP20jal4qLZS2ydBocRS3BUuVvJ3NCRfoXJIxnDFOgpSEuYhJHIk8zFnASJRSP4iigOPYE9Tm1v++rFAjf4NdHiFget0qzrSAA81Z0QiTJdYO8AeschqdJUnNk+QH/2ujNipXzgEcvLp2uo1y4K8Q2rl3vjk/YI0Sd1dreQ0LzczwC8nnbB2pnBoCIq7wyvFw+4Q266paKl2oL1cb1PUbtHLurwdov1E96vsVqtq0kBwlYKwxsBbG4C0zNhLs+V9x+NXzf3o08cLEi/+B6LdV9nwN9X5iWOMnXmTWZKLhtay0LBUQneoDPIfjx8AAR/J4dibxzcTiCnwkgE3KO2WIO1SUO0iUBI3PGuZNaZEwjIIVYkemWX2+qf3YnErpPHFa12K/H795wLWrTxS2XgmlnIQxxx4RKeNhTBhjEV7ncRDwlIcmbK8plNmrmaQmIGYr7UnUznzLy6Io74Dl3KepFD7fCCTshIQth/+l2i1kAWTnlnovILTgUm8CZcT3YjqL6mx1bWVmeBo4mhpS88I4QlAtDswy2dF3bi2q0hK26VOSXm7gBA1sZb1jSv5mJuUvZwO0uUWMaZeDLQrQoGtvFtLM+Q+wzgWtODL+YEJTCy7kEYK9kPIMD4wnGf/bVL4RSS22LDuYIrXSCEI03KTJv93rlTLc5ZTSMAgz7OecsJQGxMcB8A7CMqp/uTuwo6zbhvgwbevfxxEFDVomABY8qwDc8yO6DrIozmOyFkFMvDBKhfCymDKev1cBpga/oQDTxZcpwAj7AQV4zvIhBRjTfUwBxkx/UAEmtGP9WKQAY7aLFWAMXqAAY/gfUoCpRRMFeZcC2Jv0hcqebUzOmo63G5P+F9yqcKWU9QOySmMbkc9+AeL+wtNp5r747BeW3PCf/cLja3wmpZb0C0fodYfnRQiXLsU59+N1KLwUk4gGNPWJCLAvIpb6aRCLWJjH/vDMfuuFw/fmPbWFe0O39sGqS80KlMTQNmSZtC2eHWUCnmjDCEML82prOjQuc09z990O9L/6/wCY5OC46xAAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"1a3a837f1e7a4807ce4f6e280a0e8969\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4928", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B9C:1405CD3:53D9B765", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Thu, 31 Jul 2014 03:14:18 GMT", "date": "Thu, 31 Jul 2014 03:26:29 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406779215"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/gists/8de9b9b0ae2e45383d85"}, "recorded_at": "2014-07-31T03:26:30"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Content-Length": "0", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "DELETE", "uri": "https://api.github.com/gists/8de9b9b0ae2e45383d85/star"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "204 No Content", "x-ratelimit-remaining": "4927", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "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": "48A0C4D3:2B9C:1405D1C:53D9B765", "strict-transport-security": "max-age=31536000; includeSubdomains", "vary": "Accept-Encoding", "server": "GitHub.com", "access-control-allow-origin": "*", "x-ratelimit-limit": "5000", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "access-control-allow-credentials": "true", "date": "Thu, 31 Jul 2014 03:26:29 GMT", "x-frame-options": "deny", "x-xss-protection": "1; mode=block", "x-ratelimit-reset": "1406779215"}, "status": {"message": "No Content", "code": 204}, "url": "https://api.github.com/gists/8de9b9b0ae2e45383d85/star"}, "recorded_at": "2014-07-31T03:26:30"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_gists.py b/tests/integration/test_gists.py index 80cbf309d..72ee54b00 100644 --- a/tests/integration/test_gists.py +++ b/tests/integration/test_gists.py @@ -111,3 +111,12 @@ def test_star(self): gist = self.gh.gist('8de9b9b0ae2e45383d85') assert gist is not None assert gist.star() is True + + def test_unstar(self): + """Show that a user can unstar a gist.""" + self.basic_login() + cassette_name = self.cassette_name('unstar') + with self.recorder.use_cassette(cassette_name): + gist = self.gh.gist('8de9b9b0ae2e45383d85') + assert gist is not None + assert gist.unstar() is True From 1f1fcc1b341f5eace70d083eb2d71175fd864bae Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 08:09:19 -0500 Subject: [PATCH 287/972] Add Gist#create_comment unit test --- tests/unit/test_gists.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index a56781916..2095de2b9 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -2,7 +2,7 @@ import github3 from .helper import (create_example_data_helper, create_url_helper, - UnitIteratorHelper) + UnitHelper, UnitIteratorHelper) gist_example_data = create_example_data_helper('gist_example_data') @@ -11,6 +11,21 @@ ) +class TestGist(UnitHelper): + + """Test regular Gist methods.""" + + described_class = github3.gists.Gist + example_data = gist_example_data() + + def test_create_comment(self): + """Show that a user can create a comment.""" + self.instance.create_comment('some comment text') + + self.post_called_with(url_for('comments'), + data={'body': 'some comment text'}) + + class TestGistIterators(UnitIteratorHelper): """Test Gist methods that return Iterators.""" From 9a1c16a9b42e722ab62dc7bff0e4e91bfa6d63a2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 08:24:48 -0500 Subject: [PATCH 288/972] Finish migrating Gist#create_comment unit test --- tests/test_gists.py | 15 --------------- tests/unit/test_gists.py | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index b485dc680..ee54f493e 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -19,21 +19,6 @@ def test_str(self): def test_repr(self): assert repr(self.gist) == ''.format(self.gist) - def test_create_comment(self): - self.response('gist_comment', 201) - self.post(self.api + '/comments') - self.conf = {'data': {'body': 'bar'}} - - self.assertRaises(github3.GitHubError, self.gist.create_comment) - self.login() - - assert self.gist.create_comment(None) is None - assert self.gist.create_comment('') is None - self.not_called() - assert isinstance(self.gist.create_comment('bar'), - gists.comment.GistComment) - self.mock_assertions() - def test_delete(self): self.response('', 204) self.delete(self.api) diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index 2095de2b9..4b4742f11 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -1,4 +1,5 @@ """Unit tests for the github3.gists module.""" +import pytest import github3 from .helper import (create_example_data_helper, create_url_helper, @@ -26,6 +27,23 @@ def test_create_comment(self): data={'body': 'some comment text'}) +class TestGistRequiresAuth(UnitHelper): + + """Test Gist methods which require authentication.""" + + described_class = github3.gists.Gist + example_data = gist_example_data() + + def after_setup(self): + """Disable authentication.""" + self.session.has_auth.return_value = False + + def test_create_comment(self): + """Show that a user needs to authenticate to create a comment.""" + with pytest.raises(github3.GitHubError): + self.instance.create_comment('foo') + + class TestGistIterators(UnitIteratorHelper): """Test Gist methods that return Iterators.""" From 2349a1899aeaea43f9bdfe35404b375277437762 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 08:29:41 -0500 Subject: [PATCH 289/972] Migrate unit test for Gist#delete --- tests/test_gists.py | 12 ------------ tests/unit/test_gists.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index ee54f493e..d5e3f2d95 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -19,18 +19,6 @@ def test_str(self): def test_repr(self): assert repr(self.gist) == ''.format(self.gist) - def test_delete(self): - self.response('', 204) - self.delete(self.api) - self.conf = {} - - self.assertRaises(github3.GitHubError, self.gist.delete) - - self.not_called() - self.login() - assert self.gist.delete() - self.mock_assertions() - def test_edit(self): self.response('gist', 200) self.patch(self.api) diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index 4b4742f11..023bed902 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -26,6 +26,12 @@ def test_create_comment(self): self.post_called_with(url_for('comments'), data={'body': 'some comment text'}) + def test_delete(self): + """Show that a user can delete a gist.""" + self.instance.delete() + + self.session.delete.assert_called_once_with(url_for()) + class TestGistRequiresAuth(UnitHelper): @@ -43,6 +49,11 @@ def test_create_comment(self): with pytest.raises(github3.GitHubError): self.instance.create_comment('foo') + def test_delete(self): + """Show that a user needs to authenticate to delete a gist.""" + with pytest.raises(github3.GitHubError): + self.instance.delete() + class TestGistIterators(UnitIteratorHelper): From 8916de3e24931ab7165157fbe6da6014ecdfc782 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 08:31:31 -0500 Subject: [PATCH 290/972] Add an extra unit test for Gist#create_comment --- tests/unit/test_gists.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index 023bed902..996a7193a 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -26,6 +26,12 @@ def test_create_comment(self): self.post_called_with(url_for('comments'), data={'body': 'some comment text'}) + def test_create_comment_requires_a_body(self): + """Show that a user cannot create an empty comment.""" + self.instance.create_comment(None) + + assert self.session.post.called is False + def test_delete(self): """Show that a user can delete a gist.""" self.instance.delete() From 6265422aec3a7bca5b6b479482d76e33e5e3dba0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 08:39:43 -0500 Subject: [PATCH 291/972] Migrate Gist#edit tests --- tests/test_gists.py | 19 ------------------- tests/unit/test_gists.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index d5e3f2d95..4fca1efd1 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -19,25 +19,6 @@ def test_str(self): def test_repr(self): assert repr(self.gist) == ''.format(self.gist) - def test_edit(self): - self.response('gist', 200) - self.patch(self.api) - self.conf = { - 'data': { - 'description': 'desc', - 'files': {'file1': {'content': 'foo bar'}} - } - } - - self.assertRaises(github3.GitHubError, self.gist.edit) - - self.login() - assert self.gist.edit() is False - self.not_called() - - assert self.gist.edit(**self.conf['data']) - self.mock_assertions() - def test_fork(self): self.response('gist', 201) self.post(self.api + '/forks') diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index 996a7193a..16109597c 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -38,6 +38,20 @@ def test_delete(self): self.session.delete.assert_called_once_with(url_for()) + def test_edit(self): + """Show that a user can edit a gist.""" + desc = 'description' + files = {'file': {'content': 'foo content bar'}} + self.instance.edit(desc, files) + + self.patch_called_with(url_for(), data={desc: desc, 'files': files}) + + def test_edit_requires_changes(self): + """Show that a user must change something to edit a gist.""" + self.instance.edit() + + assert self.session.patch.called is False + class TestGistRequiresAuth(UnitHelper): @@ -60,6 +74,11 @@ def test_delete(self): with pytest.raises(github3.GitHubError): self.instance.delete() + def test_edit(self): + """Show that a user needs to authenticate to edit a gist.""" + with pytest.raises(github3.GitHubError): + self.instance.edit() + class TestGistIterators(UnitIteratorHelper): From 7cadc9d610f24943070d23978ec0b00e7504bdcc Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 09:14:54 -0500 Subject: [PATCH 292/972] Migrate Gist#fork unit tests --- tests/test_gists.py | 12 ------------ tests/unit/test_gists.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index 4fca1efd1..926906297 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -19,18 +19,6 @@ def test_str(self): def test_repr(self): assert repr(self.gist) == ''.format(self.gist) - def test_fork(self): - self.response('gist', 201) - self.post(self.api + '/forks') - self.conf = {} - - self.assertRaises(github3.GitHubError, self.gist.fork) - - self.not_called() - self.login() - assert isinstance(self.gist.fork(), gists.Gist) - self.mock_assertions() - def test_is_starred(self): self.response('', 204) self.get(self.api + '/star') diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index 16109597c..1a95ea2cd 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -52,6 +52,12 @@ def test_edit_requires_changes(self): assert self.session.patch.called is False + def test_fork(self): + """Show that a user can fork a gist.""" + self.instance.fork() + + self.session.post.assert_called_once_with(url_for('forks'), None) + class TestGistRequiresAuth(UnitHelper): @@ -79,6 +85,11 @@ def test_edit(self): with pytest.raises(github3.GitHubError): self.instance.edit() + def test_fork(self): + """Show that a user needs to authenticate to fork a gist.""" + with pytest.raises(github3.GitHubError): + self.instance.fork() + class TestGistIterators(UnitIteratorHelper): From c5c6a5730fad8eb736abe5d526c4cd9b94f5b650 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 18:03:37 -0500 Subject: [PATCH 293/972] Migrate Gist#is_starred unit test --- tests/test_gists.py | 11 ----------- tests/unit/test_gists.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index 926906297..17f4680b1 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -19,17 +19,6 @@ def test_str(self): def test_repr(self): assert repr(self.gist) == ''.format(self.gist) - def test_is_starred(self): - self.response('', 204) - self.get(self.api + '/star') - - self.assertRaises(github3.GitHubError, self.gist.is_starred) - - self.not_called() - self.login() - assert self.gist.is_starred() - self.mock_assertions() - def test_refresh(self): self.response('gist', 200) self.get(self.api) diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index 1a95ea2cd..0a90a8961 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -58,6 +58,12 @@ def test_fork(self): self.session.post.assert_called_once_with(url_for('forks'), None) + def test_is_starred(self): + """Show that a user can check if they starred a gist.""" + self.instance.is_starred() + + self.session.get.assert_called_once_with(url_for('star')) + class TestGistRequiresAuth(UnitHelper): @@ -90,6 +96,11 @@ def test_fork(self): with pytest.raises(github3.GitHubError): self.instance.fork() + def test_is_starred(self): + """Show that a user needs to auth to check if they starred a gist.""" + with pytest.raises(github3.GitHubError): + self.instance.is_starred() + class TestGistIterators(UnitIteratorHelper): From 2525f7fa9cfb52b410cfc8a9e249efc800eb0ea4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 18:16:34 -0500 Subject: [PATCH 294/972] Replace Gist#star unit test --- tests/test_gists.py | 19 ------------------- tests/unit/test_gists.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index 17f4680b1..cd4cb7746 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -19,25 +19,6 @@ def test_str(self): def test_repr(self): assert repr(self.gist) == ''.format(self.gist) - def test_refresh(self): - self.response('gist', 200) - self.get(self.api) - - assert self.gist.refresh() is self.gist - self.mock_assertions() - - def test_star(self): - self.response('', 204) - self.put(self.api + '/star') - self.conf = {} - - self.assertRaises(github3.GitHubError, self.gist.star) - - self.not_called() - self.login() - assert self.gist.star() - self.mock_assertions() - def test_unstar(self): self.response('', 204) self.delete(self.api + '/star') diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index 0a90a8961..3c8140b53 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -64,6 +64,12 @@ def test_is_starred(self): self.session.get.assert_called_once_with(url_for('star')) + def test_star(self): + """Show that a user can star a gist.""" + self.instance.star() + + self.session.put.assert_called_once_with(url_for('star')) + class TestGistRequiresAuth(UnitHelper): @@ -101,6 +107,11 @@ def test_is_starred(self): with pytest.raises(github3.GitHubError): self.instance.is_starred() + def test_star(self): + """Show that a user needs to be authenticated to star a gist.""" + with pytest.raises(github3.GitHubError): + self.instance.star() + class TestGistIterators(UnitIteratorHelper): From 89bca8f006c6fd4201d4062cce28f786a146d4c2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 18:18:57 -0500 Subject: [PATCH 295/972] Migrate Gist#unstar unit test --- tests/test_gists.py | 12 ------------ tests/unit/test_gists.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index cd4cb7746..16ce98866 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -19,18 +19,6 @@ def test_str(self): def test_repr(self): assert repr(self.gist) == ''.format(self.gist) - def test_unstar(self): - self.response('', 204) - self.delete(self.api + '/star') - self.conf = {} - - self.assertRaises(github3.GitHubError, self.gist.unstar) - - self.not_called() - self.login() - assert self.gist.unstar() - self.mock_assertions() - # As opposed to creating an all new class for this def test_history(self): hist = self.gist.history[0] diff --git a/tests/unit/test_gists.py b/tests/unit/test_gists.py index 3c8140b53..d70b8d14c 100644 --- a/tests/unit/test_gists.py +++ b/tests/unit/test_gists.py @@ -70,6 +70,12 @@ def test_star(self): self.session.put.assert_called_once_with(url_for('star')) + def test_unstar(self): + """Show that a user can unstar a gist.""" + self.instance.unstar() + + self.session.delete.assert_called_once_with(url_for('star')) + class TestGistRequiresAuth(UnitHelper): @@ -112,6 +118,11 @@ def test_star(self): with pytest.raises(github3.GitHubError): self.instance.star() + def test_unstar(self): + """Show that a user needs to be authenticated to unstar a gist.""" + with pytest.raises(github3.GitHubError): + self.instance.unstar() + class TestGistIterators(UnitIteratorHelper): From bf0129f8515f63a2450314a8b499938d1f88640b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 19:39:03 -0500 Subject: [PATCH 296/972] Migrate last unit test from Gist --- tests/test_gists.py | 12 ------------ tests/unit/test_gists.py | 4 ++++ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/test_gists.py b/tests/test_gists.py index 16ce98866..7bf0dda8b 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -13,12 +13,6 @@ def setUp(self): super(TestGist, self).setUp() self.gist = gists.Gist(self.gist.to_json(), self.g) - def test_str(self): - assert str(self.gist) == str(self.gist.id) - - def test_repr(self): - assert repr(self.gist) == ''.format(self.gist) - # As opposed to creating an all new class for this def test_history(self): hist = self.gist.history[0] @@ -31,12 +25,6 @@ def test_history(self): assert repr(hist).startswith(' Date: Thu, 31 Jul 2014 19:55:02 -0500 Subject: [PATCH 297/972] Rename Repository#iter_assignees to assignees --- HISTORY.rst | 1 + github3/repos/repo.py | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index e78ed40b0..b635121cf 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -65,6 +65,7 @@ Old name New name ``PullRequest#iter_issue_comments`` ``PullRequest#issue_comments`` ``Team#iter_members`` ``Team#members`` ``Team#iter_repos`` ``Team#repositories`` +``Repository#iter_assignees`` ``Repository#assignees`` ==================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 05622864d..a79339420 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -364,6 +364,18 @@ def asset(self, id): 200) return Asset(data, self) if data else None + def assignees(self, number=-1, etag=None): + """Iterate over all assignees to which an issue may be assigned. + + :param int number: (optional), number of assignees to return. Default: + -1 returns all available assignees + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`User `\ s + """ + url = self._build_url('assignees', base_url=self._api) + return self._iter(int(number), url, User, etag=etag) + def blob(self, sha): """Get the blob indicated by ``sha``. @@ -1087,19 +1099,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_assignees(self, number=-1, etag=None): - """Iterate over all available assignees to which an issue may be - assigned. - - :param int number: (optional), number of assignees to return. Default: - -1 returns all available assignees - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`User `\ s - """ - url = self._build_url('assignees', base_url=self._api) - return self._iter(int(number), url, User, etag=etag) - def iter_branches(self, number=-1, etag=None): """Iterate over the branches in this repository. From 5f5372e284bfeff43701ef27a539640cbd8e2d0f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 19:57:10 -0500 Subject: [PATCH 298/972] Add integration test for Repository#assignees --- tests/cassettes/Repository_assignees.json | 1 + tests/integration/test_repos_repo.py | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/cassettes/Repository_assignees.json diff --git a/tests/cassettes/Repository_assignees.json b/tests/cassettes/Repository_assignees.json new file mode 100644 index 000000000..002757be5 --- /dev/null +++ b/tests/cassettes/Repository_assignees.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/kennethreitz/requests"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA6WYy5KrNhCGX2WKbWwL8NgeU5U6WZ7lqdRkk41LgADVgEQkYZeHml2eJI+WJ0lL4mbXCb5oZRvr/9RqdUvdtB5NvShYb8PXvb/wGK6IF3mC/NUQqaS38LKmLA/d4w/CGFGFIFR9oskYfmJEeFHrlTynDPTTgcAwUwT7t/164eEjVlgcGlHCuEKpWkYI2YdylVNVNHEjiUg4U4SpVcIr1CAr/nb8NQBaLjqGxnqxH8Zh5od+muB4HyZxskl2+22w9ncByDIQXM1V024eC4fJJLoyuFBVeWWiNc1IrgZnvCz5CSjXi7o1ERqU2s+GQln+JAWULeKqIOBbWNKXdhSFLXwYZ1Qt0h8HmmqOhA0TJH2Y1OnALB0fXy2ETM0NsIllImitKGePG3ihBhoXOWb0Ez9HA7UOc23a46YYFajJEWL1cbmVtagW9IiTs3aNIAmhR3D2k8grPRDVudYp/QcEhXY9VeSA00qnaYZLSb4WnplewSDzYAFZeW/0Tw+BlAx7CtP9OKuCs5fv7+8/Xn7vTpOXjIuX702Fmfz3739WYA08+BimnU1T4+mLzJvOrTk33D8DgDwEOZjzQc4OFK1uwcRzlzYJZDSOucCK3zob5oy7wLRo+lMHjCK4cjDayAFTcO7iQSMHDJWyIXfF7tySDUWiPj1YU8X2RLsnKebAVg92Yilpzghx8NyAaFF/4MYCs6RwgfaEFtlvZodx7mCmVgMkLnnsQIHbDxlEi2SB7eWiDm6WaaYmXCAFyRzN1IQBqYTTHhsTNWIAwp2mYLsdbOwJqO08WWKWNzh3YQ4I2Gl96+b482Y9MpcnIwOAuhQTNG5cj7GRoq20JQDktYsrR8iINFXFfK0yu/RJbWIWX1X01tU+x+sAF0HuDNVxeQ3Wv29XIbdM1YQWjSeuPdA79vNe7U703kbUjjN0lb5DGPQE1P5SY1Xo0wkmqrEgzxvcAVAbY6iRVqtVWxBsquGKCKdctXoAYZEUUOo9b2PbE6B+qbAyBXamTUyh4C45Th18OiAAZzfveTutfhpVNTSVDsYZ+ZRX0RLaVc5cztCRMSUzrmhGk3uai7nUusC03yRlCVngslxAlCqaUIhbaOD03kHJSFx8Y/WwBOjkbUNREghhB28LYgktsu1gIgh0C+kBK6jzQz8Iln64DNbvwVu0fouC3Z+wiqZOL8a8Lv3dch28h2EUrqNwq8fUjSwmGDMk3L0H62izj/w3PQTOuS7s4Bu8J/ifJnxoBXRjDzIpi1H22yiKfvoCoxMlJcTPVZDfO9/x+sK5JQQjC16RGq59cGJtmqVl/0ZlBT2pXgX9hD+D11c/uLjVE94wcH3gb8LNwjthBSUn3KKXj/uKYGjF9IxYHmwuepESje704MmY6ZOHJ/pB+0G2uerx290ezkAqBO9e4jBIRmjCa8I6eG/JdmsbPAm2GtVkjBfpf3vbh8WkJMNNqQ62+AXbKyyV6VvhvdMJurRhlQY4LSI6+zab3dd/t9unUtQSAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"93d5d2c0bdffe88df594ada64339a787\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0445:389B75D:53DAE4FA", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Thu, 31 Jul 2014 22:23:26 GMT", "date": "Fri, 01 Aug 2014 00:53:14 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406857994"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/kennethreitz/requests"}, "recorded_at": "2014-08-01T00:53:14"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/kennethreitz/requests/assignees?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62V0W6bMBhG34XrqGATE4hU7QV2u6tpioz5AasEEBiiJuq77ye4DFjUxsBVqsjn8MXNUX7frKxIZG4drTfIc1BpBVJdrZ0lI+tISOAH7s7iLVe8OjVVhudSpcr6aNv9m/VLIlXahE0NlShyBbl6EcXZbuwe/tG+ErQllXZ0Wit0aEhjhzqR4GFARSiYOAQecZ0DQSxGYPasUurn9HJ8WG3PBqfqnM0m9tPuyOxwXGRZcUHL/EN99yB7IHFk/7fMk4UWJG92oVLAu8WP9NFdlKyV+ag7dbO7l5OMOk+N/7AKIuNhmsNZlxwX3ewKyuIubMJaVLJUssjNB05otBVVwnN55ctsSNco6aaZT7lTSEOL31VzvMdudlnJlov37moqECBbvOyFyhmPRvVeAnbyC78U3dVLBScenbtMY57V8LH7l+3P5o3XHE/dg3V9ypi3tNiefpws4wDgMO7He0ZFEBLiRozQwHcgdGCPA55Idhj7dazDMaNMe2p5oBN+TZpatCpK7dgux0/hOOMlIWqPaYIaM49Pg9tkN6yYBGsWXJ3ya3HRwXk0oAtr69CHqQmXsSiiHmcxxkU8h0U0jgmI0IMDCeC51IaZX6c2HDNKraeWpzbh16SmRatS047tUvsUrk1Ne0xT05h5ahrcJrVhxZrUZHLmrayamnY/MN0vHN07vussTK6HH0dH9r7LvMgP4oAy8AJKDn4IQKLA5SI+PBnddPA36U0PmwU4Yldk+L9lVYxj3bokx6YNw5xoV+c5thlHOoYXpDrGNwp2usg02z9/AYV8RhRLDgAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"43c9d7e7d324a71b5e530b4dc3b3dbf1\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0445:389B79D:53DAE4FA", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 01 Aug 2014 00:53:14 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406857994"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/kennethreitz/requests/assignees?per_page=100"}, "recorded_at": "2014-08-01T00:53:14"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 348eb7102..b950d1d67 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -1,9 +1,22 @@ +"""Integration tests for Repositories.""" import github3 from .helper import IntegrationHelper class TestRepository(IntegrationHelper): + + """Integration tests for the Repository object.""" + + def test_assignees(self): + """Test the ability to retrieve assignees of issues on a repo.""" + cassette_name = self.cassette_name('assignees') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('kennethreitz', 'requests') + assert repository is not None + for assignee in repository.assignees(): + assert isinstance(assignee, github3.users.User) + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() From da5be5d471808293813429bf01376a1ad60a61ba Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 20:15:27 -0500 Subject: [PATCH 299/972] Refactor Repository unit tests --- tests/unit/test_repos_repo.py | 179 ++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 86 deletions(-) diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 7f59f9ff0..84c5ce68b 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -1,16 +1,55 @@ from github3.repos.repo import Repository -from .helper import UnitHelper +from .helper import UnitHelper, UnitIteratorHelper - -class TestRepository(UnitHelper): - described_class = Repository - example_data = { +repo_example_data = { + "id": 1296269, + "owner": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat" + }, + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "description": "This your first repo!", + "private": False, + "fork": False, + "url": "https://api.github.com/repos/octocat/Hello-World", + "html_url": "https://github.com/octocat/Hello-World", + "clone_url": "https://github.com/octocat/Hello-World.git", + "git_url": "git://github.com/octocat/Hello-World.git", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "mirror_url": "git://git.example.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": None, + "forks": 9, + "forks_count": 9, + "watchers": 80, + "watchers_count": 80, + "size": 108, + "master_branch": "master", + "open_issues": 0, + "open_issues_count": 0, + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "organization": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "type": "Organization" + }, + "parent": { "id": 1296269, "owner": { "login": "octocat", "id": 1, - "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "avatar_url": "https://github.com/images/error/octocat.gif", "gravatar_id": "somehexcode", "url": "https://api.github.com/users/octocat" }, @@ -18,7 +57,7 @@ class TestRepository(UnitHelper): "full_name": "octocat/Hello-World", "description": "This your first repo!", "private": False, - "fork": False, + "fork": True, "url": "https://api.github.com/repos/octocat/Hello-World", "html_url": "https://github.com/octocat/Hello-World", "clone_url": "https://github.com/octocat/Hello-World.git", @@ -38,89 +77,52 @@ class TestRepository(UnitHelper): "open_issues_count": 0, "pushed_at": "2011-01-26T19:06:43Z", "created_at": "2011-01-26T19:01:12Z", - "updated_at": "2011-01-26T19:14:43Z", - "organization": { + "updated_at": "2011-01-26T19:14:43Z" + }, + "source": { + "id": 1296269, + "owner": { "login": "octocat", "id": 1, - "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "avatar_url": "https://github.com/images/error/octocat.gif", "gravatar_id": "somehexcode", - "url": "https://api.github.com/users/octocat", - "type": "Organization" - }, - "parent": { - "id": 1296269, - "owner": { - "login": "octocat", - "id": 1, - "avatar_url": "https://github.com/images/error/octocat.gif", - "gravatar_id": "somehexcode", - "url": "https://api.github.com/users/octocat" - }, - "name": "Hello-World", - "full_name": "octocat/Hello-World", - "description": "This your first repo!", - "private": False, - "fork": True, - "url": "https://api.github.com/repos/octocat/Hello-World", - "html_url": "https://github.com/octocat/Hello-World", - "clone_url": "https://github.com/octocat/Hello-World.git", - "git_url": "git://github.com/octocat/Hello-World.git", - "ssh_url": "git@github.com:octocat/Hello-World.git", - "svn_url": "https://svn.github.com/octocat/Hello-World", - "mirror_url": "git://git.example.com/octocat/Hello-World", - "homepage": "https://github.com", - "language": None, - "forks": 9, - "forks_count": 9, - "watchers": 80, - "watchers_count": 80, - "size": 108, - "master_branch": "master", - "open_issues": 0, - "open_issues_count": 0, - "pushed_at": "2011-01-26T19:06:43Z", - "created_at": "2011-01-26T19:01:12Z", - "updated_at": "2011-01-26T19:14:43Z" - }, - "source": { - "id": 1296269, - "owner": { - "login": "octocat", - "id": 1, - "avatar_url": "https://github.com/images/error/octocat.gif", - "gravatar_id": "somehexcode", - "url": "https://api.github.com/users/octocat" - }, - "name": "Hello-World", - "full_name": "octocat/Hello-World", - "description": "This your first repo!", - "private": False, - "fork": True, - "url": "https://api.github.com/repos/octocat/Hello-World", - "html_url": "https://github.com/octocat/Hello-World", - "clone_url": "https://github.com/octocat/Hello-World.git", - "git_url": "git://github.com/octocat/Hello-World.git", - "ssh_url": "git@github.com:octocat/Hello-World.git", - "svn_url": "https://svn.github.com/octocat/Hello-World", - "mirror_url": "git://git.example.com/octocat/Hello-World", - "homepage": "https://github.com", - "language": None, - "forks": 9, - "forks_count": 9, - "watchers": 80, - "watchers_count": 80, - "size": 108, - "master_branch": "master", - "open_issues": 0, - "open_issues_count": 0, - "pushed_at": "2011-01-26T19:06:43Z", - "created_at": "2011-01-26T19:01:12Z", - "updated_at": "2011-01-26T19:14:43Z" + "url": "https://api.github.com/users/octocat" }, - "has_issues": True, - "has_wiki": True, - "has_downloads": True - } + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "description": "This your first repo!", + "private": False, + "fork": True, + "url": "https://api.github.com/repos/octocat/Hello-World", + "html_url": "https://github.com/octocat/Hello-World", + "clone_url": "https://github.com/octocat/Hello-World.git", + "git_url": "git://github.com/octocat/Hello-World.git", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "mirror_url": "git://git.example.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": None, + "forks": 9, + "forks_count": 9, + "watchers": 80, + "watchers_count": 80, + "size": 108, + "master_branch": "master", + "open_issues": 0, + "open_issues_count": 0, + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z" + }, + "has_issues": True, + "has_wiki": True, + "has_downloads": True +} + + +class TestRepository(UnitHelper): + described_class = Repository + example_data = repo_example_data def test_asset(self): """Test retrieving an asset uses the right headers @@ -148,3 +150,8 @@ def test_pages(self): url = self.example_data['url'] + '/pages' self.instance.pages() self.session.get.assert_called_once_with(url) + + +class TestRepositoryIterator(UnitIteratorHelper): + described_class = Repository + example_data = repo_example_data From 379d746a60982a568cd371bc4f025e731e480b2c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 20:15:41 -0500 Subject: [PATCH 300/972] Add docstrings to Repository unit tests --- tests/unit/test_repos_repo.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 84c5ce68b..38fbab650 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -1,3 +1,4 @@ +"""Unit tests for Repositories.""" from github3.repos.repo import Repository from .helper import UnitHelper, UnitIteratorHelper @@ -121,11 +122,14 @@ class TestRepository(UnitHelper): + + """Unit test for regular Repository methods.""" + described_class = Repository example_data = repo_example_data def test_asset(self): - """Test retrieving an asset uses the right headers + """Test retrieving an asset uses the right headers. The Releases section of the API is still in Beta and uses custom headers @@ -153,5 +157,8 @@ def test_pages(self): class TestRepositoryIterator(UnitIteratorHelper): + + """Unit tests for Repository methods that return iterators.""" + described_class = Repository example_data = repo_example_data From 68ab005fa6044dfcc66761d5ba75ec43c3289ac8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 20:27:43 -0500 Subject: [PATCH 301/972] Migrate unit test for Repository#assignees --- tests/test_repos.py | 9 --------- tests/unit/test_repos_repo.py | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index acc2a4c6f..e7df0c9db 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -550,15 +550,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_assignees(self): - self.response('user', _iter=True) - self.get(self.api + 'assignees') - self.conf = {'params': {'per_page': 100}} - - u = next(self.repo.iter_assignees()) - assert isinstance(u, github3.users.User) - self.mock_assertions() - def test_iter_branches(self): self.response('branch', _iter=True) self.get(self.api + 'branches') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 38fbab650..821f241c9 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -1,7 +1,11 @@ """Unit tests for Repositories.""" from github3.repos.repo import Repository -from .helper import UnitHelper, UnitIteratorHelper +from .helper import (UnitHelper, UnitIteratorHelper, create_url_helper) + +url_for = create_url_helper( + 'https://api.github.com/repos/octocat/Hello-World' +) repo_example_data = { "id": 1296269, @@ -162,3 +166,14 @@ class TestRepositoryIterator(UnitIteratorHelper): described_class = Repository example_data = repo_example_data + + def test_assignees(self): + """Test the ability to iterate over the assignees in a Repository.""" + i = self.instance.assignees() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('assignees'), + params={'per_page': 100}, + headers={} + ) From b2dd0751ff69db352a6c40a09cf363819d249460 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 20:46:05 -0500 Subject: [PATCH 302/972] Rename Repository#iter_branches to Repository#branches --- HISTORY.rst | 1 + github3/repos/repo.py | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index b635121cf..cc4a95cd2 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -66,6 +66,7 @@ Old name New name ``Team#iter_members`` ``Team#members`` ``Team#iter_repos`` ``Team#repositories`` ``Repository#iter_assignees`` ``Repository#assignees`` +``Repository#iter_branches`` ``Repository#branches`` ==================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index a79339420..9c32e5748 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -400,6 +400,19 @@ def branch(self, name): json = self._json(self._get(url), 200) return Branch(json, self) if json else None + def branches(self, number=-1, etag=None): + """Iterate over the branches in this repository. + + :param int number: (optional), number of branches to return. Default: + -1 returns all branches + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`Branch `\ es + """ + url = self._build_url('branches', base_url=self._api) + return self._iter(int(number), url, Branch, etag=etag) + def commit(self, sha): """Get a single (repo) commit. See :func:`git_commit` for the Git Data Commit. @@ -1099,19 +1112,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_branches(self, number=-1, etag=None): - """Iterate over the branches in this repository. - - :param int number: (optional), number of branches to return. Default: - -1 returns all branches - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of - :class:`Branch `\ es - """ - url = self._build_url('branches', base_url=self._api) - return self._iter(int(number), url, Branch, etag=etag) - def iter_code_frequency(self, number=-1, etag=None): """Iterate over the code frequency per week. From 4d4e497adccca0f444167e5f14e5a9de87c4039e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 20:47:10 -0500 Subject: [PATCH 303/972] Add integration test for Repository#branches --- tests/cassettes/Repository_branches.json | 1 + tests/integration/test_repos_repo.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Repository_branches.json diff --git a/tests/cassettes/Repository_branches.json b/tests/cassettes/Repository_branches.json new file mode 100644 index 000000000..32990eed4 --- /dev/null +++ b/tests/cassettes/Repository_branches.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YQY/qNhDHvwrKtSwmBBaIVL321Pb2Dq+XXpCTOMTaJI5sB8RG+937d5yEhKcCu660QpD1/Pz3eMaZcePxxAuDrb/c+v7cK2nBvNA7cp3VUbCoLt7cS+s8P3T/UPxY0BOXtVqtyWSUOJdMemHj5eLISzDGQ0Ex06zWy12wnHv0RDWVh1rmGJdpXamQEPtQLSy1VkzGotSs1ItYFKQm1vjb6VcftKPsGAbrxf56F2xek90+3a827HW/8re7iDE/2Qc0TrcwuJmr4t08Fo7JFLkRnOkiv5FopbUmN4NTkefiDMrtoh5NRAZL4+mWwsvjFymwbIjQGYNvsaQP4yiu9OdFtVYNNljpA08MR2HDJEs+LayzgywTHx8NkawSLbCOVCx5pbkoPy9wYg2akEda8nf6NRqsFSBG2ueltFawZifE6ufNrVlDKslPNL4Y10gWM36Cs7+IvLEHUV8qk9Z/IyiM67lmB5oUJk1Tmiv2Mffa6TUGtQ/myMpno396DCRs2FVM+P2iM1HOch5JKi+zVMgZR07LlMaI1dkZx8wM4Tr7g+s/62j2+/e/TgEEYtzboORu5rbOnyTjVI4hPdiTuwikJwCQ9MYuThxj3xB8dvkUI9VpJCTV4tGhcV/gBNSQ8U8TS5rRwkl4CwAoE8LNky0AIK5UzZ4K7fsLbzmK9PlT1kVkj7xnsuY+2hKglSqc8yVjTh4cIA3pT2WkQxlnbtie0RD7rd1tenSSauyBiXIROXHwoiQtpCEqo/Y9pA+u6gzVMCZQyVJnqYYxQLV03O9WpoEMSLwENbbeSWfPIE3n0ZyWx5oe3agDBLtuXtVH+v6wiLmfO1cKkKaCkzyq3Q+5K8cotbUD8t3NpVfMFdoWJPfLnAcOGBU2rQuKgj+qC+4TO8Qk7P8HrInTW7T5/biMeSzXMBpyPZPtod/RXbzbnfq9TtJc5+jaBaeQ6Bmk+aWiOjMnF6aqqGQuojsEaSKKYmuxWDQZo21ZXTDpmMGWABSVcYaq0UVn0zNQ9RRUt9V6amQmqN5zQRMn3w4QAO02umi1hHGMVehTnQS2gDGx4DlTWpRuZ+yVMmaXQvOUx890LPfTbQJqvilexmxO83yOqNU85ohj1NpmF1FwMjcPWQKWgWsC26nkDCHt5HXJLKMhttOMJUMjkhyoRgOxWvqrl2Xw4gc//H242YWb4B+spK6SyZj1y3L7EizNGPytXs2YqlbZCIMhu5el/2Pph6ttuG6H4ATsQhDfcAWBT1x7/NTfj1oKc2sAQ6Wyq+FvV7PwP+5HOrM4RyzdBP3zc55uX0uPTSE1EwWrUCZ0Ny3DKoPqsoCnE7RfiYjVAj0wMSvj7xi62wSbSUEQi7rEfvj79dw7U43aFa/e8cO+kBiaPjM1VQebpl6oZW26Sjy5HgOjh2f+xoeOzzZtHf11i1OSSym6+6ISSYp+v2Jlxx5kYKDt1kJjMxoB3XjQy+5WkbCU1rk+2OIZshNU/bmooLtk+oy2rwcb2rji6Je9+/gXDJOMSz0TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d2c6b1e2b18a782a93e6e71c4a44b0b3\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:693E:11E1362:53DAF0DD", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 30 Jul 2014 19:19:26 GMT", "date": "Fri, 01 Aug 2014 01:43:57 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406857994"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-01T01:43:58"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/branches?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62Uy47jIBBF/8XrTgwUjyK/MppFUVUklpzEip2WRq38+zBqaZSWvPDCS0BwzkUXfn11N7pqd+rs0RxonC7UfXR8v16HpTt9dXMbnzqgUkJQrMqgnglrrdHl6qv1kKSAsCenvm19Psa24bIs03zqe5qG43lYLs9ybGf2D53ucz8P5yt9Do/n7Hz/vQrH6U//TZ37zbTX6+O/PokcRrrJzDTpSoSca9FqXbDsig1CJYrJbB0Y67JqNooxedgnwmbaewTRMtBtxb0kDIUBXDEQDVXkaHLzTg4di2t5jALatI/7ZtpP908d79OKPFgj4osxXpLFLJgkGcjGWO88Y4hRQ0AT95HfTPshf+f58JyElrXmgFXxFRJiKwzFbBNGShy0FSeJcZygclLeK8BG2nuAOoyLPg6urj1eijGj5eI1F8tYpViPGqAIu5oA27z1JdV9/DfT3v3Pl8NEZ51X6uOKZPRkXYSao6ZsDYVEJSNlEGQ0rT0IeR/7zbR3+yvN7fZX3K0WlgpSjUejEisb5fZN5tAerxr14d/f6WQf98201+v3X1YgEDn3BQAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"84d6357b829b2ef4ba761f2ca90f215e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:693E:11E136D:53DAF0DD", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 30 Jul 2014 19:19:26 GMT", "date": "Fri, 01 Aug 2014 01:43:57 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406857994"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/branches?per_page=100"}, "recorded_at": "2014-08-01T01:43:58"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index b950d1d67..627123ccc 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -17,6 +17,15 @@ def test_assignees(self): for assignee in repository.assignees(): assert isinstance(assignee, github3.users.User) + def test_branches(self): + """Test the ability to retrieve the brances in a repository.""" + cassette_name = self.cassette_name('branches') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for branch in repository.branches(): + assert isinstance(branch, github3.repos.branch.Branch) + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() From d0d23cfcbb7c317725a0d07eb9b399423d7b324b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 20:57:58 -0500 Subject: [PATCH 304/972] Migrate Repository#branches unit test --- tests/test_repos.py | 9 --------- tests/unit/test_repos_repo.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index e7df0c9db..51dff8b54 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -550,15 +550,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_branches(self): - self.response('branch', _iter=True) - self.get(self.api + 'branches') - self.conf = {'params': {'per_page': 100}} - - b = next(self.repo.iter_branches()) - assert isinstance(b, repos.branch.Branch) - self.mock_assertions() - def test_iter_collaborators(self): self.response('user', _iter=True) self.get(self.api + 'collaborators') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 821f241c9..e1259fd2c 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -177,3 +177,14 @@ def test_assignees(self): params={'per_page': 100}, headers={} ) + + def test_branches(self): + """Test the ability to iterate over the branches in a Repository.""" + i = self.instance.branches() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('branches'), + params={'per_page': 100}, + headers={} + ) From 78a0916cb1ad6d319704d3539be6a0b69e9fdae4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 21:02:46 -0500 Subject: [PATCH 305/972] Rename Repository#iter_code_frequency --- HISTORY.rst | 1 + github3/repos/repo.py | 48 +++++++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index cc4a95cd2..7d21ab506 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -67,6 +67,7 @@ Old name New name ``Team#iter_repos`` ``Team#repositories`` ``Repository#iter_assignees`` ``Repository#assignees`` ``Repository#iter_branches`` ``Repository#branches`` +``Repository#iter_code_frequency`` ``Repository#code_frequency`` ==================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 9c32e5748..fb107b360 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -413,6 +413,30 @@ def branches(self, number=-1, etag=None): url = self._build_url('branches', base_url=self._api) return self._iter(int(number), url, Branch, etag=etag) + def code_frequency(self, number=-1, etag=None): + """Iterate over the code frequency per week. + + Returns a weekly aggregate of the number of additions and deletions + pushed to this repository. + + :param int number: (optional), number of weeks to return. Default: -1 + returns all weeks + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of lists ``[seconds_from_epoch, additions, + deletions]`` + + .. note:: All statistics methods may return a 202. On those occasions, + you will not receive any objects. You should store your + iterator and check the new ``last_status`` attribute. If it + is a 202 you should wait before re-requesting. + + .. versionadded:: 0.7 + + """ + url = self._build_url('stats', 'code_frequency', base_url=self._api) + return self._iter(int(number), url, list, etag=etag) + def commit(self, sha): """Get a single (repo) commit. See :func:`git_commit` for the Git Data Commit. @@ -1112,30 +1136,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_code_frequency(self, number=-1, etag=None): - """Iterate over the code frequency per week. - - Returns a weekly aggregate of the number of additions and deletions - pushed to this repository. - - :param int number: (optional), number of weeks to return. Default: -1 - returns all weeks - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of lists ``[seconds_from_epoch, additions, - deletions]`` - - .. note:: All statistics methods may return a 202. On those occasions, - you will not receive any objects. You should store your - iterator and check the new ``last_status`` attribute. If it - is a 202 you should wait before re-requesting. - - .. versionadded:: 0.7 - - """ - url = self._build_url('stats', 'code_frequency', base_url=self._api) - return self._iter(int(number), url, list, etag=etag) - def iter_collaborators(self, number=-1, etag=None): """Iterate over the collaborators of this repository. From 8c9d17121eee5928ed220571955682fcec57f60c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 21:15:49 -0500 Subject: [PATCH 306/972] Add integration tests for Repository#code_frequency --- tests/cassettes/Repository_code_frequency.json | 1 + tests/integration/test_repos_repo.py | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/cassettes/Repository_code_frequency.json diff --git a/tests/cassettes/Repository_code_frequency.json b/tests/cassettes/Repository_code_frequency.json new file mode 100644 index 000000000..1848cb76a --- /dev/null +++ b/tests/cassettes/Repository_code_frequency.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YXY+rNhCG/0rEbZM4hGTzIVWnvWp7dy5Ob3oTGTDBWsDINomyaP97X2MgkKPmY11pFSWs5/Hr8YyZce3x2NsHG3+x8f2pV9CceXvvyHVahcG8vHhTL6my7ND+Q/FjTk9cVmq5IqNR4lww6e1rLxNHXoAxHAqKmWa5WmyDxdSjJ6qpPFQyw7hU61LtCbEP1dxSK8VkJArNCj2PRE4qYo2/nX71QTvKlmGwXuSvtsH6Ld7ukt1yzd52S3+zDRnz411Ao2QDg5u5St7OY+GYTJEbwanOsxuJVlpjcjM4EVkmzqDcLurRRKS3NJ5uKLw4fpECy5oInTL4Fkv6NI7iSr8uqrGqscFKH3hsOAobJln8srDWDrJMfHzWRLJSNMAqVJHkpeaieF3gyBo0IY+04B/0azRYK0CMtNelNFawZifE6uvm1qwmpeQnGl2MaySLGD/B2V9E3tiDqC+lSeu/ERTG9VyzA41zk6YJzRT7nHrN9BqDmgdTZOWz0T8+BmLW7yom/H7RqSgmGQ8llZdJIuSEI6dlQiPE6uSMY2aCcJ38wfWfVTj5/ftfpwACMe69V3I3cxvnj5JxLMeQHuzJXQTSEwBIemcXJ46xrwk+23yKkOo0FJJq8ejQuC9wBKrJ8KeJJc1o7iS8AQCUCuHmyQYAEFeqYk+F9v2FNxxFuvwpqjy0R94zWXMfbQnQShXO+YIxJw/2kJp0pzLSoYhSN2zHqIn91uw2PTpJNfbAhJkInTh4UZIGUhOVUvse0gdXdYZqGCOoZImzVMPooVo67ncj00B6JF6CGlvvpLNjkLr1aEaLY0WPbtQegl03r+oj/XhYxNzPnSsFSFPBSR5W7ofclWOU2toB+e7m0ivmCm0KkvtlzgMHDAqbxgV5zh/VBfeJLWIU9v8D1sTpLdr8flzGPJZrGDW5nsn20G/pLt5tT/1OJ6mvc7TtglNIdAxS/1JSnZqTC1OVVDIX0S2C1CFFsTWfz+uU0aaszpl0zGBLAIrKKEXV6KKz7hioenKqm2o9MTJjVO+ZoLGTb3sIgHYbXbRawjDGSvSpTgIbwJCY84wpLQq3M/ZKGbILoXnCo2c6lvvpNgLV3xQvIjalWTZF1GoeccQxam2ziyg4mZuHLAHLwDWB7VQyhpB28rpkllET22lGkqERiQ9Uo4FYLvzlbBHM/OCHv9uvt/t18A9WUpXxaMxqttjMgoUZg7/lmxlTViodYDBkO1v4Pxa+wSwaDE7ANgTxDVcQ+MS1x0/9/aClMLcGMFQqvRr+djXb/8f9SGsWZYilm6B/fs7T7WvpsSmkpiJnJcqE9qalX2VQXubwdIz2KxaRmqMHJmZl/ANDt+tgPSoIIlEV2A9/t5p6Z6pRu+LVO3zYFRJ902empupg09Tba1mZrhJPrsfA4OGZv/O+47NNW0t/2+CU5FKK9r6oQJKi3y9Z0bJ7GRhou7W9sRmMgG486GS3q4hZQqtMH2zxDNkxqv5MlNBdMH1G29eBDW1YcXTL3n7+CwuxtoY9EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"a71523e9a0ebccfdf17d43e25adfee08\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:693D:9CB7B5:53DAF7DD", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 30 Jul 2014 19:19:26 GMT", "date": "Fri, 01 Aug 2014 02:13:50 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406862830"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-01T02:13:50"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/stats/code_frequency?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA1VWW45rMQjb0KkU3rCW0d3/Nq6BdKbVaD6KEjC2Iefnh0RIWc85j+lz/j0d4cOZiODvBlzEPwPCkrj00POiPYLfuPdxR1WR4yNgx7iz/t0xt/hK6+yN5a+wp0dnRf3n5bqlQjt2Hray51VVG84T3vkR7hLkcuOe1FU44nnFxorTu1CRPy8572gWdTWhTGQQ2bgeLSQAco16XmhikijROV3QDyNJLTqlODblCODoLDhlodMFJRRn5WbgIuuCqaindstJx/psGspJ5s2hxE3pLzsKHhrY4zhmvKBMREcZsAGssSSoldRUYhDJeQ+79VlgZUWY3GyTBOkYIE8zyXIBRNjYgI50xbhZUmzMENpwZQ2hWT6GoJBu7p2jrEVqenBYF50dirUGJUA32MFhJ2IMYgbpdAk2khyT2Gly9iBVjk+IAVgWl8EI4xM7nZS3CROqsYl3tGg5N0Gr09oofFafZmdsglafV15QQDsugdAg54pm5n2/oy273LPOPBaB6EsLuuexB8ajb9+eQmXsEU2s0oWaZ6zwQGc4d7WxMS6CMGnru/0Xz7TtSX43VTnGfby5prO0+NFR/aG0Nr9sXqczdD2ddZKioSkF2/8WQj8+zmie6Z7jjK/t4KIxhkht2mi5QK4cQ7SsnfDax3UyAjv+345wY4xo1x7zbJduWWsHAHJfkG5n3dC+voAC5p9KuLqnIloyCImO6cZSaI2gCOZlIYvXB+0uv3XLeGxAaOc2HYdkd0VzOEXiDA2NGf3ZWiiwJ9YBPUp3NoJKxwTvBRtsNvoTDvG9KWSj/u8h6eb7UFvsnV/FR3kGNt5pwBz66I7B7TFddJihkV2a0SUqHHb/KuEj3EdNDO/o3exunqgatev08r2uDKyqkbxh3ILIvAtg3HfnPyqbjnYBgqthHmy26aF9sd0nYSdMmXdhLHGsKUQcN7fRZOYde2s73l2XPD7rud8tPrhTwNQ4as6uBwBZ921op0K3ParwZFfCi4VStxbWyQg+pMpFbpih6UaQVO80YkJ9NB+h7ruQcXw0J0UQb8eWCo8R3gt+u2svk2OU53am7TKADM1bWwRBvvVL8XQ00l4bk7HwJo34/fysqet4jfSMGtsN3rn6Ur6oGgc6ARGbvBgEjvb4MnjV6lJC2Aydi2CJm0yC9mvg9CuyeAufA18fBKUz0X/eKjMZ2TXud0Y5JOjkPaXbjcd8ncAaM7k7aRXYMDPgTTu8s2cDc9oFuDd7XBiJzbze6gRvcHj3R/f+gIDT9j6Wy8jeb+Ewhx9o7WNAEJgN9EGTHrKx9HtO9XBv1q9ADLl/J0QG6oPqwzVs2Np+HoGFPh97xcfTGV3vOkAgaVT9DTgejjfYf/8BdL8dGNsJAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"47bcab8d5559c97a2df8609f5e4fe72f\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:693D:9CB7BF:53DAF7DE", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 01 Aug 2014 02:13:50 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406862830"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/stats/code_frequency?per_page=100"}, "recorded_at": "2014-08-01T02:13:50"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 627123ccc..6d501c204 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -26,6 +26,16 @@ def test_branches(self): for branch in repository.branches(): assert isinstance(branch, github3.repos.branch.Branch) + def test_code_frequency(self): + """Test the ability to retrieve the code frequency in a repo.""" + cassette_name = self.cassette_name('code_frequency') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for code_freq in repository.code_frequency(): + assert isinstance(code_freq, list) + assert len(code_freq) > 0 + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() From 94943f73cb648c3aadf6cfa8859f6323294b8b31 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 21:19:42 -0500 Subject: [PATCH 307/972] Update Repository docstring --- github3/repos/repo.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index fb107b360..b8cd9fde5 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -40,8 +40,9 @@ class Repository(GitHubCore): - """The :class:`Repository ` object. It represents how GitHub - sends information about repositories. + """The :class:`Repository ` object. + + It represents how GitHub sends information about repositories. Two repository instances can be checked like so:: From 1a1a221f7131f31059c6c79b52f7e0d7cadd7397 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 21:21:36 -0500 Subject: [PATCH 308/972] Migrate Repository#code_frequency unit tests --- tests/test_repos.py | 9 --------- tests/unit/test_repos_repo.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index 51dff8b54..a3c6fd75a 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -1095,15 +1095,6 @@ def test_iter_contributor_statistics(self): self.mock_assertions() - def test_iter_code_frequency(self): - self.response('code_frequency', _iter=True) - self.get(self.api + 'stats/code_frequency') - - s = next(self.repo.iter_code_frequency()) - assert isinstance(s, list) - - self.mock_assertions() - class TestContents(BaseCase): def __init__(self, methodName='runTest'): diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index e1259fd2c..fc0033685 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -188,3 +188,14 @@ def test_branches(self): params={'per_page': 100}, headers={} ) + + def test_code_frequency(self): + """Test the ability to iterate over the statistics in a Repository.""" + i = self.instance.code_frequency() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('stats/code_frequency'), + params={'per_page': 100}, + headers={} + ) From 63326a6cbfc008ae62caf10c4c8763f3e1a25f6b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 21:34:28 -0500 Subject: [PATCH 309/972] Rename Repository#iter_collaborators --- HISTORY.rst | 1 + github3/repos/repo.py | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 7d21ab506..99315a89d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -68,6 +68,7 @@ Old name New name ``Repository#iter_assignees`` ``Repository#assignees`` ``Repository#iter_branches`` ``Repository#branches`` ``Repository#iter_code_frequency`` ``Repository#code_frequency`` +``Repository#iter_collaborators`` ``Repository#collaborators`` ==================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index b8cd9fde5..c12511d73 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -438,6 +438,18 @@ def code_frequency(self, number=-1, etag=None): url = self._build_url('stats', 'code_frequency', base_url=self._api) return self._iter(int(number), url, list, etag=etag) + def collaborators(self, number=-1, etag=None): + """Iterate over the collaborators of this repository. + + :param int number: (optional), number of collaborators to return. + Default: -1 returns all comments + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`User `\ s + """ + url = self._build_url('collaborators', base_url=self._api) + return self._iter(int(number), url, User, etag=etag) + def commit(self, sha): """Get a single (repo) commit. See :func:`git_commit` for the Git Data Commit. @@ -1137,18 +1149,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_collaborators(self, number=-1, etag=None): - """Iterate over the collaborators of this repository. - - :param int number: (optional), number of collaborators to return. - Default: -1 returns all collaborators - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`User `\ s - """ - url = self._build_url('collaborators', base_url=self._api) - return self._iter(int(number), url, User, etag=etag) - def iter_comments(self, number=-1, etag=None): """Iterate over comments on all commits in the repository. From 2ac340465ccba6ae70036a33382f6f57f4f14931 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 21:46:09 -0500 Subject: [PATCH 310/972] Add integration test for Repository#collaborators --- tests/cassettes/Repository_collaborators.json | 1 + tests/integration/test_repos_repo.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Repository_collaborators.json diff --git a/tests/cassettes/Repository_collaborators.json b/tests/cassettes/Repository_collaborators.json new file mode 100644 index 000000000..64015a94f --- /dev/null +++ b/tests/cassettes/Repository_collaborators.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YQY/qNhDHvwrKtSwmBBaIVL321Pb2Dq+XXpCTOMTaJI5sB8RG+937d5yEhKcCu660QpD1/Pz3eMaZcePxxAuDrb/c+v7cK2nBvNA7cp3VUbCoLt7cS+s8P3T/UPxY0BOXtVqtyWSUOJdMemHj5eLISzDGQ0Ex06zWy12wnHv0RDWVh1rmGJdpXamQEPtQLSy1VkzGotSs1ItYFKQm1vjb6VcftKPsGAbrxf56F2xek90+3a827HW/8re7iDE/2Qc0TrcwuJmr4t08Fo7JFLkRnOkiv5FopbUmN4NTkefiDMrtoh5NRAZL4+mWwsvjFymwbIjQGYNvsaQP4yiu9OdFtVYNNljpA08MR2HDJEs+LayzgywTHx8NkawSLbCOVCx5pbkoPy9wYg2akEda8nf6NRqsFSBG2ueltFawZifE6ufNrVlDKslPNL4Y10gWM36Cs7+IvLEHUV8qk9Z/IyiM67lmB5oUJk1Tmiv2Mffa6TUGtQ/myMpno396DCRs2FVM+P2iM1HOch5JKi+zVMgZR07LlMaI1dkZx8wM4Tr7g+s/62j2+/e/TgEEYtzboORu5rbOnyTjVI4hPdiTuwikJwCQ9MYuThxj3xB8dvkUI9VpJCTV4tGhcV/gBNSQ8U8TS5rRwkl4CwAoE8LNky0AIK5UzZ4K7fsLbzmK9PlT1kVkj7xnsuY+2hKglSqc8yVjTh4cIA3pT2WkQxlnbtie0RD7rd1tenSSauyBiXIROXHwoiQtpCEqo/Y9pA+u6gzVMCZQyVJnqYYxQLV03O9WpoEMSLwENbbeSWfPIE3n0ZyWx5oe3agDBLtuXtVH+v6wiLmfO1cKkKaCkzyq3Q+5K8cotbUD8t3NpVfMFdoWJPfLnAcOGBU2rQuKgj+qC+4TO8Qk7P8HrInTW7T5/biMeSzXMBpyPZPtod/RXbzbnfq9TtJc5+jaBaeQ6Bmk+aWiOjMnF6aqqGQuojsEaSKKYmuxWDQZo21ZXTDpmMGWABSVcYaq0UVn0zNQ9RRUt9V6amQmqN5zQRMn3w4QAO02umi1hHGMVehTnQS2gDGx4DlTWpRuZ+yVMmaXQvOUx890LPfTbQJqvilexmxO83yOqNU85ohj1NpmF1FwMjcPWQKWgWsC26nkDCHt5HXJLKMhttOMJUMjkhyoRgOxWvqrl2Xw4gc//H242YWb4B+spK6SyZj1y3L7EizNGPytXs2YqlbZCIMhu5el/2O5Cld+uN6ZITgBuxDEN1xB4BPXHj/196OWwtwawFCp7Gr429Us/I/7kc4szhFLN0H//Jyn29fSY1NIzUTBKpQJ3U3LsMqguizg6QTtVyJitUAPTMzK+DuG7jbBZlIQxKIusR/+fj33zlSjdsWrd/ywLySGps9MTdXBpqkXalmbrhJPrsfA6OGZv/Gh47NNW0d/3eKU5FKK7r6oRJKi369Y2bEHGRhou7XQ2IxGQDce9LK7VSQspXWuD7Z4huwEVX8uKugumT6j7evBhjauOPpl7z7+BVO2+U09EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"63e45d2c67a09c9be3b2060faeb9eb16\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:338B:16A1AA8:53DAFDE1", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 30 Jul 2014 19:19:26 GMT", "date": "Fri, 01 Aug 2014 02:39:29 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406862830"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-01T02:39:30"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/collaborators?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62T3Y6bMBBG34XraPmzg4lU9Sl6Va0igwdilQCyDatdtO/eAZOW0FV3DblJIuTzzecJ5+fgVU0pa+/kaVleeS9VpyPiHTwpvFNEAhYHB4/33HB17lSF5y7GtPrk+/ahfiqluXRZp0HlTW2gNk95c/U738Lf+28hppVqzhhjvTwkLKZHwdIijSgc0yhMWAYQijTmeZEgsJrVynmODcdh2l8Vvphrtapoq03I6nDRVFXzginrS302yP9DYkn7W9blxhQkB78xF8Dd4pXex0VJbdxLTdTgj19nKcYcjX+YAuFcbOaw1kuNjQZfQdtMgV2mcyVbI5vaveAdjWmNKnkt3/i2NKQ1hozV3KtMFNLQ47vqjlts8Fsle56/jqtRkIPscdkbI1c8JprXFtCTH/hSjKuXBs5cXEdNC15peD8stMWhfLzPJGwQHEm6VdgJ/lBYTqKcZCIsRBYlNGSU04RkUcwoCRmPBY7/irC3qp+oejvmJulE7dBzye8S0wbtU9JmPFDGOXAp8SYNbY6zgBbboJ4F8RNd3S3drcWdrm66gea5gV+aZ7NyR5bSNNyonIU/VC4ACmEkaE4KlgKQmEZJwQIuKKFAs/hryt3V/b92d0ed1PtLbtfvn4w9Ci7Cdmm4yHmcisvQvTouslyVXKDuWi7gx6h518ZVz+ffGua6ccYKAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d6feee804f65ce71d30907aaab2799d0\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:338B:16A1ABC:53DAFDE1", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 01 Aug 2014 02:39:29 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406862830"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/collaborators?per_page=100"}, "recorded_at": "2014-08-01T02:39:30"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 6d501c204..0f583aabb 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -36,6 +36,15 @@ def test_code_frequency(self): assert isinstance(code_freq, list) assert len(code_freq) > 0 + def test_collaborators(self): + """Test the ability to retrieve the collaborators on a repository.""" + cassette_name = self.cassette_name('collaborators') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for collaborator in repository.collaborators(): + assert isinstance(collaborator, github3.users.User) + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() From 993d7288eb3f28873f6aa15335c3f9b511d751fa Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 21:52:54 -0500 Subject: [PATCH 311/972] Migrate Repository#collaborators unit test --- tests/test_repos.py | 9 --------- tests/unit/test_repos_repo.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index a3c6fd75a..60761f9e4 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -550,15 +550,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_collaborators(self): - self.response('user', _iter=True) - self.get(self.api + 'collaborators') - self.conf = {'params': {'per_page': 100}} - - u = next(self.repo.iter_collaborators()) - assert isinstance(u, github3.users.User) - self.mock_assertions() - def test_iter_comments(self): self.response('repo_comment', _iter=True) self.get(self.api + 'comments') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index fc0033685..7f5b80c1a 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -199,3 +199,14 @@ def test_code_frequency(self): params={'per_page': 100}, headers={} ) + + def test_collaborators(self): + """Test the ability to iterate over the collaborators on a repo.""" + i = self.instance.collaborators() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('collaborators'), + params={'per_page': 100}, + headers={} + ) From 10482fec2dc409a8cea7f7c618eaed50b2c7df94 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 22:03:05 -0500 Subject: [PATCH 312/972] Rename Repository#iter_comments --- HISTORY.rst | 1 + github3/repos/repo.py | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 99315a89d..0e98197c9 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -69,6 +69,7 @@ Old name New name ``Repository#iter_branches`` ``Repository#branches`` ``Repository#iter_code_frequency`` ``Repository#code_frequency`` ``Repository#iter_collaborators`` ``Repository#collaborators`` +``Repository#iter_comments`` ``Repository#comments`` ==================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index c12511d73..bccab0fe7 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -450,6 +450,19 @@ def collaborators(self, number=-1, etag=None): url = self._build_url('collaborators', base_url=self._api) return self._iter(int(number), url, User, etag=etag) + def comments(self, number=-1, etag=None): + """Iterate over comments on all commits in the repository. + + :param int number: (optional), number of comments to return. Default: + -1 returns all comments + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`RepoComment `\ s + """ + url = self._build_url('comments', base_url=self._api) + return self._iter(int(number), url, RepoComment, etag=etag) + def commit(self, sha): """Get a single (repo) commit. See :func:`git_commit` for the Git Data Commit. @@ -1149,19 +1162,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_comments(self, number=-1, etag=None): - """Iterate over comments on all commits in the repository. - - :param int number: (optional), number of comments to return. Default: - -1 returns all comments - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of - :class:`RepoComment `\ s - """ - url = self._build_url('comments', base_url=self._api) - return self._iter(int(number), url, RepoComment, etag=etag) - def iter_comments_on_commit(self, sha, number=1, etag=None): """Iterate over comments for a single commit. From 28a473aaca6883d1c5b3cddd66125400443bf463 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 22:03:39 -0500 Subject: [PATCH 313/972] Migrate Repository#comments unit test --- tests/test_repos.py | 9 --------- tests/unit/test_repos_repo.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index 60761f9e4..b29ece939 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -550,15 +550,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_comments(self): - self.response('repo_comment', _iter=True) - self.get(self.api + 'comments') - self.conf = {'params': {'per_page': 100}} - - c = next(self.repo.iter_comments()) - assert isinstance(c, repos.comment.RepoComment) - self.mock_assertions() - def test_iter_comments_on_commit(self): self.response('repo_comment', _iter=True) self.get(self.api + 'commits/fakesha/comments') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 7f5b80c1a..1e6c1a4d4 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -210,3 +210,14 @@ def test_collaborators(self): params={'per_page': 100}, headers={} ) + + def test_comments(self): + """Test the ability to iterate over the comments on a repository.""" + i = self.instance.comments() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('comments'), + params={'per_page': 100}, + headers={} + ) From 2e9759e9005bea5db52cd5833c96c07d96e212e5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 31 Jul 2014 22:05:24 -0500 Subject: [PATCH 314/972] Add integration test for Repository#comments --- tests/cassettes/Repository_comments.json | 1 + tests/integration/test_repos_repo.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Repository_comments.json diff --git a/tests/cassettes/Repository_comments.json b/tests/cassettes/Repository_comments.json new file mode 100644 index 000000000..77ad64a61 --- /dev/null +++ b/tests/cassettes/Repository_comments.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YXY+rNhCG/0rEbZM4hGTzIVWnvWp7dy5Ob3oTGTDBWsDINomyaP97X2MgkKPmY11pFSWs5/Hr8YyZce3x2NsHG3+x8f2pV9CceXvvyHVahcG8vHhTL6my7ND+Q/FjTk9cVmq5IqNR4lww6e1rLxNHXoAxHAqKmWa5WmyDxdSjJ6qpPFQyw7hU61LtCbEP1dxSK8VkJArNCj2PRE4qYo2/nX71QTvKlmGwXuSvtsH6Ld7ukt1yzd52S3+zDRnz411Ao2QDg5u5St7OY+GYTJEbwanOsxuJVlpjcjM4EVkmzqDcLurRRKS3NJ5uKLw4fpECy5oInTL4Fkv6NI7iSr8uqrGqscFKH3hsOAobJln8srDWDrJMfHzWRLJSNMAqVJHkpeaieF3gyBo0IY+04B/0azRYK0CMtNelNFawZifE6uvm1qwmpeQnGl2MaySLGD/B2V9E3tiDqC+lSeu/ERTG9VyzA41zk6YJzRT7nHrN9BqDmgdTZOWz0T8+BmLW7yom/H7RqSgmGQ8llZdJIuSEI6dlQiPE6uSMY2aCcJ38wfWfVTj5/ftfpwACMe69V3I3cxvnj5JxLMeQHuzJXQTSEwBIemcXJ46xrwk+23yKkOo0FJJq8ejQuC9wBKrJ8KeJJc1o7iS8AQCUCuHmyQYAEFeqYk+F9v2FNxxFuvwpqjy0R94zWXMfbQnQShXO+YIxJw/2kJp0pzLSoYhSN2zHqIn91uw2PTpJNfbAhJkInTh4UZIGUhOVUvse0gdXdYZqGCOoZImzVMPooVo67ncj00B6JF6CGlvvpLNjkLr1aEaLY0WPbtQegl03r+oj/XhYxNzPnSsFSFPBSR5W7ofclWOU2toB+e7m0ivmCm0KkvtlzgMHDAqbxgV5zh/VBfeJLWIU9v8D1sTpLdr8flzGPJZrGDW5nsn20G/pLt5tT/1OJ6mvc7TtglNIdAxS/1JSnZqTC1OVVDIX0S2C1CFFsTWfz+uU0aaszpl0zGBLAIrKKEXV6KKz7hioenKqm2o9MTJjVO+ZoLGTb3sIgHYbXbRawjDGSvSpTgIbwJCY84wpLQq3M/ZKGbILoXnCo2c6lvvpNgLV3xQvIjalWTZF1GoeccQxam2ziyg4mZuHLAHLwDWB7VQyhpB28rpkllET22lGkqERiQ9Uo4FYLvzlbBHM/OCHv9uvt/t18A9WUpXxaMxqttjMgoUZg7/lmxlTViodYDBkO1v4PxbL/Rp/GzMEJ2AbgviGKwh84trjp/5+0FKYWwMYKpVeDX+7mu3/436kNYsyxNJN0D8/5+n2tfTYFFJTkbMSZUJ709KvMigvc3g6RvsVi0jN0QMTszL+gaHbdbAeFQSRqArsh79bTb0z1ahd8eodPuwKib7pM1NTdbBp6u21rExXiSfXY2Dw8Mzfed/x2aatpb9tcEpyKUV7X1QgSdHvl6xo2b0MDLTd2t7YDEZANx50sttVxCyhVaYPtniG7BhVfyZK6C6YPqPt68CGNqw4umVvP/8F40XdZj0TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"babd47d6ec47483777379c4fbc8aa707\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "55", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B97:9C82CE:53DB03DF", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 30 Jul 2014 19:19:26 GMT", "date": "Fri, 01 Aug 2014 03:05:03 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406862830"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-01T03:05:04"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/comments?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"137ca911c91e4a9afa2ba8a872cd973c\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "54", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B97:9C82D1:53DB03DF", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 01 Aug 2014 03:05:04 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406862830"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/comments?per_page=100"}, "recorded_at": "2014-08-01T03:05:05"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 0f583aabb..14f58fe08 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -45,6 +45,15 @@ def test_collaborators(self): for collaborator in repository.collaborators(): assert isinstance(collaborator, github3.users.User) + def test_comments(self): + """Test the ability to retrieve comments on a repository.""" + cassette_name = self.cassette_name('comments') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for comment in repository.comments(): + assert isinstance(comment, github3.repos.comment.RepoComment) + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() From 44a2701d081786a8a4c138b543acefc47a488ab8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 1 Aug 2014 08:19:04 -0500 Subject: [PATCH 315/972] Rename Repository#iter_comments_on_commit --- HISTORY.rst | 7 ++++--- github3/repos/repo.py | 30 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 0e98197c9..8ed8eec3d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -20,9 +20,9 @@ Breaking Changes - All methods and functions starting with ``iter_`` have been renamed. -==================================== ============================================== +====================================== ============================================== Old name New name -==================================== ============================================== +====================================== ============================================== ``github3.iter_all_repos`` ``github3.all_repositories`` ``github3.iter_all_users`` ``github3.all_users`` ``github3.iter_events`` ``github3.all_events`` @@ -70,8 +70,9 @@ Old name New name ``Repository#iter_code_frequency`` ``Repository#code_frequency`` ``Repository#iter_collaborators`` ``Repository#collaborators`` ``Repository#iter_comments`` ``Repository#comments`` +``Repository#iter_comments_on_commit`` ``Repository#comments_on_commit`` -==================================== ============================================== +====================================== ============================================== - ``github3.login`` has been simplified and split into two functions: diff --git a/github3/repos/repo.py b/github3/repos/repo.py index bccab0fe7..713aea50c 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -463,6 +463,21 @@ def comments(self, number=-1, etag=None): url = self._build_url('comments', base_url=self._api) return self._iter(int(number), url, RepoComment, etag=etag) + def comments_on_commit(self, sha, number=1, etag=None): + """Iterate over comments for a single commit. + + :param sha: (required), sha of the commit to list comments on + :type sha: str + :param int number: (optional), number of comments to return. Default: + -1 returns all comments + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`RepoComment `\ s + """ + url = self._build_url('commits', sha, 'comments', base_url=self._api) + return self._iter(int(number), url, RepoComment, etag=etag) + def commit(self, sha): """Get a single (repo) commit. See :func:`git_commit` for the Git Data Commit. @@ -1162,21 +1177,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_comments_on_commit(self, sha, number=1, etag=None): - """Iterate over comments for a single commit. - - :param sha: (required), sha of the commit to list comments on - :type sha: str - :param int number: (optional), number of comments to return. Default: - -1 returns all comments - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of - :class:`RepoComment `\ s - """ - url = self._build_url('commits', sha, 'comments', base_url=self._api) - return self._iter(int(number), url, RepoComment, etag=etag) - def iter_commit_activity(self, number=-1, etag=None): """Iterate over last year of commit activity by week. From c097c452f4959d8b310a2d7948d68e77b86695fe Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 1 Aug 2014 08:19:15 -0500 Subject: [PATCH 316/972] Satisfy pep257 --- tests/integration/test_repos_repo.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 14f58fe08..04561e7b0 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -136,9 +136,7 @@ def test_iter_releases(self): assert isinstance(release, github3.repos.release.Release) def test_milestone(self): - """ - Test the ability to retrieve a specific milestone on a repository. - """ + """Test the ability to retrieve a milestone on a repository.""" cassette_name = self.cassette_name('milestone') with self.recorder.use_cassette(cassette_name): repository = self.gh.repository('sigmavirus24', 'github3.py') From 210d4840958fc0afe3e781ae10fbf91c0d12e857 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 1 Aug 2014 08:24:41 -0500 Subject: [PATCH 317/972] Add integration test for Repository#comments_on_commit --- tests/cassettes/Repository_comments_on_commit.json | 1 + tests/integration/test_repos_repo.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/cassettes/Repository_comments_on_commit.json diff --git a/tests/cassettes/Repository_comments_on_commit.json b/tests/cassettes/Repository_comments_on_commit.json new file mode 100644 index 000000000..e67067110 --- /dev/null +++ b/tests/cassettes/Repository_comments_on_commit.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YXY+rNhCG/writkkcSDbJIlWnVa97dbaq1JvIgAFrwUa2SbSL9r93/EEgaXdDtL45SzieZ17GnmGGPqR5mMRRvN2vt0+LkOGGhEn4J86p5Gz5N28IW1K2fCFZFS7Coqvro1tT1m+MUYk+W8vPjIgw6cOal5QB1BkARvuMnuLnzW63CPEJKyyOnahhTaVUKxOE7E25KqmqurSTRGScKcLUKuMN6pCz/nH6NQJeKRxEg8O82BS7bP+03m73h2hz2ESHKE3JoViTeLMtnsHgxllLnSNLB28SjWor1dQ38qwss3pcV/C65mewvX2WL/DoYqSjawCUlY8DwKhHXFUEAgnyP3RQqFQPSTEGPdJ/jjTXCAkbI0j+iBxnAmL09n/0SJCWG1aXykzQVlHOHpJ1ZQggLkrM6Dt+GASGEuy1oIcEGAMwJCc4fw9ZWosetYKecPamwyBIRugJYvo47cYUYOqt1dn6F+y4jjBV5IjzRidbgWtJPhah8axgkbmxgPyacZY/TemcXLYQ3P4enEmqnQYFF4ErA4EpGQFlgS4ZAWZ5AKeSioA0mNYBI2dZE6WMYDB7vSj7MiXNFgyp9qk8zbuzPzNAkJKAAXmv5M0DTVN6BP+6nMogyXHKBVb8XqWYI/YK16PpT33cFMGNh4cwGMBVnPuIsMEAjkrZkVmZMCcUhibRkHSsa1JbCeek2hwHlgO6sZS0ZIR4iOwF1aOhcKcCs6zyAR9IPbJX5kTg0oNsTQFYWvPUAw1ep8igeiQrbF9e6uhHqWZr0hVakMKTbE26oJXwciaMZI26gOGtquB4eNA8kFDvIl1jVna49MG+oOBk6D6gxO93u6E5eTeyAKz7QEHTzlf5HGlatW1SoG74CPUIG9Gm//m6oZoVkkk3ZYLSNPRebzKH60BXyeINrs/1rQP9+35bNVe6JvVorPz2BeN8fD/q7g0zaEb96MmNJx6OzUBC/S8tVpWuhuCwxYJ8/wEcCPUphvZwtVr1FcGm1W+I8FIDLAeAWGQVNLrf19wPJOjLGqzMSFFoyTmMGDXHuYeYX1CAtZv8fd2WMz2NLUzPHsQazJTb0JpIxZmPGj6yph4YV7Sg2ZyZa06qXuH6H5KyjCxwXS/glCuaUTj3MNDqPYZWmfiImeXAI8H3DTuG1QRSwMNuCGJJPbIzcyYIDFz5ESsYkeJ1tF2ud8t49xLtkug5ibb/wFN1bX67Zr+MNi/xOol3yeZZr2k7WV1jYMneYA4OA/XUHVO4go8m//0q8f+jkv7YAR6krEbz30bj5MsvO844q+G83STJo/5Pty/CuQAQX8GY2ULbEiYM0kEPv+9wHW/gg9Kk9ch4x2Af4kV4xgp6anitj7eGdgX26Y+fPzUTy6PN2jBRotPjMtwZa8Pk5pm+0mGRHTsddw2llArB3QctK463hDny4B/W2TkzgavJ/4f69yDWKM9JgbtaHW0LD2IbLO38zIg6w6w6QU77Fyfo6eNfSnr5U+QTAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"56de4dd4674a769de3c7bfbe2f6ec3b8\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:693E:16E719E:53DB947A", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 13 Jul 2014 20:26:39 GMT", "date": "Fri, 01 Aug 2014 13:22:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406902922"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech"}, "recorded_at": "2014-08-01T13:22:02"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech/commits/65c0c7d58b3ef09a0b3d5f9779228f9d1a5ad552/comments?per_page=1"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52U3Y6bMBCFXyVyL3oTYn5C+FGaPkFvqlSVWlWRwQYsgY1swzZFybN3DGy3odJukysMnPP5zJjh+4A6VaMUVca0OsWYtHxTclN12SaXDVaslRqX9VkIrvEnQrmWwvkqGyYcLpwjyysMOrg1Gke+FyTJDq2B1tSnW/Bf0Ldx3OBdmLt5RMM4C1jhJsTNAhoWSRQlvh8XCfVISGgY+u/s9tzMIZyXDJyidL5bo04zhdIB1bLkAsrVvGxIz1Wn/S3ktVp/68aBu0akJ4aoRfrpoZ5bY2m5FAaqHrvU4cn8sf/gAa1UM8NiUe5t4yDc0TgpEj9ku8T3ojhjzKNJQPIiAsOrR2A303gR+PUGL8SFrGv5BJRlUbdn/e9G+I8TQk5rLsoHKeAcsDQVg95CSRfbKK7N/aFG14Dt5cSp5Wg4MMXo3cFmH8R6EpBoGD/3EdhlOle8NVyK+wPeuIEmVUkE/0Ueo4FbA2ScxLsrHF3gZr2d0Lvtk23AreI9yc+2NYrljPfQ7AeRCz8QzbllMCdf7IhC67lhJ0IbO6YFqTW7rBHUwG3zUCq6ul6jmgtwTOuWmOp5Pf0K4KMA3P/+P2DLXDFioCJiwOe73tZxIyfwjq6ben7qx99A07X0TU0m6flkJxMw+/ZwrIh5r1darvaU1YfPBM5gj+1y1TBDNnvcHoA8ugz7aTd/sYzqSTdrbl5fr6Pgep0llx+/ASpIo5zKBQAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e3b4b0bd50c4aa9bc085a8875557d59b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:693E:16E71CE:53DB947A", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 01 Aug 2014 13:22:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406902922"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech/commits/65c0c7d58b3ef09a0b3d5f9779228f9d1a5ad552/comments?per_page=1"}, "recorded_at": "2014-08-01T13:22:03"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 04561e7b0..46caba19a 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -54,6 +54,17 @@ def test_comments(self): for comment in repository.comments(): assert isinstance(comment, github3.repos.comment.RepoComment) + def test_comments_on_commit(self): + """Test the ability to retrieve the comments on a commit.""" + sha = '65c0c7d58b3ef09a0b3d5f9779228f9d1a5ad552' + cassette_name = self.cassette_name('comments_on_commit') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('glynnis', + 'Madison-Women-in-Tech') + assert repository is not None + for comment in repository.comments_on_commit(sha): + assert isinstance(comment, github3.repos.comment.RepoComment) + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() From 120fc7562277a1af23f65379c11e180eb3740c5c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 1 Aug 2014 08:29:31 -0500 Subject: [PATCH 318/972] Migrate unit test for Repository#comments_on_commit Fix bug in method signature --- github3/repos/repo.py | 2 +- tests/test_repos.py | 9 --------- tests/unit/test_repos_repo.py | 11 +++++++++++ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 713aea50c..f23c5ca97 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -463,7 +463,7 @@ def comments(self, number=-1, etag=None): url = self._build_url('comments', base_url=self._api) return self._iter(int(number), url, RepoComment, etag=etag) - def comments_on_commit(self, sha, number=1, etag=None): + def comments_on_commit(self, sha, number=-1, etag=None): """Iterate over comments for a single commit. :param sha: (required), sha of the commit to list comments on diff --git a/tests/test_repos.py b/tests/test_repos.py index b29ece939..5bccd394e 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -550,15 +550,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_comments_on_commit(self): - self.response('repo_comment', _iter=True) - self.get(self.api + 'commits/fakesha/comments') - self.conf = {'params': {'per_page': 1}} - - c = next(self.repo.iter_comments_on_commit('fakesha')) - assert isinstance(c, repos.comment.RepoComment) - self.mock_assertions() - def test_iter_commits(self): self.response('commit', _iter=True) self.get(self.api + 'commits') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 1e6c1a4d4..1e2cef365 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -221,3 +221,14 @@ def test_comments(self): params={'per_page': 100}, headers={} ) + + def test_comments_on_commit(self): + """Test the ability to iterate over comments on a specific commit.""" + i = self.instance.comments_on_commit('some-sha') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('commits/some-sha/comments'), + params={'per_page': 100}, + headers={} + ) From 8962eef2b9f7f701b3f3f806f9fda18722a480e7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 1 Aug 2014 08:41:04 -0500 Subject: [PATCH 319/972] Re-record cassette for Repository#comments_on_commit --- tests/cassettes/Repository_comments_on_commit.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cassettes/Repository_comments_on_commit.json b/tests/cassettes/Repository_comments_on_commit.json index e67067110..d080cd188 100644 --- a/tests/cassettes/Repository_comments_on_commit.json +++ b/tests/cassettes/Repository_comments_on_commit.json @@ -1 +1 @@ -{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YXY+rNhCG/writkkcSDbJIlWnVa97dbaq1JvIgAFrwUa2SbSL9r93/EEgaXdDtL45SzieZ17GnmGGPqR5mMRRvN2vt0+LkOGGhEn4J86p5Gz5N28IW1K2fCFZFS7Coqvro1tT1m+MUYk+W8vPjIgw6cOal5QB1BkARvuMnuLnzW63CPEJKyyOnahhTaVUKxOE7E25KqmqurSTRGScKcLUKuMN6pCz/nH6NQJeKRxEg8O82BS7bP+03m73h2hz2ESHKE3JoViTeLMtnsHgxllLnSNLB28SjWor1dQ38qwss3pcV/C65mewvX2WL/DoYqSjawCUlY8DwKhHXFUEAgnyP3RQqFQPSTEGPdJ/jjTXCAkbI0j+iBxnAmL09n/0SJCWG1aXykzQVlHOHpJ1ZQggLkrM6Dt+GASGEuy1oIcEGAMwJCc4fw9ZWosetYKecPamwyBIRugJYvo47cYUYOqt1dn6F+y4jjBV5IjzRidbgWtJPhah8axgkbmxgPyacZY/TemcXLYQ3P4enEmqnQYFF4ErA4EpGQFlgS4ZAWZ5AKeSioA0mNYBI2dZE6WMYDB7vSj7MiXNFgyp9qk8zbuzPzNAkJKAAXmv5M0DTVN6BP+6nMogyXHKBVb8XqWYI/YK16PpT33cFMGNh4cwGMBVnPuIsMEAjkrZkVmZMCcUhibRkHSsa1JbCeek2hwHlgO6sZS0ZIR4iOwF1aOhcKcCs6zyAR9IPbJX5kTg0oNsTQFYWvPUAw1ep8igeiQrbF9e6uhHqWZr0hVakMKTbE26oJXwciaMZI26gOGtquB4eNA8kFDvIl1jVna49MG+oOBk6D6gxO93u6E5eTeyAKz7QEHTzlf5HGlatW1SoG74CPUIG9Gm//m6oZoVkkk3ZYLSNPRebzKH60BXyeINrs/1rQP9+35bNVe6JvVorPz2BeN8fD/q7g0zaEb96MmNJx6OzUBC/S8tVpWuhuCwxYJ8/wEcCPUphvZwtVr1FcGm1W+I8FIDLAeAWGQVNLrf19wPJOjLGqzMSFFoyTmMGDXHuYeYX1CAtZv8fd2WMz2NLUzPHsQazJTb0JpIxZmPGj6yph4YV7Sg2ZyZa06qXuH6H5KyjCxwXS/glCuaUTj3MNDqPYZWmfiImeXAI8H3DTuG1QRSwMNuCGJJPbIzcyYIDFz5ESsYkeJ1tF2ud8t49xLtkug5ibb/wFN1bX67Zr+MNi/xOol3yeZZr2k7WV1jYMneYA4OA/XUHVO4go8m//0q8f+jkv7YAR6krEbz30bj5MsvO844q+G83STJo/5Pty/CuQAQX8GY2ULbEiYM0kEPv+9wHW/gg9Kk9ch4x2Af4kV4xgp6anitj7eGdgX26Y+fPzUTy6PN2jBRotPjMtwZa8Pk5pm+0mGRHTsddw2llArB3QctK463hDny4B/W2TkzgavJ/4f69yDWKM9JgbtaHW0LD2IbLO38zIg6w6w6QU77Fyfo6eNfSnr5U+QTAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"56de4dd4674a769de3c7bfbe2f6ec3b8\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:693E:16E719E:53DB947A", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 13 Jul 2014 20:26:39 GMT", "date": "Fri, 01 Aug 2014 13:22:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406902922"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech"}, "recorded_at": "2014-08-01T13:22:02"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech/commits/65c0c7d58b3ef09a0b3d5f9779228f9d1a5ad552/comments?per_page=1"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52U3Y6bMBCFXyVyL3oTYn5C+FGaPkFvqlSVWlWRwQYsgY1swzZFybN3DGy3odJukysMnPP5zJjh+4A6VaMUVca0OsWYtHxTclN12SaXDVaslRqX9VkIrvEnQrmWwvkqGyYcLpwjyysMOrg1Gke+FyTJDq2B1tSnW/Bf0Ldx3OBdmLt5RMM4C1jhJsTNAhoWSRQlvh8XCfVISGgY+u/s9tzMIZyXDJyidL5bo04zhdIB1bLkAsrVvGxIz1Wn/S3ktVp/68aBu0akJ4aoRfrpoZ5bY2m5FAaqHrvU4cn8sf/gAa1UM8NiUe5t4yDc0TgpEj9ku8T3ojhjzKNJQPIiAsOrR2A303gR+PUGL8SFrGv5BJRlUbdn/e9G+I8TQk5rLsoHKeAcsDQVg95CSRfbKK7N/aFG14Dt5cSp5Wg4MMXo3cFmH8R6EpBoGD/3EdhlOle8NVyK+wPeuIEmVUkE/0Ueo4FbA2ScxLsrHF3gZr2d0Lvtk23AreI9yc+2NYrljPfQ7AeRCz8QzbllMCdf7IhC67lhJ0IbO6YFqTW7rBHUwG3zUCq6ul6jmgtwTOuWmOp5Pf0K4KMA3P/+P2DLXDFioCJiwOe73tZxIyfwjq6ben7qx99A07X0TU0m6flkJxMw+/ZwrIh5r1darvaU1YfPBM5gj+1y1TBDNnvcHoA8ugz7aTd/sYzqSTdrbl5fr6Pgep0llx+/ASpIo5zKBQAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e3b4b0bd50c4aa9bc085a8875557d59b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:693E:16E71CE:53DB947A", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 01 Aug 2014 13:22:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406902922"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech/commits/65c0c7d58b3ef09a0b3d5f9779228f9d1a5ad552/comments?per_page=1"}, "recorded_at": "2014-08-01T13:22:03"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YXY+rNhCG/writkkcSDbJIlWnVa97dbaq1JvIgAFrwUa2SbSL9r93/EEgaXdDtL45SzieZ17GnmGGPqR5mMRRvN2vt0+LkOGGhEn4J86p5Gz5N28IW1K2fCFZFS7Coqvro1tT1m+MUYk+W8vPjIgw6cOal5QB1BkARvuMnuLnzW63CPEJKyyOnahhTaVUKxOE7E25KqmqurSTRGScKcLUKuMN6pCz/nH6NQJeKRxEg8O82BS7bP+03m73h2hz2ESHKE3JoViTeLMtnsHgxllLnSNLB28SjWor1dQ38qwss3pcV/C65mewvX2WL/DoYqSjawCUlY8DwKhHXFUEAgnyP3RQqFQPSTEGPdJ/jjTXCAkbI0j+iBxnAmL09n/0SJCWG1aXykzQVlHOHpJ1ZQggLkrM6Dt+GASGEuy1oIcEGAMwJCc4fw9ZWosetYKecPamwyBIRugJYvo47cYUYOqt1dn6F+y4jjBV5IjzRidbgWtJPhah8axgkbmxgPyacZY/TemcXLYQ3P4enEmqnQYFF4ErA4EpGQFlgS4ZAWZ5AKeSioA0mNYBI2dZE6WMYDB7vSj7MiXNFgyp9qk8zbuzPzNAkJKAAXmv5M0DTVN6BP+6nMogyXHKBVb8XqWYI/YK16PpT33cFMGNh4cwGMBVnPuIsMEAjkrZkVmZMCcUhibRkHSsa1JbCeek2hwHlgO6sZS0ZIR4iOwF1aOhcKcCs6zyAR9IPbJX5kTg0oNsTQFYWvPUAw1ep8igeiQrbF9e6uhHqWZr0hVakMKTbE26oJXwciaMZI26gOGtquB4eNA8kFDvIl1jVna49MG+oOBk6D6gxO93u6E5eTeyAKz7QEHTzlf5HGlatW1SoG74CPUIG9Gm//m6oZoVkkk3ZYLSNPRebzKH60BXyeINrs/1rQP9+35bNVe6JvVorPz2BeN8fD/q7g0zaEb96MmNJx6OzUBC/S8tVpWuhuCwxYJ8/wEcCPUphvZwtVr1FcGm1W+I8FIDLAeAWGQVNLrf19wPJOjLGqzMSFFoyTmMGDXHuYeYX1CAtZv8fd2WMz2NLUzPHsQazJTb0JpIxZmPGj6yph4YV7Sg2ZyZa06qXuH6H5KyjCxwXS/glCuaUTj3MNDqPYZWmfiImeXAI8H3DTuG1QRSwMNuCGJJPbIzcyYIDFz5ESsYkeJ1tF2ud8t49xLtkug5ibb/wFN1bX67Zr+MNi/xOol3yeZZr2k7WV1jYMneYA4OA/XUHVO4go8m//0q8f+jkv7YAR6krEbz30bj5MsvO844q+G83STJo/5Pty/CuQAQX8GY2ULbEiYM0kEPv+9wHW/gg9Kk9ch4x2Af4kV4xgp6anitj7eGdgX26Y+fPzUTy6PN2jBRotPjMtwZa8Pk5pm+0mGRHTsddw2llArB3QctK463hDny4B/W2TkzgavJ/4f69yDWKM9JgbtaHW0LD2IbLO38zIg6w6w6QU77Fyfo6eNfSnr5U+QTAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"56de4dd4674a769de3c7bfbe2f6ec3b8\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6940:3554364:53DB964A", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 13 Jul 2014 20:26:39 GMT", "date": "Fri, 01 Aug 2014 13:29:46 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406902922"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech"}, "recorded_at": "2014-08-01T13:29:46"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech/commits/65c0c7d58b3ef09a0b3d5f9779228f9d1a5ad552/comments?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA52U3Y6bMBCFXyVyL3oTYn5C+FGaPkFvqlSVWlWRwQYsgY1swzZFybN3DGy3odJukysMnPP5zJjh+4A6VaMUVca0OsWYtHxTclN12SaXDVaslRqX9VkIrvEnQrmWwvkqGyYcLpwjyysMOrg1Gke+FyTJDq2B1tSnW/Bf0Ldx3OBdmLt5RMM4C1jhJsTNAhoWSRQlvh8XCfVISGgY+u/s9tzMIZyXDJyidL5bo04zhdIB1bLkAsrVvGxIz1Wn/S3ktVp/68aBu0akJ4aoRfrpoZ5bY2m5FAaqHrvU4cn8sf/gAa1UM8NiUe5t4yDc0TgpEj9ku8T3ojhjzKNJQPIiAsOrR2A303gR+PUGL8SFrGv5BJRlUbdn/e9G+I8TQk5rLsoHKeAcsDQVg95CSRfbKK7N/aFG14Dt5cSp5Wg4MMXo3cFmH8R6EpBoGD/3EdhlOle8NVyK+wPeuIEmVUkE/0Ueo4FbA2ScxLsrHF3gZr2d0Lvtk23AreI9yc+2NYrljPfQ7AeRCz8QzbllMCdf7IhC67lhJ0IbO6YFqTW7rBHUwG3zUCq6ul6jmgtwTOuWmOp5Pf0K4KMA3P/+P2DLXDFioCJiwOe73tZxIyfwjq6ben7qx99A07X0TU0m6flkJxMw+/ZwrIh5r1darvaU1YfPBM5gj+1y1TBDNnvcHoA8ugz7aTd/sYzqSTdrbl5fr6Pgep0llx+/ASpIo5zKBQAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e3b4b0bd50c4aa9bc085a8875557d59b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6940:3554391:53DB964A", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 01 Aug 2014 13:29:46 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406902922"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/glynnis/Madison-Women-in-Tech/commits/65c0c7d58b3ef09a0b3d5f9779228f9d1a5ad552/comments?per_page=100"}, "recorded_at": "2014-08-01T13:29:46"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file From e08a0af4c239e98f8b16598475f74634d52b1419 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 1 Aug 2014 20:36:06 -0500 Subject: [PATCH 320/972] Rename Repository#iter_commit_activity --- HISTORY.rst | 1 + github3/repos/repo.py | 43 +++++++++++++++++++++---------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 8ed8eec3d..a7ba58b16 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -71,6 +71,7 @@ Old name New name ``Repository#iter_collaborators`` ``Repository#collaborators`` ``Repository#iter_comments`` ``Repository#comments`` ``Repository#iter_comments_on_commit`` ``Repository#comments_on_commit`` +``Repository#iter_commit_activity`` ``Repository#commit_activity`` ====================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index f23c5ca97..eef44791e 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -490,6 +490,27 @@ def commit(self, sha): json = self._json(self._get(url), 200) return RepoCommit(json, self) if json else None + def commit_activity(self, number=-1, etag=None): + """Iterate over last year of commit activity by week. + + See: http://developer.github.com/v3/repos/statistics/ + + .. note:: All statistics methods may return a 202. On those occasions, + you will not receive any objects. You should store your + iterator and check the new ``last_status`` attribute. If it + is a 202 you should wait before re-requesting. + + .. versionadded:: 0.7 + + :param int number: (optional), number of weeks to return. Default -1 + will return all of the weeks. + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of dictionaries + """ + url = self._build_url('stats', 'commit_activity', base_url=self._api) + return self._iter(int(number), url, dict, etag=etag) + def commit_comment(self, comment_id): """Get a single commit comment. @@ -1177,28 +1198,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_commit_activity(self, number=-1, etag=None): - """Iterate over last year of commit activity by week. - - See: http://developer.github.com/v3/repos/statistics/ - - :param int number: (optional), number of weeks to return. Default -1 - will return all of the weeks. - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of dictionaries - - .. note:: All statistics methods may return a 202. On those occasions, - you will not receive any objects. You should store your - iterator and check the new ``last_status`` attribute. If it - is a 202 you should wait before re-requesting. - - .. versionadded:: 0.7 - - """ - url = self._build_url('stats', 'commit_activity', base_url=self._api) - return self._iter(int(number), url, dict, etag=etag) - def iter_commits(self, sha=None, path=None, author=None, number=-1, etag=None, since=None, until=None): """Iterate over commits in this repository. From fc20feba7e86a486cca50890c19cd045ec0bbe60 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 1 Aug 2014 21:13:25 -0500 Subject: [PATCH 321/972] Add integration test for Repository#commit_activity --- tests/cassettes/Repository_commit_activity.json | 1 + tests/integration/test_repos_repo.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/cassettes/Repository_commit_activity.json diff --git a/tests/cassettes/Repository_commit_activity.json b/tests/cassettes/Repository_commit_activity.json new file mode 100644 index 000000000..49d90798c --- /dev/null +++ b/tests/cassettes/Repository_commit_activity.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YT3OzNhDGv4qHax3LmDi2mem87ant7T28vfTiESCMJoAYSdjjMPnufYQAg9+p/0S9ZBKi/enRanfZpfF44oXBxl9ufH/ulbRgXugduM7qKFhUZ2/upXWe77t/KH4o6JHLWq1eyWSVOJVMemHj5eLASzDGS0Ex26xel9tgOffokWoq97XMsS7TulIhIfahWlhqrZiMRalZqRexKEhNrPG3468+aAfZMQzWi/3XbbB+S7a7dLdas7fdyt9sI8b8ZBfQON3A4Gqvinf7WDg2U+RKcKaL/EqildaaXC1ORZ6LEyjXh7q3ERksjadbCi8PX6TAsiFCZwy+xZE+jaO40s+Laq0aXLDSe54YjsKFSZY8LayzgywTH58NkawSLbCOVCx5pbkonxc4sQZNyAMt+Qf9Gg3WChAj7XkprRWs2RGx+ry5NWtIJfmRxmfjGslixo9w9heRV/Yg6nNl0vpvBIVxPddsT5PCpGlKc8U+5167vcai9sEcWflo9E/LQMKGW8WG3886E+Us55Gk8jxLhZxx5LRMaYxYnZ1QZmYI19kfXP9ZR7Pfv/91DCAQ694HJTczt3X+JBmncgzpzp3cRCA9AYCkd3Z24hj7huBnl08xUp1GQlIt7hWN2wInoIaM/zSxpBktnIS3AIAyIdw82QIA4krV7KHQvn3wlqNInz9lXUS25D2SNbfRlgCtVKHOl4w5eXCANKSvykiHMs7csD2jIfa39rbpwUmqsQcmykXkxMGLkrSQhqiM2veQ3ruqM1TDmEAlS52lGsYA1dLxvluZBjIg8RLUuHonnT2DNJ1Hc1oeanpwow4Q3Lp5VR/ox90m5nbuXChAmg5O8qh2L3IXjlFqewfku5tLL5gLtG1Ibrc5dxwwamxaFxQFv9cX3CZ2iEnY/w9YE6fXaPP3/TbmvlzDaMilJtui39FdvNtV/V4naS57dOOCU0j0DNL8UlGdmcqFrSoqmYvoDkGaiKLZWiwWTcZo21YXTDpmsCUARWWcoWt00dn0DHQ9BdVtt54amQm691zQxMm3AwRAe40uWi1hHGMV5lQngS1gTCx4zpQWpVuNvVDG7FJonvL4kYnldrpNQM03xcuYzWmezxG1mscccYxe29wiGk7m5iFLwDHwmcBOKjlDSDt5XTLLaIidNGPJMIgke6oxQKyW/uplGbz4wQ9/F6634Tr4Byepq2Sy5vVluX1Z+j/8dehvwmBt1lS1ykaYYUkQvvrhcmuWoAJ2IYjf8AkCP/HZ46f5fjRSmK8GMFQquxj+djEL/+P7SGcW54ilq6B/fM/j9WvpvimkZqJgFdqE7kvLcMqgOi/g6QTjVyJitcAMTMzJ+AeWbtfBetIQxKIucR/+7m3unahG74pX7/hh30gMQ5/Zmqq9TVMv1LI2UyWeXMrA6OGJv/Nh4rNDW0d/26BKcilF972oRJJi3q9Y2bEHGVhop7XQ2IxWQDce9LK7UyQspXWu97Z5huwEXX8uKugumT5h7OvBhjbuOPpjbz//Bf5ChbM9EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"8914166a34218037e0ba45534e5dd5be\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6941:54A2B36:53DC4539", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Sat, 02 Aug 2014 01:56:09 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406948071"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-02T01:56:10"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/stats/commit_activity?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5WVzYocMQyE36XPPlj+leZVlj0sZE8J5JCFEELePZLnx2VNd7JNM7cpJH+uKr/83r68/fqxXV5isC/pj0J8DdvH94+3b9slh+3n+/vX7UK519pLifFPcKKrFEQRRI26pNOizjpob5Iuh+sRTOqZmRdRHidKgSi0QAlO1VAnkpsbVgaN8U1VARFXsRV3WHQFmKdIZ0+CSiKvMOYgXXSqGEUc9Vh+lJ3N7Qd3xbFQWmE8DmRAdi+YKVJfSZC5YVA8IsHUUlpJ5OvfhxQm9XkmTin1FQQN492+AvwqytjwrSgolFBVWxdfwAVzLrl5FqqwYRR6aHNYEhhWlOFKQ24k1EwLjoRHK02/JxtG3dI+dAZcMtdU6SgmHZ2BG1auuuCKw+D3wLopjEpoDd3PDAXWNXwGf5hx37rcY7NhoBKdIiNf6kUwFM7qrccVRlFNNhBuQ7wwTr0ewdA7Q3dAJjX9lhNc8Z4us+9+ulgKl5WGxuNmw4UGHEtiZPFBgXztpktik9P1KZTkqT5twduKcxKAEBKD7mOiAVHuKQj4HcpJUo2uP9u42xHjxReIIhO59rxCf1oQciy500F7DopzQXhJpOTkynMiPxaJ1aAvz7sQ2glJ1Jr/UZ6wXpp1IU1fSP+MXJtQHD4k0Xpx7Wmw04hiDgxhhLaQnourT+0I1Vx9gaeCWEkXS5W3hbFIGmVU4bm4VteeZO3y+A5WFGquPe+Kka/9iEhvrjv/e8VqdHWTb4s29hsenJNmS6tIR3kWu4eaDiyR6niKdx79Id2zbYmJRkufFPURYSd69BIwfziwxJzHBZ+bZEVxGoS+IK40P3FPupsrzc+ImM6WZomt0CjN17/0cfmi3woAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"deb45a42616a08e6fdc5dd536fd10381\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "55", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6941:54A2B6C:53DC4539", "cache-control": "public, max-age=60, s-maxage=60", "date": "Sat, 02 Aug 2014 01:56:09 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406948071"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/stats/commit_activity?per_page=100"}, "recorded_at": "2014-08-02T01:56:10"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 46caba19a..cd7e7e55a 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -65,6 +65,15 @@ def test_comments_on_commit(self): for comment in repository.comments_on_commit(sha): assert isinstance(comment, github3.repos.comment.RepoComment) + def test_commit_activity(self): + """Test the ability to retrieve commit activity on a repo.""" + cassette_name = self.cassette_name('commit_activity') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for activity in repository.commit_activity(): + assert isinstance(activity, dict) + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() From 474cc6130a28b5d07f01bf7e1cf59601baec054b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 1 Aug 2014 21:52:44 -0500 Subject: [PATCH 322/972] Replace Repository#commit_activity unit tests --- tests/test_repos.py | 9 --------- tests/unit/test_repos_repo.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index 5bccd394e..e44ac9aed 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -1050,15 +1050,6 @@ def test_weekly_commit_count(self): self.assertEqual(w, {}) self.mock_assertions() - def test_iter_commit_activity(self): - self.response('commit_activity', _iter=True) - self.get(self.api + 'stats/commit_activity') - - w = next(self.repo.iter_commit_activity()) - assert isinstance(w, dict) - - self.mock_assertions() - def test_iter_contributor_statistics(self): self.response('contributor_statistics', _iter=True) self.get(self.api + 'stats/contributors') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 1e2cef365..c5c5c862d 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -232,3 +232,14 @@ def test_comments_on_commit(self): params={'per_page': 100}, headers={} ) + + def test_commit_activity(self): + """Test the ability to iterate over commit activity on a repo.""" + i = self.instance.commit_activity() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('stats/commit_activity'), + params={'per_page': 100}, + headers={} + ) From 8b58ba768cdb6235bb14b92ad31655d6fc2ee134 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 14:14:29 -0500 Subject: [PATCH 323/972] Rename Repository#iter_commits to commits - I realized timestamp_parameter is not working as I would expect it to --- HISTORY.rst | 1 + github3/repos/repo.py | 68 ++++++++++++------------- tests/cassettes/Repository_commits.json | 1 + tests/integration/test_repos_repo.py | 9 ++++ tests/test_repos.py | 2 + tests/unit/test_repos_repo.py | 26 ++++++++++ 6 files changed, 73 insertions(+), 34 deletions(-) create mode 100644 tests/cassettes/Repository_commits.json diff --git a/HISTORY.rst b/HISTORY.rst index a7ba58b16..64bee24ae 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -72,6 +72,7 @@ Old name New name ``Repository#iter_comments`` ``Repository#comments`` ``Repository#iter_comments_on_commit`` ``Repository#comments_on_commit`` ``Repository#iter_commit_activity`` ``Repository#commit_activity`` +``Repository#iter_commits`` ``Repository#commits`` ====================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index eef44791e..5a95c44f7 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -522,6 +522,40 @@ def commit_comment(self, comment_id): json = self._json(self._get(url), 200) return RepoComment(json, self) if json else None + def commits(self, sha=None, path=None, author=None, number=-1, etag=None, + since=None, until=None): + r"""Iterate over commits in this repository. + + :param str sha: (optional), sha or branch to start listing commits + from + :param str path: (optional), commits containing this path will be + listed + :param str author: (optional), GitHub login, real name, or email to + filter commits by (using commit author) + :param int number: (optional), number of comments to return. Default: + -1 returns all comments + :param str etag: (optional), ETag from a previous request to the same + endpoint + :param since: (optional), Only commits after this date will + be returned. This can be a `datetime` or an `ISO8601` formatted + date string. + :type since: datetime or string + :param until: (optional), Only commits before this date will + be returned. This can be a `datetime` or an `ISO8601` formatted + date string. + :type until: datetime or string + + :returns: generator of + :class:`RepoCommit `\ s + """ + params = {'sha': sha, 'path': path, 'author': author, + 'since': timestamp_parameter(since), + 'until': timestamp_parameter(until)} + + self._remove_none(params) + url = self._build_url('commits', base_url=self._api) + return self._iter(int(number), url, RepoCommit, params, etag) + def compare_commits(self, base, head): """Compare two commits. @@ -1198,40 +1232,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_commits(self, sha=None, path=None, author=None, number=-1, - etag=None, since=None, until=None): - """Iterate over commits in this repository. - - :param str sha: (optional), sha or branch to start listing commits - from - :param str path: (optional), commits containing this path will be - listed - :param str author: (optional), GitHub login, real name, or email to - filter commits by (using commit author) - :param int number: (optional), number of commits to return. Default: - -1 returns all commits - :param str etag: (optional), ETag from a previous request to the same - endpoint - :param since: (optional), Only commits after this date will - be returned. This can be a `datetime` or an `ISO8601` formatted - date string. - :type since: datetime or string - :param until: (optional), Only commits before this date will - be returned. This can be a `datetime` or an `ISO8601` formatted - date string. - :type until: datetime or string - - :returns: generator of - :class:`RepoCommit `\ s - """ - params = {'sha': sha, 'path': path, 'author': author, - 'since': timestamp_parameter(since), - 'until': timestamp_parameter(until)} - - self._remove_none(params) - url = self._build_url('commits', base_url=self._api) - return self._iter(int(number), url, RepoCommit, params, etag) - def iter_contributors(self, anon=False, number=-1, etag=None): """Iterate over the contributors to this repository. diff --git a/tests/cassettes/Repository_commits.json b/tests/cassettes/Repository_commits.json new file mode 100644 index 000000000..5b1d0d256 --- /dev/null +++ b/tests/cassettes/Repository_commits.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YQZOqOBDHv4rFdR0jMo5K1av39rS7t3eYvezFChAkNUCoJGg51Hz3/YcAgq9WncleLMX0L/90ukN3Go8nXhhs/OXG9+deSQvmhd6B66yOgkV19uZeWuf5vvtD8UNBj1zWavVMJqPEqWTSCxsvFwdegjEeCoqZZvW83AbLuUePVFO5r2WOcZnWlQoJsQ/VwlJrxWQsSs1KvYhFQWpijb8fv/mgHWTHMFgv9p+3wfol2e7S3WrNXnYrf7ONGPOTXUDjdAODq7kq3s1j4ZhMkSvBmS7yK4lWWmtyNTgVeS5OoFwv6t5EZLA0nm4pvDx8kQLLhgidMfgWS/owjuJKf15Ua9Vgg5Xe88RwFDZMsuTTwjo7yDLx8dEQySrRAutIxZJXmovy8wIn1qAJeaAlf6dfo8FaAWKkfV5KawVrdkSsft7cmjWkkvxI47NxjWQx40c4+4vIK3sQ9bkyaf03gsK4nmu2p0lh0jSluWIfc6+dXmNQ+2COrHw0+qfHQMKGXcWEP886E+Us55Gk8jxLhZxx5LRMaYxYnZ1wzMwQrrM/uP6zjma///zrGEAgxr0NSm5mbuv8STJO5RjSnT25iUB6AgBJb+zsxDH2DcFnl08xUp1GQlIt7h0atwVOQA0Z/zSxpBktnIS3AIAyIdw82QIA4krV7KHQvr3wlqNInz9lXUT2yHska26jLQFaqcI5XzLm5MEB0pD+VEY6lHHmhu0ZDbHf2t2mByepxh6YKBeREwcvStJCGqIyat9Deu+qzlANYwKVLHWWahgDVEvH/W5lGsiAxEtQY+uddPYM0nQezWl5qOnBjTpAsOvmVX2g73eLmNu5c6EAaSo4yaPa/ZC7cIxSWzsg391cesFcoG1BcrvMueOAUWHTuqAo+L264DaxQ0zC/n/Amji9Rpvf98uY+3INoyGXM9ke+h3dxbvdqd/rJM1ljq5dcAqJnkGa3yqqM3NyYaqKSuYiukOQJqIothaLRZMx2pbVBZOOGWwJQFEZZ6gaXXQ2PQNVT0F1W62nRmaC6j0XNHHy7QAB0G6ji1ZLGMdYhT7VSWALGBMLnjOlRel2xl4oY3YpNE95/EjHcjvdJqDmu+JlzOY0z+eIWs1jjjhGrW12EQUnc/OQJWAZuCawnUrOENJOXpfMMhpiO81YMjQiyZ5qNBCrpb96WgZPfvDq78L1NlwH/2AldZVMxjw/LbdPS//VX4f+JgzWZkxVq2yEsUNWr8tVuF6FzzszBCdgF4L4hisIfOLa45f+ftRSmFsDGCqVXQx/XMzC/7gf6cziHLF0FfSPz3m8fi3dN4XUTBSsQpnQ3bQMqwyq8wKeTtB+JSJWC/TAxKyMv2Podh2sJwVBLOoS++HvXubeiWrUrnj1jh/2hcTQ9JmpqdrbNPVCLWvTVeLJ5RgYPTzxNz50fLZp6+gvG5ySXErR3ReVSFL0+xUrO/YgY2sbR+WFxmY0ArrxXy+7W0XCUlrnem+LZ8hOUPXnooLukukT2r4ebGjjiqNf9vbjX+XI0jk9EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"41e49ac65c74aa0b5c09fd76032b9888\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:3389:61AB299:53DCF634", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Sat, 02 Aug 2014 14:31:17 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406993477"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-02T14:31:17"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/commits?per_page=25"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"6d922c419e0c661d60ab584877ef846b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:3389:61AB2BE:53DCF635", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 28 Jun 2014 18:02:24 GMT", "link": "; rel=\"next\"", "date": "Sat, 02 Aug 2014 14:31:17 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1406993477"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/commits?per_page=25"}, "recorded_at": "2014-08-02T14:31:17"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index cd7e7e55a..974647633 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -74,6 +74,15 @@ def test_commit_activity(self): for activity in repository.commit_activity(): assert isinstance(activity, dict) + def test_commits(self): + """Test the ability to retrieve commits on a repository.""" + cassette_name = self.cassette_name('commits') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for commit in repository.commits(number=25): + assert isinstance(commit, github3.repos.commit.RepoCommit) + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() diff --git a/tests/test_repos.py b/tests/test_repos.py index e44ac9aed..14189de43 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -1,4 +1,5 @@ import os +import pytest import github3 import pytest from github3 import repos @@ -550,6 +551,7 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() + @pytest.mark.xfail def test_iter_commits(self): self.response('commit', _iter=True) self.get(self.api + 'commits') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index c5c5c862d..34bff3df0 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -1,4 +1,7 @@ """Unit tests for Repositories.""" +import datetime +import pytest + from github3.repos.repo import Repository from .helper import (UnitHelper, UnitIteratorHelper, create_url_helper) @@ -243,3 +246,26 @@ def test_commit_activity(self): params={'per_page': 100}, headers={} ) + + def test_commits(self): + """Test the ability to iterate over commits in a repo.""" + i = self.instance.commits() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('commits'), + params={'per_page': 100}, + headers={} + ) + + @pytest.mark.xfail + def test_commits_since_datetime(self): + """Test the ability to iterate over commits in a repo since a date.""" + i = self.instance.commits(since=datetime.datetime(2014, 8, 1)) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('commits'), + params={'per_page': 100, 'since': '2014-08-01T00:00:00Z'}, + headers={} + ) From 00588a5d3dadedb3bbdb868779ee97952fe3bdb7 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 15:07:19 -0500 Subject: [PATCH 324/972] Update github3.utils - Correct timestamp_parameter - Add docstrings to most things --- github3/utils.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/github3/utils.py b/github3/utils.py index 554abfc36..1c94ac862 100644 --- a/github3/utils.py +++ b/github3/utils.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +"""A collection of useful utilities.""" from collections import Callable from datetime import datetime, timedelta, tzinfo from requests.compat import basestring @@ -12,14 +13,27 @@ def timestamp_parameter(timestamp, allow_none=True): - + """Function to check the conformance of timestamps passed by users. + + This will check that a string is a valid format and allow users to pass a + datetime object which we will then convert to a proper ISO8601 date-time + string. + + :param timestamp: string to be validated or datetime object to be + converted. + :param bool allow_none: whether or not to allow timestamp to be None. + Default: ``True`` + :returns: valid ISO8601 string + :rtype: str + :raises: ValueError + """ if timestamp is None: if allow_none: return None raise ValueError("Timestamp value cannot be None") if isinstance(timestamp, datetime): - return timestamp.isoformat() + return timestamp.isoformat() + 'Z' if isinstance(timestamp, basestring): if not ISO_8601.match(timestamp): @@ -31,6 +45,7 @@ def timestamp_parameter(timestamp, allow_none=True): class UTC(tzinfo): + """Yet another UTC reimplementation, to avoid a dependency on pytz or dateutil.""" @@ -50,6 +65,15 @@ def utcoffset(self, dt): def stream_response_to_file(response, path=None): + """Stream a response body to the specified file. + + Either use the ``path`` provided or use the name provided in the + ``Content-Disposition`` header. + + :param response: A Response object from requests + :type response: requests.models.Response + :param str path: The full path and file name used to save the response + """ pre_opened = False fd = None if path: From a5dbd2fbab79c2f428500612999d89e4a6420c8e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 15:07:40 -0500 Subject: [PATCH 325/972] Fix timestamp test --- tests/unit/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 815b15001..dfd52c140 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -10,7 +10,7 @@ class TestTimestampConverter: def test_datetimes(self): timestamp = datetime(2010, 6, 1, 12, 15, 30) - assert '2010-06-01T12:15:30' == timestamp_parameter(timestamp) + assert '2010-06-01T12:15:30Z' == timestamp_parameter(timestamp) def test_valid_datestring(self): testvals = ( From 58b932fcd3a64290aeb61b8df6b4430a210b5d4b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 15:08:07 -0500 Subject: [PATCH 326/972] Allow our new unit test to run --- tests/unit/test_repos_repo.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 34bff3df0..7b1979d9f 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -1,6 +1,5 @@ """Unit tests for Repositories.""" import datetime -import pytest from github3.repos.repo import Repository @@ -258,7 +257,6 @@ def test_commits(self): headers={} ) - @pytest.mark.xfail def test_commits_since_datetime(self): """Test the ability to iterate over commits in a repo since a date.""" i = self.instance.commits(since=datetime.datetime(2014, 8, 1)) From 8fc61505927d951a7e04aaeaa7cb3344e92f4bfa Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 16:16:46 -0500 Subject: [PATCH 327/972] Finish replacing old Repository#commits unit test --- tests/test_repos.py | 32 -------------------------------- tests/unit/test_repos_repo.py | 21 +++++++++++++++++---- 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index 14189de43..ce58d1e74 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -1,5 +1,4 @@ import os -import pytest import github3 import pytest from github3 import repos @@ -551,37 +550,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - @pytest.mark.xfail - def test_iter_commits(self): - self.response('commit', _iter=True) - self.get(self.api + 'commits') - self.conf = {'params': {'per_page': 100}} - - c = next(self.repo.iter_commits()) - assert isinstance(c, repos.commit.RepoCommit) - self.mock_assertions() - - self.conf = {'params': {'sha': 'fakesha', 'path': '/', - 'per_page': 100}} - c = next(self.repo.iter_commits('fakesha', '/')) - self.mock_assertions() - - since = datetime(2013, 6, 1, 0, 0, 0) - until = datetime(2013, 6, 2, 0, 0, 0) - self.conf = {'params': {'since': '2013-06-01T00:00:00', - 'until': '2013-06-02T00:00:00', - 'per_page': 100}} - c = next(self.repo.iter_commits(since=since, until=until)) - self.mock_assertions() - - since = '2013-06-01T00:00:00' - until = '2013-06-02T00:00:00' - self.conf = {'params': {'since': '2013-06-01T00:00:00', - 'until': '2013-06-02T00:00:00', - 'per_page': 100}} - c = next(self.repo.iter_commits(since=since, until=until)) - self.mock_assertions() - def test_iter_contributors(self): self.response('user', _iter=True) self.get(self.api + 'contributors') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 7b1979d9f..3ef4658fe 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -257,13 +257,26 @@ def test_commits(self): headers={} ) - def test_commits_since_datetime(self): - """Test the ability to iterate over commits in a repo since a date.""" - i = self.instance.commits(since=datetime.datetime(2014, 8, 1)) + def test_commits_since_until_datetime(self): + """Test the ability to iterate over repo's commits in a date range.""" + i = self.instance.commits(since=datetime.datetime(2014, 8, 1), + until='2014-09-01T00:00:00Z') self.get_next(i) self.session.get.assert_called_once_with( url_for('commits'), - params={'per_page': 100, 'since': '2014-08-01T00:00:00Z'}, + params={'per_page': 100, 'since': '2014-08-01T00:00:00Z', + 'until': '2014-09-01T00:00:00Z'}, + headers={} + ) + + def test_commits_sha_path(self): + """Test the ability to filter commits by branch and path.""" + i = self.instance.commits(sha='branch', path='tests/') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('commits'), + params={'per_page': 100, 'sha': 'branch', 'path': 'tests/'}, headers={} ) From d4aaa3752219026a8bec622a53eee0c5dbd919b1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 16:21:14 -0500 Subject: [PATCH 328/972] Remove datetime from old test file --- tests/test_repos.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_repos.py b/tests/test_repos.py index ce58d1e74..dae6d1d76 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -2,7 +2,6 @@ import github3 import pytest from github3 import repos -from datetime import datetime from tests.utils import (BaseCase, load, mock) From 5dc4271a8b32e7ef822b43ccb8b6726a48598a98 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 19:22:35 -0500 Subject: [PATCH 329/972] Rename Repository#iter_contributors to Repository#contributors --- HISTORY.rst | 1 + github3/repos/repo.py | 34 ++++++++++---------- tests/cassettes/Repository_contributors.json | 1 + tests/integration/test_repos_repo.py | 9 ++++++ tests/test_repos.py | 16 --------- tests/unit/test_repos_repo.py | 22 +++++++++++++ 6 files changed, 50 insertions(+), 33 deletions(-) create mode 100644 tests/cassettes/Repository_contributors.json diff --git a/HISTORY.rst b/HISTORY.rst index 64bee24ae..88d564dde 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -73,6 +73,7 @@ Old name New name ``Repository#iter_comments_on_commit`` ``Repository#comments_on_commit`` ``Repository#iter_commit_activity`` ``Repository#commit_activity`` ``Repository#iter_commits`` ``Repository#commits`` +``Repository#iter_contributors`` ``Repository#contributors`` ====================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 5a95c44f7..925f023f8 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -595,6 +595,23 @@ def contents(self, path, ref=None): return dict((j.get('name'), Contents(j, self)) for j in json) return None + def contributors(self, anon=False, number=-1, etag=None): + r"""Iterate over the contributors to this repository. + + :param bool anon: (optional), True lists anonymous contributors as + well + :param int number: (optional), number of contributors to return. + Default: -1 returns all contributors + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`User `\ s + """ + url = self._build_url('contributors', base_url=self._api) + params = {} + if anon: + params = {'anon': 'true'} + return self._iter(int(number), url, User, params, etag) + @requires_auth def create_blob(self, content, encoding): """Create a blob with ``content``. @@ -1232,23 +1249,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_contributors(self, anon=False, number=-1, etag=None): - """Iterate over the contributors to this repository. - - :param bool anon: (optional), True lists anonymous contributors as - well - :param int number: (optional), number of contributors to return. - Default: -1 returns all contributors - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`User `\ s - """ - url = self._build_url('contributors', base_url=self._api) - params = {} - if anon: - params = {'anon': True} - return self._iter(int(number), url, User, params, etag) - def iter_contributor_statistics(self, number=-1, etag=None): """Iterate over the contributors list. diff --git a/tests/cassettes/Repository_contributors.json b/tests/cassettes/Repository_contributors.json new file mode 100644 index 000000000..1e38e7cb0 --- /dev/null +++ b/tests/cassettes/Repository_contributors.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YQZOqOBDHv4rFdR0jMo5K1av39rS7t3eYvezFChAkNUCoJGg51Hz3/YcAgq9WncleLMX0L/90ukN3Go8nXhhs/OXG9+deSQvmhd6B66yOgkV19uZeWuf5vvtD8UNBj1zWavVMJqPEqWTSCxsvFwdegjEeCoqZZvW83AbLuUePVFO5r2WOcZnWlQoJsQ/VwlJrxWQsSs1KvYhFQWpijb8fv/mgHWTHMFgv9p+3wfol2e7S3WrNXnYrf7ONGPOTXUDjdAODq7kq3s1j4ZhMkSvBmS7yK4lWWmtyNTgVeS5OoFwv6t5EZLA0nm4pvDx8kQLLhgidMfgWS/owjuJKf15Ua9Vgg5Xe88RwFDZMsuTTwjo7yDLx8dEQySrRAutIxZJXmovy8wIn1qAJeaAlf6dfo8FaAWKkfV5KawVrdkSsft7cmjWkkvxI47NxjWQx40c4+4vIK3sQ9bkyaf03gsK4nmu2p0lh0jSluWIfc6+dXmNQ+2COrHw0+qfHQMKGXcWEP886E+Us55Gk8jxLhZxx5LRMaYxYnZ1wzMwQrrM/uP6zjma///zrGEAgxr0NSm5mbuv8STJO5RjSnT25iUB6AgBJb+zsxDH2DcFnl08xUp1GQlIt7h0atwVOQA0Z/zSxpBktnIS3AIAyIdw82QIA4krV7KHQvr3wlqNInz9lXUT2yHska26jLQFaqcI5XzLm5MEB0pD+VEY6lHHmhu0ZDbHf2t2mByepxh6YKBeREwcvStJCGqIyat9Deu+qzlANYwKVLHWWahgDVEvH/W5lGsiAxEtQY+uddPYM0nQezWl5qOnBjTpAsOvmVX2g73eLmNu5c6EAaSo4yaPa/ZC7cIxSWzsg391cesFcoG1BcrvMueOAUWHTuqAo+L264DaxQ0zC/n/Amji9Rpvf98uY+3INoyGXM9ke+h3dxbvdqd/rJM1ljq5dcAqJnkGa3yqqM3NyYaqKSuYiukOQJqIothaLRZMx2pbVBZOOGWwJQFEZZ6gaXXQ2PQNVT0F1W62nRmaC6j0XNHHy7QAB0G6ji1ZLGMdYhT7VSWALGBMLnjOlRel2xl4oY3YpNE95/EjHcjvdJqDmu+JlzOY0z+eIWs1jjjhGrW12EQUnc/OQJWAZuCawnUrOENJOXpfMMhpiO81YMjQiyZ5qNBCrpb96WgZPfvDq78L1NlwH/2AldZVMxjw/LbdPS//VX4f+JgzWZkxVq2yEsUNWrys/XC3D9YsZghOwC0F8wxUEPnHt8Ut/P2opzK0BDJXKLoY/Lmbhf9yPdGZxjli6CvrH5zxev5bum0JqJgpWoUzoblqGVQbVeQFPJ2i/EhGrBXpgYlbG3zF0uw7Wk4IgFnWJ/fB3L3PvRDVqV7x6xw/7QmJo+szUVO1tmnqhlrXpKvHkcgyMHp74Gx86Ptu0dfSXDU5JLqXo7otKJCn6/YqVHXuQsbWNo/JCYzMaAd34r5fdrSJhKa1zvbfFM2QnqPpzUUF3yfQJbV8PNrRxxdEve/vxL71lBEs9EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d1edbbfe6b8872b92e28e817dcb5be22\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B99:39DD921:53DD56D9", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Sat, 02 Aug 2014 21:23:37 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407018217"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-02T21:23:38"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/contributors?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63dXW/juBUG4P+S68FG/BLJARYF2l72okDRq6JYkBSVeOLYge1kZnew/71HEilLsuqIPASK7WKg950z2XkgW6Ko//x82B+fdoeHrw/n3dOr+did3s+UP3x52DUPXymvFKu+PJgPczGn395Pezju+XJ5O399fBx+8fzL0+7y/G7fz/7kjoeLP1x+ccfXx/fHIfyXj18JtD2dQkdX++AIV0zUjdKtpsLXmhKprPek0cy4VkJg8Xu97cLvM5TDb3Z+XAz8fHndL0YcRusji4Pb435//A4tyz/UZ7/R45iEIYd/3x2eMlsg+fPxeHn28LOFP9Kf3Q9qd76kD9Wnfj52//fbrul6zvAf7OSb5MFCDsb6foCJfj6e/NuxL3y3Z3favV12x0P6gLM0tB1PT+aw+8PktUH6DCXdaOmj9ClI+w/4u5oeH2I/H99Ouw/jfu9+NCfv/O4DftiZlYs8NF5+f/Pg5N/wl6L70e8u/jfTvHZMW7M/+y8PHbXTzr73P7+Hr4Qq8eeXq2V/Nu7iX87GQrwjVystNMmUPIRXJVdeeEIb4XirtPecCSpbVZlGcOGFZfDbb5A8G/e+49mhSYqvyXzDNx0YwZMylN9JTzm909Kp/By7k65UuZNouttJuIza2TQz8xlm+UysfdrtrT9dgldWEyZ5ptchvOq1rkjNG0m1Na1RThHPJGsdbarKt1a7bV4nw97XOjkwyWrM5UtdNGCcjlUopWNLOaPXSqzQsSnV5xhM1zlGy9icTIKVSevpufQM85nuA0P/ibiqaq4zXQ7hVZeGU8dtQ9rGUimIEkZIbilTghNlWLPN5TjqfZXjYUkmh1S+yFke4zEUoTSGjnIWYyFWYuhJdRhi6QpDsIzBcQq0QDIV6MxpvzuOn2Thy6LIFFirLrwqkBhGjDDacmGFNVI5WtdNK5QV1FfCbxM4jnpf4HhYksAhlS9wlscIDEUogaGjnMBYiBUYelIFhli6wBAsI3CcAiuQ0KnA5rg7v/r93r6fDvAXJ1BURBKiMikO4VWKmnMiuFGydi3V1DSe1ELAuZGQ1sCXzG0Ub2e+b/L2+CSci3i+0vUiDNdlI8rtsqwc4JtmrORlYSrpZT7d9rKhDPJla4HrR9VUu9n7b+bQnI5Px1f/R8DOK12x3E++Q3gVu6+U8I0WknFf6ZaZujaSa8e9M9oZtQ37zcj3rd8cnkR9ns6XvtqDgb4oRDlfdJVjvizGKl/0pSJfxNONLwrKEL+ZCns+V7PTuXne70yATShnuVeG++wq67ZqGLWyppZx1zrGpNOtNRWzjjnfbD2Hx0Hvc27iYUmMh1Q+31kewzYUobiGjnJMYyGWZ+hJZRli6RxDsAzDcYqi/H7ATZsn97wzr7vjR1BIGatzz659dlUh1560cMkXvtcyXrXOwo0ZAld7pVI1qaqNl3uX897HuDw6yeQsnE9zrQYjdN6HgjqvKud10YtlO69L1TtPpyOe58tYXs6EJT27SPxm3vfn7+Z0iR+XKeGwqiHzu/EQXhUtnSWSG+NYoz1z1lXe2oqrWrWSVE297ePybNz7nGeHJlm+JvMh33RgFE/KUIQnPeX8TkuxeCddqXIn0XS2k3AZs7NpsGD59CPwizXwv3DyZbVi+TdbIbtKFW7kaMe4YIzBRSsvWy+V1A3c5fG0pX7jyXcc9D7T8bAkokMqn+csj6EZilAsQ0c5krEQyzH0pFIMsXSGIViG4DgFlh+b8nu1xx/xKrIQKvdEqbrsKj5dtcRxIz3RplHc19wxq7yhrfXU6I23c8KY9+mFg5LgdZl8dpM0Bl1fgyLXN5QDN9RhufUtqdj6UDq1PlYGWpigKLM3s29P/vd4mlOC0cyPpLASgdFVaU3L4U5NZbwgVMK1ne6Sj5XUEwVnO1jju/UTaZz0PrbrnyjJW4jlk5sXYNTFJhS8WFLO3tiI5ReLUgXGXDrCmCzj8DpHWYqX46u5xFUMXGgmc896Q3gVo6UV4bCsT1Ytb0gNaxqYa43UlYTbp3DNZyPGcdZPMI7HpWEcYgiMswIUxtCEwxhKCmKMjWiMoSgZY8hlYAzJQhjHObAYZ+sZLruLORzf46o+wipaZ54Y++yqxYoyAvc8BFykaTWrtIEFfpU30klNvNh6qWYy6n2MkwOTNMZcPsdFA8bjWIUCObaUE3mtxJIcm1JNjsF0lGO0jMrJJEVZwooDf3p+jx9Xaa2EzGTJ+vCqS1YZRg11rag5F6r1mrpuJbyorOTwS9vOkddZ77O8HpekMsTyUc4LMCZjE4pkLCkncmzEgoxFqR5jLp1jTJbReJ2jKMbDx667StKteldM8dzro3121SGva99KURNTWbgZ2ThhSEUJPKima9rQjV8cw5j3EYaDkgR2mXx+kzTGXl+Dgtc3lFM31GHJ9S2p3vpQOrY+VkZamKAos8ubv3QPeXbOuCQi9wJNn111xqRtK7jjD6vYda1qqxxcBXWWmtqJmpF22/kuznkfWjwqSVofyqc2jWOsDT0obENFOW2hD8ttqEn1NqTSwQ25MuLiDEXJweK6H+74/tY/XD2c3yQsP838pKlYF16VR2trCFOk1cZU1BqrGtVq3tK60o00Gz9pzsa9z292aJLBazIf4k0HRuOkDEVy0lPO5bQUi3PSlSp0Ek1nOgmXsTqbBgt29gCY6ar7FelxuRyBC5qaZ1+zGdKrZmsD9zJgQY1rGOMU9icxbWur2jpOGrixsfFsOZ/4E7SzP12a2msUwfamBOV20oaDOykqKHfaiqY7KUu2O8lm4J2kC+mdzVOW7wlufRyOHzv3HE+4mtA6+4Tbh1fxeiWs9NapxrjGGCVgFbrWupWuljXjG7cjMbN5P8E7OzYN7zWKwHtTgsI7acPhnRQVxDttReOdlCXjnWQz8E7ShfDO5imK96/+4Jvdy+VfftfsA19SCXheK/fJz5BeBSwsga0QLK11bWlju2uyLWkIdVLRitXdgr0N+wktZ75PeHl0EuJZOJ/xWg0G8rwPRXleVQ7zohfLeV6XCnqeTic9z5dBvZypKOu/mde/w25/zfl4+OdufzzEE7PiVfYaIdWHV10bDhd3rZQKnlRprTKUe9vA3kNO+7ZVduOy9ZWh79NeCSTpXubzgf+fJozxm0oU85u2ctJvq7HYbxpTvd8UpJO/qSij/qa2wNPd05W3/3h/Mefx2U+mqBDZX6OH9Cp4K2CnBrjibFTLBXXaEsLg2TOqFTywUm3dw2Ec9j7z8bAk3EMqn/Qsj4EcilB8Q0c5tLEQSzX0pAINsXSWIVgG4zhF0XNvA1uf+v23bpvb/q5PxWuRu8vuEF4l2FhXtxbuChEpJTwCahpqW/gaDE+EVpL7jWsBJ8PeRzg5MIlhzOVDXDRgKI5VKIxjSzmO10osyLEpleQYTEc5RsuwnExSGOaH3/947bcH7mXCx1WVe3YcwqsyCYetxuDKlLdMtBXsu9k2QrTO1MwaWC24WeZ12s9oXo9MtBmCGJzzCpzO2IXkGWtK+hw78UBjVbrQmMwhGrOljF5nKYv0+5txz++n+Bm2ZhXXuUiH8CpS2J1eW1t7wWCxrpbKSNodTblzsKBebEU6mfYTpJMj05DGIALpogKFdOzCIR1rCiK9dqKRjlXJSMdkBtIxWwjpZJaiSJ/Mdz9eLSaqlixzdQVsMAjhVaBKOc/h3g7nDB7ohK+ZxsL5VPKGCgen042rK+Kk93HGo5Jg9qF8lNM4BuTQg8I4VJSDGPqwCIeaVIBDKh3fkCsDL85QFN238/t+D2+lOMA/4tJdrlnNc+/UDOFVfFRXhHDGa3j1hNGAzsGFnkpWSsLWJLAkatuNmuXE9xEuj07COAvno1yrweCc96GQzqvKYV30YtHO61LxztPpiOf5MpiXM5VF3e7j89tUSp79UoghvGq5gX0SYJM+ygxsd820YcpSBXvQt5bCPry6e4fMhpuu34ZBPyE8HJQmFzIIsNc0ymlXg+PZNRRU2dehMXYtyQa7UAa9LlZI3DBBWWgHeBMXrFMK135gwTzNffisz65Sk7WUlrO2hu+sDScOtiWBvTEpnDLh0RdlNu4J9O066ifcrgemkQs5BLt5A4perMLxiy0FCY6VaIaxKZliDGZwjNFCJK+TlGX5Cnvav8WFRzUsyq1z75WQIb0KU8AXTdvCjrWthNcn8W6JAjwkyrXysNTY+40vYPkWh/2EZTwsDWWfQpCc5lEghyIcx6GjIMZQiKY49CRDHGIZDIdgIYRxiqIED+SlindE4ANh7lmxe6nD+lnRVfCyULiyyqloBVxdFbA+33J4BQs8FAqvKtPbPoCGMe/TCwclwesy+ewmaQy6vgZFrm8oB26ow3LrW1Kx9aF0an2sDLQwQVlmu5edM+MbAOHNJ3Xuw6CsD6+e6GSlrdPdVaGqexRN1soR7+Cx0FprUsuNJ7rDOOsn3Mbj0sQNMQS6WQHKXWjC0QslBfXFRjTAUJRsMOQyGIZkIYnjHEUxGuvP425dsCOByqXYZ1clcmuocaSFF//BSlh4i27F4QwIK90F/CJsoLftrDcOeh/ieFiSwyGVz3CWxygMRSiEoaOcwViIJRh6UgWGWDrAECzjb5yiKL8Wnjp5eYk7AREN2/mI3O3yQnrVoKoUtxq2yjPM1xJ26YIrrHBvv/WtsHBvY+MDY9dp7yO8HpekMMTyGc4LMA5jEwpiLCkncWzEUoxFqRZjLh1jTJbReJ2jKEfYuXJnzvFl8rB9AbxrIPOG/hBexWi8a4i0VkkB2+M12vkWtkrn8PYgeG2QVN130A33Ia6z3sd4PS4JY4jlY5wXYDDGJhTGWFIO49iIxRiLUjHGXDrGmCyD8ToHHuN//weYmtk2qoUAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ef86cd868565f93545eee221465f4c2b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B99:39DD934:53DD56D9", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Sat, 02 Aug 2014 21:23:37 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407018217"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/contributors?per_page=100"}, "recorded_at": "2014-08-02T21:23:38"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 974647633..e071d1aa3 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -83,6 +83,15 @@ def test_commits(self): for commit in repository.commits(number=25): assert isinstance(commit, github3.repos.commit.RepoCommit) + def test_contributors(self): + """Test the ability to retrieve the contributors to a repository.""" + cassette_name = self.cassette_name('contributors') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for contributor in repository.contributors(): + assert isinstance(contributor, github3.users.User) + def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" self.basic_login() diff --git a/tests/test_repos.py b/tests/test_repos.py index dae6d1d76..468ae7cdd 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -549,22 +549,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_contributors(self): - self.response('user', _iter=True) - self.get(self.api + 'contributors') - self.conf = {'params': {'per_page': 100}} - - u = next(self.repo.iter_contributors()) - assert isinstance(u, github3.users.User) - self.mock_assertions() - - self.conf = {'params': {'anon': True, 'per_page': 100}} - next(self.repo.iter_contributors(True)) - self.mock_assertions() - - next(self.repo.iter_contributors('true value')) - self.mock_assertions() - def test_iter_events(self): self.response('event', _iter=True) self.get(self.api + 'events') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 3ef4658fe..29fb6aff3 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -280,3 +280,25 @@ def test_commits_sha_path(self): params={'per_page': 100, 'sha': 'branch', 'path': 'tests/'}, headers={} ) + + def test_contributors(self): + """Test the ability to iterate over contributors to a repository.""" + i = self.instance.contributors() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('contributors'), + params={'per_page': 100}, + headers={} + ) + + def test_contributors_with_anon(self): + """Test the ability to iterate over anonymous contributors.""" + i = self.instance.contributors(anon=True) + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('contributors'), + params={'per_page': 100, 'anon': 'true'}, + headers={} + ) From eaf9e66a1bc6b56ed78469f763484163a76eb373 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 20:46:26 -0500 Subject: [PATCH 330/972] Rename Repository#iter_contributor_statistics --- HISTORY.rst | 113 +++++++++--------- github3/repos/repo.py | 45 ++++--- .../Repository_contributor_statistics.json | 1 + tests/integration/test_repos_repo.py | 9 ++ tests/test_repos.py | 9 -- tests/unit/test_repos_repo.py | 11 ++ 6 files changed, 100 insertions(+), 88 deletions(-) create mode 100644 tests/cassettes/Repository_contributor_statistics.json diff --git a/HISTORY.rst b/HISTORY.rst index 88d564dde..e81045375 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -20,62 +20,63 @@ Breaking Changes - All methods and functions starting with ``iter_`` have been renamed. -====================================== ============================================== -Old name New name -====================================== ============================================== -``github3.iter_all_repos`` ``github3.all_repositories`` -``github3.iter_all_users`` ``github3.all_users`` -``github3.iter_events`` ``github3.all_events`` -``github3.iter_followers`` ``github3.followers_of`` -``github3.iter_following`` ``github3.followed_by`` -``github3.iter_repo_issues`` ``github3.repository_issues`` -``github3.iter_orgs`` ``github3.organizations_with`` -``github3.iter_user_repos`` ``github3.repositories_by`` -``github3.iter_starred`` ``github3.starred_by`` -``github3.iter_subscriptions`` ``github3.subscriptions_for`` -``Gist#iter_comments`` ``Gist#comments`` -``Gist#iter_commits`` ``Gist#commits`` -``Gist#iter_files`` ``Gist#files`` -``Gist#iter_forks`` ``Gist#forks`` -``GitHub#iter_all_repos`` ``GitHub#all_repositories`` -``GitHub#iter_all_users`` ``GitHub#all_users`` -``GitHub#iter_authorizations`` ``GitHub#authorizations`` -``GitHub#iter_emails`` ``GitHub#emails`` -``GitHub#iter_events`` ``GitHub#events`` -``GitHub#iter_followers`` ``GitHub#{followers,followers_of}`` -``GitHub#iter_following`` ``GitHub#{following,followed_by}`` -``GitHub#iter_gists`` ``GitHub#{gists,gists_by,public_gists}`` -``GitHub#iter_notifications`` ``GitHub#notifications`` -``GitHub#iter_org_issues`` ``GitHub#organization_issues`` -``GitHub#iter_issues`` ``GitHub#issues`` -``GitHub#iter_user_issues`` ``GitHub#user_issues`` -``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` -``GitHub#iter_keys`` ``GitHub#keys`` -``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` -``GitHub#iter_repos`` ``GitHub#reposistories`` -``GitHub#iter_user_repos`` ``GitHub#repositories_by`` -``GitHub#iter_user_teams`` ``GitHub#user_teams`` -``Organization#iter_members`` ``Organization#members`` -``Organization#iter_public_members`` ``Organization#public_members`` -``Organization#iter_repos`` ``Organization#repositories`` -``Organization#iter_teams`` ``Organization#teams`` -``PullRequest#iter_comments`` ``PullRequest#review_comments`` -``PullRequest#iter_commits`` ``PullRequest#commits`` -``PullRequest#iter_files`` ``PullRequest#files`` -``PullRequest#iter_issue_comments`` ``PullRequest#issue_comments`` -``Team#iter_members`` ``Team#members`` -``Team#iter_repos`` ``Team#repositories`` -``Repository#iter_assignees`` ``Repository#assignees`` -``Repository#iter_branches`` ``Repository#branches`` -``Repository#iter_code_frequency`` ``Repository#code_frequency`` -``Repository#iter_collaborators`` ``Repository#collaborators`` -``Repository#iter_comments`` ``Repository#comments`` -``Repository#iter_comments_on_commit`` ``Repository#comments_on_commit`` -``Repository#iter_commit_activity`` ``Repository#commit_activity`` -``Repository#iter_commits`` ``Repository#commits`` -``Repository#iter_contributors`` ``Repository#contributors`` - -====================================== ============================================== +========================================== ============================================== +Old name New name +========================================== ============================================== +``github3.iter_all_repos`` ``github3.all_repositories`` +``github3.iter_all_users`` ``github3.all_users`` +``github3.iter_events`` ``github3.all_events`` +``github3.iter_followers`` ``github3.followers_of`` +``github3.iter_following`` ``github3.followed_by`` +``github3.iter_repo_issues`` ``github3.repository_issues`` +``github3.iter_orgs`` ``github3.organizations_with`` +``github3.iter_user_repos`` ``github3.repositories_by`` +``github3.iter_starred`` ``github3.starred_by`` +``github3.iter_subscriptions`` ``github3.subscriptions_for`` +``Gist#iter_comments`` ``Gist#comments`` +``Gist#iter_commits`` ``Gist#commits`` +``Gist#iter_files`` ``Gist#files`` +``Gist#iter_forks`` ``Gist#forks`` +``GitHub#iter_all_repos`` ``GitHub#all_repositories`` +``GitHub#iter_all_users`` ``GitHub#all_users`` +``GitHub#iter_authorizations`` ``GitHub#authorizations`` +``GitHub#iter_emails`` ``GitHub#emails`` +``GitHub#iter_events`` ``GitHub#events`` +``GitHub#iter_followers`` ``GitHub#{followers,followers_of}`` +``GitHub#iter_following`` ``GitHub#{following,followed_by}`` +``GitHub#iter_gists`` ``GitHub#{gists,gists_by,public_gists}`` +``GitHub#iter_notifications`` ``GitHub#notifications`` +``GitHub#iter_org_issues`` ``GitHub#organization_issues`` +``GitHub#iter_issues`` ``GitHub#issues`` +``GitHub#iter_user_issues`` ``GitHub#user_issues`` +``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` +``GitHub#iter_keys`` ``GitHub#keys`` +``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` +``GitHub#iter_repos`` ``GitHub#reposistories`` +``GitHub#iter_user_repos`` ``GitHub#repositories_by`` +``GitHub#iter_user_teams`` ``GitHub#user_teams`` +``Organization#iter_members`` ``Organization#members`` +``Organization#iter_public_members`` ``Organization#public_members`` +``Organization#iter_repos`` ``Organization#repositories`` +``Organization#iter_teams`` ``Organization#teams`` +``PullRequest#iter_comments`` ``PullRequest#review_comments`` +``PullRequest#iter_commits`` ``PullRequest#commits`` +``PullRequest#iter_files`` ``PullRequest#files`` +``PullRequest#iter_issue_comments`` ``PullRequest#issue_comments`` +``Team#iter_members`` ``Team#members`` +``Team#iter_repos`` ``Team#repositories`` +``Repository#iter_assignees`` ``Repository#assignees`` +``Repository#iter_branches`` ``Repository#branches`` +``Repository#iter_code_frequency`` ``Repository#code_frequency`` +``Repository#iter_collaborators`` ``Repository#collaborators`` +``Repository#iter_comments`` ``Repository#comments`` +``Repository#iter_comments_on_commit`` ``Repository#comments_on_commit`` +``Repository#iter_commit_activity`` ``Repository#commit_activity`` +``Repository#iter_commits`` ``Repository#commits`` +``Repository#iter_contributor_statistics`` ``Repository#contributor_statistics`` +``Repository#iter_contributors`` ``Repository#contributors`` + +========================================== ============================================== - ``github3.login`` has been simplified and split into two functions: diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 925f023f8..20abb8ac2 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -595,6 +595,28 @@ def contents(self, path, ref=None): return dict((j.get('name'), Contents(j, self)) for j in json) return None + def contributor_statistics(self, number=-1, etag=None): + """Iterate over the contributors list. + + See also: http://developer.github.com/v3/repos/statistics/ + + .. note:: All statistics methods may return a 202. On those occasions, + you will not receive any objects. You should store your + iterator and check the new ``last_status`` attribute. If it + is a 202 you should wait before re-requesting. + + .. versionadded:: 0.7 + + :param int number: (optional), number of weeks to return. Default -1 + will return all of the weeks. + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`ContributorStats ` + """ + url = self._build_url('stats', 'contributors', base_url=self._api) + return self._iter(int(number), url, ContributorStats, etag=etag) + def contributors(self, anon=False, number=-1, etag=None): r"""Iterate over the contributors to this repository. @@ -1249,29 +1271,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_contributor_statistics(self, number=-1, etag=None): - """Iterate over the contributors list. - - See also: http://developer.github.com/v3/repos/statistics/ - - :param int number: (optional), number of weeks to return. Default -1 - will return all of the weeks. - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of - :class:`ContributorStats ` - - .. note:: All statistics methods may return a 202. On those occasions, - you will not receive any objects. You should store your - iterator and check the new ``last_status`` attribute. If it - is a 202 you should wait before re-requesting. - - .. versionadded:: 0.7 - - """ - url = self._build_url('stats', 'contributors', base_url=self._api) - return self._iter(int(number), url, ContributorStats, etag=etag) - def iter_deployments(self, number=-1, etag=None): """Iterate over deployments for this repository. diff --git a/tests/cassettes/Repository_contributor_statistics.json b/tests/cassettes/Repository_contributor_statistics.json new file mode 100644 index 000000000..c526e0ff5 --- /dev/null +++ b/tests/cassettes/Repository_contributor_statistics.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YQZOqOBDHv4rFdR0jMo5K1av39rS7t3eYvezFChAkNUCoJGg51Hz3/YcAgq9WncleLMX0L/90ukN3Go8nXhhs/OXG9+deSQvmhd6B66yOgkV19uZeWuf5vvtD8UNBj1zWavVMJqPEqWTSCxsvFwdegjEeCoqZZvW83AbLuUePVFO5r2WOcZnWlQoJsQ/VwlJrxWQsSs1KvYhFQWpijb8fv/mgHWTHMFgv9p+3wfol2e7S3WrNXnYrf7ONGPOTXUDjdAODq7kq3s1j4ZhMkSvBmS7yK4lWWmtyNTgVeS5OoFwv6t5EZLA0nm4pvDx8kQLLhgidMfgWS/owjuJKf15Ua9Vgg5Xe88RwFDZMsuTTwjo7yDLx8dEQySrRAutIxZJXmovy8wIn1qAJeaAlf6dfo8FaAWKkfV5KawVrdkSsft7cmjWkkvxI47NxjWQx40c4+4vIK3sQ9bkyaf03gsK4nmu2p0lh0jSluWIfc6+dXmNQ+2COrHw0+qfHQMKGXcWEP886E+Us55Gk8jxLhZxx5LRMaYxYnZ1wzMwQrrM/uP6zjma///zrGEAgxr0NSm5mbuv8STJO5RjSnT25iUB6AgBJb+zsxDH2DcFnl08xUp1GQlIt7h0atwVOQA0Z/zSxpBktnIS3AIAyIdw82QIA4krV7KHQvr3wlqNInz9lXUT2yHska26jLQFaqcI5XzLm5MEB0pD+VEY6lHHmhu0ZDbHf2t2mByepxh6YKBeREwcvStJCGqIyat9Deu+qzlANYwKVLHWWahgDVEvH/W5lGsiAxEtQY+uddPYM0nQezWl5qOnBjTpAsOvmVX2g73eLmNu5c6EAaSo4yaPa/ZC7cIxSWzsg391cesFcoG1BcrvMueOAUWHTuqAo+L264DaxQ0zC/n/Amji9Rpvf98uY+3INoyGXM9ke+h3dxbvdqd/rJM1ljq5dcAqJnkGa3yqqM3NyYaqKSuYiukOQJqIothaLRZMx2pbVBZOOGWwJQFEZZ6gaXXQ2PQNVT0F1W62nRmaC6j0XNHHy7QAB0G6ji1ZLGMdYhT7VSWALGBMLnjOlRel2xl4oY3YpNE95/EjHcjvdJqDmu+JlzOY0z+eIWs1jjjhGrW12EQUnc/OQJWAZuCawnUrOENJOXpfMMhpiO81YMjQiyZ5qNBCrpb96WgZPfvDq78L1NlwH/2AldZVMxjw/LbdPS//VX4f+JgzWZkxVq2yEsUNWrys/XC3D9YsZghOwC0F8wxUEPnHt8Ut/P2opzK0BDJXKLoY/Lmbhf9yPdGZxjli6CvrH5zxev5bum0JqJgpWoUzoblqGVQbVeQFPJ2i/EhGrBXpgYlbG3zF0uw7Wk4IgFnWJ/fB3L3PvRDVqV7x6xw/7QmJo+szUVO1tmnqhlrXpKvHkcgyMHp74Gx86Ptu0dfSXDU5JLqXo7otKJCn6/YqVHXuQsbWNo/JCYzMaAd34r5fdrSJhKa1zvbfFM2QnqPpzUUF3yfQJbV8PNrRxxdEve/vxL71lBEs9EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d1edbbfe6b8872b92e28e817dcb5be22\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0445:8636B52:53DD928B", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Sun, 03 Aug 2014 01:38:19 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407033086"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-03T01:38:19"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/stats/contributors?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"72e92b765509bce6f98c6b7cad114a15\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "55", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0445:8636B82:53DD928B", "cache-control": "public, max-age=60, s-maxage=60", "date": "Sun, 03 Aug 2014 01:38:19 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407033086"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/stats/contributors?per_page=100"}, "recorded_at": "2014-08-03T01:38:20"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index e071d1aa3..d04c3a2e1 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -83,6 +83,15 @@ def test_commits(self): for commit in repository.commits(number=25): assert isinstance(commit, github3.repos.commit.RepoCommit) + def test_contributor_statistics(self): + """Test the ability to retrieve contributor statistics for a repo.""" + cassette_name = self.cassette_name('contributor_statistics') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for stat in repository.contributor_statistics(): + assert isinstance(stat, github3.repos.stats.ContributorStats) + def test_contributors(self): """Test the ability to retrieve the contributors to a repository.""" cassette_name = self.cassette_name('contributors') diff --git a/tests/test_repos.py b/tests/test_repos.py index 468ae7cdd..77f72d1bf 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -1003,15 +1003,6 @@ def test_weekly_commit_count(self): self.assertEqual(w, {}) self.mock_assertions() - def test_iter_contributor_statistics(self): - self.response('contributor_statistics', _iter=True) - self.get(self.api + 'stats/contributors') - - s = next(self.repo.iter_contributor_statistics()) - assert isinstance(s, repos.stats.ContributorStats) - - self.mock_assertions() - class TestContents(BaseCase): def __init__(self, methodName='runTest'): diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 29fb6aff3..d1282669a 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -281,6 +281,17 @@ def test_commits_sha_path(self): headers={} ) + def test_contributor_statistics(self): + """Test the ability to iterate over contributor statistics.""" + i = self.instance.contributor_statistics() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('stats/contributors'), + params={'per_page': 100}, + headers={} + ) + def test_contributors(self): """Test the ability to iterate over contributors to a repository.""" i = self.instance.contributors() From 6bfcd6c0c2bf1bd5bb37955f83dface80dc0eb20 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 2 Aug 2014 21:37:57 -0500 Subject: [PATCH 331/972] Rename Repository#iter_deployments --- github3/repos/repo.py | 30 +++++++++---------- ...ments.json => Repository_deployments.json} | 0 tests/integration/test_repos_deployment.py | 4 +-- tests/integration/test_repos_repo.py | 18 +++++++++++ tests/unit/test_repos_repo.py | 13 ++++++++ 5 files changed, 48 insertions(+), 17 deletions(-) rename tests/cassettes/{Repository_iter_deployments.json => Repository_deployments.json} (100%) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 20abb8ac2..22c0d21e9 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1112,6 +1112,21 @@ def delete_subscription(self): url = self._build_url('subscription', base_url=self._api) return self._boolean(self._delete(url), 204, 404) + def deployments(self, number=-1, etag=None): + """Iterate over deployments for this repository. + + :param int number: (optional), number of deployments to return. + Default: -1, returns all available deployments + :param str etag: (optional), ETag from a previous request for all + deployments + :returns: generator of + :class:`Deployment `\ s + """ + url = self._build_url('deployments', base_url=self._api) + i = self._iter(int(number), url, Deployment, etag=etag) + i.headers.update(Deployment.CUSTOM_HEADERS) + return i + @requires_auth def edit(self, name, @@ -1271,21 +1286,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_deployments(self, number=-1, etag=None): - """Iterate over deployments for this repository. - - :param int number: (optional), number of deployments to return. - Default: -1, returns all available deployments - :param str etag: (optional), ETag from a previous request for all - deployments - :returns: generator of - :class:`Deployment `\ s - """ - url = self._build_url('deployments', base_url=self._api) - i = self._iter(int(number), url, Deployment, etag=etag) - i.headers.update(Deployment.CUSTOM_HEADERS) - return i - def iter_events(self, number=-1, etag=None): """Iterate over events on this repository. diff --git a/tests/cassettes/Repository_iter_deployments.json b/tests/cassettes/Repository_deployments.json similarity index 100% rename from tests/cassettes/Repository_iter_deployments.json rename to tests/cassettes/Repository_deployments.json diff --git a/tests/integration/test_repos_deployment.py b/tests/integration/test_repos_deployment.py index 4da5128c8..5862c2772 100644 --- a/tests/integration/test_repos_deployment.py +++ b/tests/integration/test_repos_deployment.py @@ -18,7 +18,7 @@ def test_create_status(self): repository = self.gh.repository('sigmavirus24', 'github3.py') assert repository is not None deployment = find(lambda d: d.id == 801, - repository.iter_deployments()) + repository.deployments()) assert deployment is not None status = deployment.create_status('success') @@ -33,7 +33,7 @@ def test_iter_statuses(self): repository = self.gh.repository('sigmavirus24', 'github3.py') assert repository is not None deployment = find(lambda d: d.id == 801, - repository.iter_deployments()) + repository.deployments()) assert deployment is not None statuses = list(deployment.iter_statuses(5)) diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index d04c3a2e1..d42fd326d 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -138,6 +138,15 @@ def test_create_release(self): assert isinstance(release, github3.repos.release.Release) + def test_deployments(self): + """Test that a repository's deployments may be retrieved.""" + cassette_name = self.cassette_name('deployments') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for d in repository.deployments(): + assert isinstance(d, github3.repos.deployment.Deployment) + def test_ignore(self): """Test that a user can ignore the notifications on a repository.""" self.basic_login() @@ -149,6 +158,15 @@ def test_ignore(self): subscription = repository.ignore() assert subscription.ignored is True + def test_iter_issues_accepts_state_all(self): + """Test that the state parameter accets 'all'.""" + cassette_name = self.cassette_name('issues_state_all') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'betamax') + assert repository is not None + for issue in repository.iter_issues(state='all'): + assert issue.state in ('open', 'closed') + def test_iter_languages(self): """Test that a repository's languages can be retrieved.""" cassette_name = self.cassette_name('iter_languages') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index d1282669a..d7aaec7d5 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -313,3 +313,16 @@ def test_contributors_with_anon(self): params={'per_page': 100, 'anon': 'true'}, headers={} ) + + def test_deployments(self): + """Test the ability to iterate over deployments.""" + i = self.instance.deployments() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('deployments'), + params={'per_page': 100}, + headers={ + 'Accept': 'application/vnd.github.cannonball-preview+json' + } + ) From eb0963e81b8c6a5319981336662a90be8a11c17a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 3 Aug 2014 09:33:21 -0500 Subject: [PATCH 332/972] Docstring the world --- tests/integration/test_repos_deployment.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/integration/test_repos_deployment.py b/tests/integration/test_repos_deployment.py index 5862c2772..a5bddaefe 100644 --- a/tests/integration/test_repos_deployment.py +++ b/tests/integration/test_repos_deployment.py @@ -1,17 +1,20 @@ +"""Deployment integration tests.""" import github3 from .helper import IntegrationHelper def find(func, iterable): + """Helper function to find the first item in an interable.""" return next(iter(filter(func, iterable))) class TestDeployment(IntegrationHelper): + + """Integration tests for the Deployment class.""" + def test_create_status(self): - """ - Test that using a Deployment instance, a user can create a status. - """ + """Show that a user can create a deployment status.""" self.basic_login() cassette_name = self.cassette_name('create_status') with self.recorder.use_cassette(cassette_name): @@ -25,9 +28,7 @@ def test_create_status(self): assert isinstance(status, github3.repos.deployment.DeploymentStatus) def test_iter_statuses(self): - """ - Test that using a Deployment instance, a user can retrieve statuses. - """ + """Show that a user can retrieve deployment statuses.""" cassette_name = self.cassette_name('statuses') with self.recorder.use_cassette(cassette_name): repository = self.gh.repository('sigmavirus24', 'github3.py') From 5497b6f04b0f373d5d804ea3cf94fe530bc4f879 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 3 Aug 2014 12:54:23 -0500 Subject: [PATCH 333/972] Fix docstrings for Repository class and update HISTORY --- HISTORY.rst | 11 ++++++ github3/repos/repo.py | 84 ++++++++++++++++++++++--------------------- 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index e81045375..ace54c582 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -200,6 +200,17 @@ Old name New attribute name - The ``is_public`` method has been removed since it just returned the ``Gist.public`` attribute. +- Most instances of ``login`` as a parameter have been changed to ``username`` + for clarity and consistency. This affects the following methods: + + - ``Organization#add_member`` + - ``Organization#is_member`` + - ``Organization#is_public_member`` + - ``Organization#remove_member`` + - ``Repository#is_assignee`` + - ``Team#add_member`` + - ``Team#is_member`` + 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 22c0d21e9..34b9dd1ff 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -352,7 +352,7 @@ def archive(self, format, path='', ref='master'): return False def asset(self, id): - """Returns a single Asset. + """Return a single asset. :param int id: (required), id of the asset :returns: :class:`Asset ` @@ -366,7 +366,7 @@ def asset(self, id): return Asset(data, self) if data else None def assignees(self, number=-1, etag=None): - """Iterate over all assignees to which an issue may be assigned. + r"""Iterate over all assignees to which an issue may be assigned. :param int number: (optional), number of assignees to return. Default: -1 returns all available assignees @@ -402,7 +402,7 @@ def branch(self, name): return Branch(json, self) if json else None def branches(self, number=-1, etag=None): - """Iterate over the branches in this repository. + r"""Iterate over the branches in this repository. :param int number: (optional), number of branches to return. Default: -1 returns all branches @@ -439,7 +439,7 @@ def code_frequency(self, number=-1, etag=None): return self._iter(int(number), url, list, etag=etag) def collaborators(self, number=-1, etag=None): - """Iterate over the collaborators of this repository. + r"""Iterate over the collaborators of this repository. :param int number: (optional), number of collaborators to return. Default: -1 returns all comments @@ -451,7 +451,7 @@ def collaborators(self, number=-1, etag=None): return self._iter(int(number), url, User, etag=etag) def comments(self, number=-1, etag=None): - """Iterate over comments on all commits in the repository. + r"""Iterate over comments on all commits in the repository. :param int number: (optional), number of comments to return. Default: -1 returns all comments @@ -464,7 +464,7 @@ def comments(self, number=-1, etag=None): return self._iter(int(number), url, RepoComment, etag=etag) def comments_on_commit(self, sha, number=-1, etag=None): - """Iterate over comments for a single commit. + r"""Iterate over comments for a single commit. :param sha: (required), sha of the commit to list comments on :type sha: str @@ -479,8 +479,9 @@ def comments_on_commit(self, sha, number=-1, etag=None): return self._iter(int(number), url, RepoComment, etag=etag) def commit(self, sha): - """Get a single (repo) commit. See :func:`git_commit` for the Git Data - Commit. + """Get a single (repo) commit. + + See :func:`git_commit` for the Git Data Commit. :param str sha: (required), sha of the commit :returns: :class:`RepoCommit ` if @@ -821,7 +822,7 @@ def create_issue(self, assignee=None, milestone=None, labels=None): - """Creates an issue on this repository. + """Create an issue on this repository. :param str title: (required), title of the issue :param str body: (optional), body of the issue @@ -1113,7 +1114,7 @@ def delete_subscription(self): return self._boolean(self._delete(url), 204, 404) def deployments(self, number=-1, etag=None): - """Iterate over deployments for this repository. + r"""Iterate over deployments for this repository. :param int number: (optional), number of deployments to return. Default: -1, returns all available deployments @@ -1226,15 +1227,16 @@ def ignore(self): json = self._json(self._put(url, data=dumps({'ignored': True})), 200) return Subscription(json, self) if json else None - def is_assignee(self, login): - """Check if the user is a possible assignee for an issue on this - repository. + def is_assignee(self, username): + """Check if the user can be assigned an issue on this repository. + :param username: name of the user to check + :type username: str or :class:`User ` :returns: :class:`bool` """ - if not login: + if not username: return False - url = self._build_url('assignees', login, base_url=self._api) + url = self._build_url('assignees', str(username), base_url=self._api) return self._boolean(self._get(url), 204, 404) def issue(self, number): @@ -1264,7 +1266,7 @@ def key(self, id_num): return Key(json, self) if json else None def label(self, name): - """Get the label specified by ``name`` + """Get the label specified by ``name``. :param str name: (required), name of the label :returns: :class:`Label ` if successful, @@ -1287,7 +1289,7 @@ def latest_pages_build(self): return PagesBuild(json) if json else None def iter_events(self, number=-1, etag=None): - """Iterate over events on this repository. + r"""Iterate over events on this repository. :param int number: (optional), number of events to return. Default: -1 returns all available events @@ -1317,7 +1319,7 @@ def iter_forks(self, sort='', number=-1, etag=None): @requires_auth def iter_hooks(self, number=-1, etag=None): - """Iterate over hooks registered on this repository. + r"""Iterate over hooks registered on this repository. :param int number: (optional), number of hoks to return. Default: -1 returns all hooks @@ -1339,7 +1341,7 @@ def iter_issues(self, since=None, number=-1, etag=None): - """Iterate over issues on this repo based upon parameters passed. + r"""Iterate over issues on this repo based upon parameters passed. .. versionchanged:: 0.9.0 @@ -1374,7 +1376,7 @@ def iter_issues(self, return self._iter(int(number), url, Issue, params, etag) def iter_issue_events(self, number=-1, etag=None): - """Iterates over issue events on this repository. + r"""Iterate over issue events on this repository. :param int number: (optional), number of events to return. Default: -1 returns all available events @@ -1388,7 +1390,7 @@ def iter_issue_events(self, number=-1, etag=None): @requires_auth def iter_keys(self, number=-1, etag=None): - """Iterates over deploy keys on this repository. + r"""Iterate over deploy keys on this repository. :param int number: (optional), number of keys to return. Default: -1 returns all available keys @@ -1400,7 +1402,7 @@ def iter_keys(self, number=-1, etag=None): return self._iter(int(number), url, Key, etag=etag) def iter_labels(self, number=-1, etag=None): - """Iterates over labels on this repository. + r"""Iterate over labels on this repository. :param int number: (optional), number of labels to return. Default: -1 returns all available labels @@ -1425,7 +1427,7 @@ def iter_languages(self, number=-1, etag=None): def iter_milestones(self, state=None, sort=None, direction=None, number=-1, etag=None): - """Iterates over the milestones on this repository. + r"""Iterate over the milestones on this repository. :param str state: (optional), state of the milestones, accepted values: ('open', 'closed') @@ -1453,7 +1455,7 @@ def iter_milestones(self, state=None, sort=None, direction=None, return self._iter(int(number), url, Milestone, params, etag) def iter_network_events(self, number=-1, etag=None): - """Iterates over events on a network of repositories. + r"""Iterate over events on a network of repositories. :param int number: (optional), number of events to return. Default: -1 returns all available events @@ -1468,7 +1470,7 @@ def iter_network_events(self, number=-1, etag=None): @requires_auth def iter_notifications(self, all=False, participating=False, since=None, number=-1, etag=None): - """Iterates over the notifications for this repository. + r"""Iterate over the notifications for this repository. :param bool all: (optional), show all notifications, including ones marked as read @@ -1505,7 +1507,7 @@ def iter_pages_builds(self, number=-1, etag=None): def iter_pulls(self, state=None, head=None, base=None, sort='created', direction='desc', number=-1, etag=None): - """List pull requests on repository. + r"""List pull requests on repository. .. versionchanged:: 0.9.0 @@ -1542,7 +1544,7 @@ def iter_pulls(self, state=None, head=None, base=None, sort='created', return self._iter(int(number), url, PullRequest, params, etag) def iter_refs(self, subspace='', number=-1, etag=None): - """Iterates over references for this repository. + r"""Iterate over references for this repository. :param str subspace: (optional), e.g. 'tags', 'stashes', 'notes' :param int number: (optional), number of refs to return. Default: -1 @@ -1559,7 +1561,7 @@ def iter_refs(self, subspace='', number=-1, etag=None): return self._iter(int(number), url, Reference, etag=etag) def iter_releases(self, number=-1, etag=None): - """Iterates over releases for this repository. + r"""Iterate over releases for this repository. :param int number: (optional), number of refs to return. Default: -1 returns all available refs @@ -1574,7 +1576,7 @@ def iter_releases(self, number=-1, etag=None): return iterator def iter_stargazers(self, number=-1, etag=None): - """List users who have starred this repository. + r"""List users who have starred this repository. :param int number: (optional), number of stargazers to return. Default: -1 returns all subscribers available @@ -1586,7 +1588,7 @@ def iter_stargazers(self, number=-1, etag=None): return self._iter(int(number), url, User, etag=etag) def iter_subscribers(self, number=-1, etag=None): - """Iterates over users subscribed to this repository. + r"""Iterate over users subscribed to this repository. :param int number: (optional), number of subscribers to return. Default: -1 returns all subscribers available @@ -1598,7 +1600,7 @@ def iter_subscribers(self, number=-1, etag=None): return self._iter(int(number), url, User, etag=etag) def iter_statuses(self, sha, number=-1, etag=None): - """Iterates over the statuses for a specific SHA. + r"""Iterate over the statuses for a specific SHA. :param str sha: SHA of the commit to list the statuses of :param int number: (optional), return up to number statuses. Default: @@ -1613,7 +1615,7 @@ def iter_statuses(self, sha, number=-1, etag=None): return self._iter(int(number), url, Status, etag=etag) def iter_tags(self, number=-1, etag=None): - """Iterates over tags on this repository. + r"""Iterate over tags on this repository. :param int number: (optional), return up to at most number tags. Default: -1 returns all available tags. @@ -1626,7 +1628,7 @@ def iter_tags(self, number=-1, etag=None): @requires_auth def iter_teams(self, number=-1, etag=None): - """Iterates over teams with access to this repository. + r"""Iterate over teams with access to this repository. :param int number: (optional), return up to number Teams. Default: -1 returns all Teams. @@ -1866,14 +1868,7 @@ def update_label(self, name, color, new_name=''): return resp def weekly_commit_count(self): - """Returns the total commit counts. - - The dictionary returned has two entries: ``all`` and ``owner``. Each - has a fifty-two element long list of commit counts. (Note: ``all`` - includes the owner.) ``d['all'][0]`` will be the oldest week, - ``d['all'][51]`` will be the most recent. - - :returns: dict + """Retrieve the total commit counts. .. note:: All statistics methods may return a 202. If github3.py receives a 202 in this case, it will return an emtpy dictionary. @@ -1882,6 +1877,12 @@ def weekly_commit_count(self): ..versionadded:: 0.7 + The dictionary returned has two entries: ``all`` and ``owner``. Each + has a fifty-two element long list of commit counts. (Note: ``all`` + includes the owner.) ``d['all'][0]`` will be the oldest week, + ``d['all'][51]`` will be the most recent. + + :returns: dict """ url = self._build_url('stats', 'participation', base_url=self._api) resp = self._get(url) @@ -1905,6 +1906,7 @@ def repo_issue_params(milestone=None, since=None, number=-1, etag=None): + """Validate and filter issue method parameters in one place.""" params = {'assignee': assignee, 'mentioned': mentioned} if milestone in ('*', 'none') or isinstance(milestone, int): params['milestone'] = milestone From ee8c454658a78e2930cd5d7314afbc08895774e5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 3 Aug 2014 13:34:47 -0500 Subject: [PATCH 334/972] Rename Repository#iter_events to Repository#events --- github3/repos/repo.py | 34 +++++++++++--------------- tests/cassettes/Repository_events.json | 1 + tests/integration/test_repos_repo.py | 12 +++++++++ tests/test_repos.py | 9 ------- tests/unit/test_repos_repo.py | 11 +++++++++ 5 files changed, 38 insertions(+), 29 deletions(-) create mode 100644 tests/cassettes/Repository_events.json diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 34b9dd1ff..f60c74fcf 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1129,14 +1129,8 @@ def deployments(self, number=-1, etag=None): return i @requires_auth - def edit(self, - name, - description=None, - homepage=None, - private=None, - has_issues=None, - has_wiki=None, - has_downloads=None, + def edit(self, name, description=None, homepage=None, private=None, + has_issues=None, has_wiki=None, has_downloads=None, default_branch=None): """Edit this repository. @@ -1175,6 +1169,18 @@ def edit(self, return True return False + def events(self, number=-1, etag=None): + r"""Iterate over events on this repository. + + :param int number: (optional), number of events to return. Default: -1 + returns all available events + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Event `\ s + """ + url = self._build_url('events', base_url=self._api) + return self._iter(int(number), url, Event, etag=etag) + def is_collaborator(self, login): """Check to see if ``login`` is a collaborator on this repository. @@ -1288,18 +1294,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_events(self, number=-1, etag=None): - r"""Iterate over events on this repository. - - :param int number: (optional), number of events to return. Default: -1 - returns all available events - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Event `\ s - """ - url = self._build_url('events', base_url=self._api) - return self._iter(int(number), url, Event, etag=etag) - def iter_forks(self, sort='', number=-1, etag=None): """Iterate over forks of this repository. diff --git a/tests/cassettes/Repository_events.json b/tests/cassettes/Repository_events.json new file mode 100644 index 000000000..a2bd37c84 --- /dev/null +++ b/tests/cassettes/Repository_events.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY+rNhSG/0rEtpk4hMkkQapuu2q7u4vbTTeRAROsAYxskyiD5r/3NQYCuWo+xt1ECfF5/Pr4HHOOG48nXhhs/OXG9+deSQvmhd6B66yOgkV19uZeWuf5vvtD8UNBj1zWavVKJqPEqWTSCxsvFwdegjEeCoqZZvW63AbLuUePVFO5r2WOcZnWlQoJsQ/VwlJrxWQsSs1KvYhFQWpijb8df/VBO8iOYbBe7L9ug/Vbst2lu9Wave1W/mYbMeYnu4DG6QYGV3NVvJvHwjGZIleCM13kVxKttNbkanAq8lycQLle1L2JyGBpPN1SeHn4IgWWDRE6Y/AtlvRpHMWVfl5Ua9Vgg5Xe88RwFDZMsuRpYZ0dZJn4+GyIZJVogXWkYskrzUX5vMCJNWhCHmjJP+jXaLBWgBhpz0tprWDNjojV582tWUMqyY80PhvXSBYzfoSzv4i8sgdRnyuT1n8jKIzruWZ7mhQmTVOaK/Y599rpNQa1D+bIykejf3oMJGzYVUz4/awzUc5yHkkqz7NUyBlHTsuUxojV2QnHzAzhOvuD6z/raPb797+OAQRi3Pug5Gbmts6fJONUjiHd2ZObCKQnAJD0zs5OHGPfEHx2+RQj1WkkJNXi3qFxW+AE1JDxTxNLmtHCSXgLACgTws2TLQAgrlTNHgrt2wtvOYr0+VPWRWSPvEey5jbaEqCVKpzzJWNOHhwgDelPZaRDGWdu2J7REPut3W16cJJq7IGJchE5cfCiJC2kISqj9j2k967qDNUwJlDJUmephjFAtXTc71amgQxIvAQ1tt5JZ88gTefRnJaHmh7cqAMEu25e1Qf6cbeIuZ07FwqQpoKTPKrdD7kLxyi1tQPy3c2lF8wF2hYkt8ucOw4YFTatC4qC36sLbhM7xCTs/wesidNrtPl9v4y5L9cwGnI5k+2h39FdvNud+r1O0lzm6NoFp5DoGaT5paI6MycXpqqoZC6iOwRpIopia7FYNBmjbVldMOmYwZYAFJVxhqrRRWfTM1D1FFS31XpqZCao3nNBEyffDhAA7Ta6aLWEcYxV6FOdBLaAMbHgOVNalG5n7IUyZpdC85THj3Qst9NtAmq+KV7GbE7zfI6o1TzmiGPU2mYXUXAyNw9ZApaBawLbqeQMIe3kdcksoyG204wlQyOS7KlGA7Fa+quXZfDiBz/8XbjehuvgH6ykrpLJmNeX5fZl6f/w16G/CYO1GVPVKhth7BBgXsMgCFftEJyAXQjiG64g8Ilrj5/6+1FLYW4NYKhUdjH87WIW/sf9SGcW54ilq6B/fM7j9WvpvimkZqJgFcqE7qZlWGVQnRfwdIL2KxGxWqAHJmZl/ANDt+tgPSkIYlGX2A9/9zb3TlSjdsWrd/ywLySGps9MTdXepqkXalmbrhJPLsfA6OGJv/Oh47NNW0d/2+CU5FKK7r6oRJKi369Y2bEHGVvbOCovNDajEdCN/3rZ3SoSltI613tbPEN2gqo/FxV0l0yf0Pb1YEMbVxz9sref/wKwzEahPRMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"1ee1d4c5402ca1f23e58dc8fdcf68aaf\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B9C:9F6A1A4:53DE80A0", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Sun, 03 Aug 2014 18:34:08 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407094448"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-03T18:34:09"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/events?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"c72a4ea382b6c25a0e34bff1addc98a6\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B9C:9F6A1E0:53DE80A0", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 03 Aug 2014 07:33:25 GMT", "link": "; rel=\"next\"", "date": "Sun, 03 Aug 2014 18:34:08 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407094448"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/events?per_page=100"}, "recorded_at": "2014-08-03T18:34:09"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repositories/3710711/events?per_page=100&page=2"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"b65c59b951f30c3956f2c3e05e879b48\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B9C:9F6A203:53DE80A0", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 28 Jul 2014 19:47:27 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 03 Aug 2014 18:34:08 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407094448"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repositories/3710711/events?per_page=100&page=2"}, "recorded_at": "2014-08-03T18:34:09"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repositories/3710711/events?per_page=100&page=3"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ed8c0a6e625347f925cca4de250c5b8c\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B9C:9F6A232:53DE80A0", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 25 Jul 2014 18:01:49 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 03 Aug 2014 18:34:09 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407094448"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repositories/3710711/events?per_page=100&page=3"}, "recorded_at": "2014-08-03T18:34:09"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repositories/3710711/events?per_page=100&page=4"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"53effd0f36e4f5eda6cdae0b1c959282\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "55", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:2B9C:9F6A281:53DE80A1", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 20 Jul 2014 08:07:14 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Sun, 03 Aug 2014 18:34:09 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407094448"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repositories/3710711/events?per_page=100&page=4"}, "recorded_at": "2014-08-03T18:34:09"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index d42fd326d..38e8d1f3d 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -147,6 +147,18 @@ def test_deployments(self): for d in repository.deployments(): assert isinstance(d, github3.repos.deployment.Deployment) + def test_events(self): + """Test that a user can iterate over the events from a repository.""" + cassette_name = self.cassette_name('events') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + events = list(repository.events(number=100)) + + assert len(events) > 0 + for event in events: + assert isinstance(event, github3.events.Event) + def test_ignore(self): """Test that a user can ignore the notifications on a repository.""" self.basic_login() diff --git a/tests/test_repos.py b/tests/test_repos.py index 77f72d1bf..37c4ba531 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -549,15 +549,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_events(self): - self.response('event', _iter=True) - self.get(self.api + 'events') - self.conf = {'params': {'per_page': 100}} - - e = next(self.repo.iter_events()) - assert isinstance(e, github3.events.Event) - self.mock_assertions() - def test_iter_forks(self): self.response('repo', _iter=True) self.get(self.api + 'forks') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index d7aaec7d5..9648e6216 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -326,3 +326,14 @@ def test_deployments(self): 'Accept': 'application/vnd.github.cannonball-preview+json' } ) + + def test_events(self): + """Test the ability to iterate over events from a repository.""" + i = self.instance.events() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('events'), + params={'per_page': 100}, + headers={} + ) From bdc8792f3e5a9f8b8da121fd6704fc1765303bdd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 3 Aug 2014 14:24:12 -0500 Subject: [PATCH 335/972] Replace login with username for Repository methods --- HISTORY.rst | 3 +++ github3/repos/repo.py | 51 ++++++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index ace54c582..1e0789a11 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -207,7 +207,10 @@ Old name New attribute name - ``Organization#is_member`` - ``Organization#is_public_member`` - ``Organization#remove_member`` + - ``Repository#add_collaborator`` - ``Repository#is_assignee`` + - ``Repository#is_collaborator`` + - ``Repository#remove_collaborator`` - ``Team#add_member`` - ``Team#is_member`` diff --git a/github3/repos/repo.py b/github3/repos/repo.py index f60c74fcf..1b0ba7366 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -313,17 +313,18 @@ def _create_pull(self, data): return PullRequest(json, self._session) if json else None @requires_auth - def add_collaborator(self, login): - """Add ``login`` as a collaborator to a repository. + def add_collaborator(self, username): + """Add ``username`` as a collaborator to a repository. - :param str login: (required), login of the user + :param username: (required), username of the user + :type username: str or :class:`User ` :returns: bool -- True if successful, False otherwise """ - resp = False - if login: - url = self._build_url('collaborators', login, base_url=self._api) - resp = self._boolean(self._put(url), 204, 404) - return resp + if not username: + return False + url = self._build_url('collaborators', str(username), + base_url=self._api) + return self._boolean(self._put(url), 204, 404) def archive(self, format, path='', ref='master'): """Get the tarball or zipball archive for this repo at ref. @@ -1181,16 +1182,18 @@ def events(self, number=-1, etag=None): url = self._build_url('events', base_url=self._api) return self._iter(int(number), url, Event, etag=etag) - def is_collaborator(self, login): - """Check to see if ``login`` is a collaborator on this repository. + def is_collaborator(self, username): + """Check to see if ``username`` is a collaborator on this repository. - :param str login: (required), login for the user + :param username: (required), login for the user + :type username: str or :class:`User ` :returns: bool -- True if successful, False otherwise """ - if login: - url = self._build_url('collaborators', login, base_url=self._api) - return self._boolean(self._get(url), 204, 404) - return False + if not username: + return False + url = self._build_url('collaborators', str(username), + base_url=self._api) + return self._boolean(self._get(url), 204, 404) def git_commit(self, sha): """Get a single (git) commit. @@ -1741,17 +1744,19 @@ def release(self, id): return Release(json, self) if json else None @requires_auth - def remove_collaborator(self, login): - """Remove collaborator ``login`` from the repository. + def remove_collaborator(self, username): + """Remove collaborator ``username`` from the repository. - :param str login: (required), login name of the collaborator + :param username: (required), login name of the collaborator + :type username: str or :class:`User ` :returns: bool """ - resp = False - if login: - url = self._build_url('collaborators', login, base_url=self._api) - resp = self._boolean(self._delete(url), 204, 404) - return resp + if not username: + return False + + url = self._build_url('collaborators', str(username), + base_url=self._api) + return self._boolean(self._delete(url), 204, 404) @requires_auth def subscribe(self): From f7830c05a7abfba16722ba71098b39ad29b77605 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 3 Aug 2014 20:40:45 -0500 Subject: [PATCH 336/972] Relocate Repository#is_collaborator --- github3/repos/repo.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 1b0ba7366..f02e228da 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1182,19 +1182,6 @@ def events(self, number=-1, etag=None): url = self._build_url('events', base_url=self._api) return self._iter(int(number), url, Event, etag=etag) - def is_collaborator(self, username): - """Check to see if ``username`` is a collaborator on this repository. - - :param username: (required), login for the user - :type username: str or :class:`User ` - :returns: bool -- True if successful, False otherwise - """ - if not username: - return False - url = self._build_url('collaborators', str(username), - base_url=self._api) - return self._boolean(self._get(url), 204, 404) - def git_commit(self, sha): """Get a single (git) commit. @@ -1248,6 +1235,19 @@ def is_assignee(self, username): url = self._build_url('assignees', str(username), base_url=self._api) return self._boolean(self._get(url), 204, 404) + def is_collaborator(self, username): + """Check to see if ``username`` is a collaborator on this repository. + + :param username: (required), login for the user + :type username: str or :class:`User ` + :returns: bool -- True if successful, False otherwise + """ + if not username: + return False + url = self._build_url('collaborators', str(username), + base_url=self._api) + return self._boolean(self._get(url), 204, 404) + def issue(self, number): """Get the issue specified by ``number``. From e408296e9fe85148bf6ddccd0b4ee98be2c792bb Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 3 Aug 2014 20:49:47 -0500 Subject: [PATCH 337/972] Rename Repository#iter_forks to Repository#forks --- HISTORY.rst | 1 + github3/repos/repo.py | 40 ++++++++++++--------------- tests/cassettes/Repository_forks.json | 1 + tests/integration/test_repos_repo.py | 12 ++++++++ tests/test_repos.py | 15 ---------- tests/unit/test_repos_repo.py | 11 ++++++++ 6 files changed, 43 insertions(+), 37 deletions(-) create mode 100644 tests/cassettes/Repository_forks.json diff --git a/HISTORY.rst b/HISTORY.rst index 1e0789a11..2898096d0 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -75,6 +75,7 @@ Old name New name ``Repository#iter_commits`` ``Repository#commits`` ``Repository#iter_contributor_statistics`` ``Repository#contributor_statistics`` ``Repository#iter_contributors`` ``Repository#contributors`` +``Repository#iter_forks`` ``Repository#forks`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index f02e228da..dba34f6fa 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -67,13 +67,9 @@ def __init__(self, repo, session=None): #: Description of the repository. self.description = repo.get('description', '') - # The number of forks - #: The number of forks made of this repository. DEPRECATED - self.forks = repo.get('forks', 0) - #: The number of forks of this repository. self.forks_count = repo.get('forks_count') - # For backward compatibility + #: The number of forks of this repository. For backward compatibility self.fork_count = self.forks_count #: Is this repository a fork? @@ -1182,6 +1178,23 @@ def events(self, number=-1, etag=None): url = self._build_url('events', base_url=self._api) return self._iter(int(number), url, Event, etag=etag) + def forks(self, sort='', number=-1, etag=None): + """Iterate over forks of this repository. + + :param str sort: (optional), accepted values: + ('newest', 'oldest', 'watchers'), API default: 'newest' + :param int number: (optional), number of forks to return. Default: -1 + returns all forks + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Repository ` + """ + url = self._build_url('forks', base_url=self._api) + params = {} + if sort in ('newest', 'oldest', 'watchers'): + params = {'sort': sort} + return self._iter(int(number), url, Repository, params, etag) + def git_commit(self, sha): """Get a single (git) commit. @@ -1297,23 +1310,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_forks(self, sort='', number=-1, etag=None): - """Iterate over forks of this repository. - - :param str sort: (optional), accepted values: - ('newest', 'oldest', 'watchers'), API default: 'newest' - :param int number: (optional), number of forks to return. Default: -1 - returns all forks - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Repository ` - """ - url = self._build_url('forks', base_url=self._api) - params = {} - if sort in ('newest', 'oldest', 'watchers'): - params = {'sort': sort} - return self._iter(int(number), url, Repository, params, etag) - @requires_auth def iter_hooks(self, number=-1, etag=None): r"""Iterate over hooks registered on this repository. diff --git a/tests/cassettes/Repository_forks.json b/tests/cassettes/Repository_forks.json new file mode 100644 index 000000000..b71a9421d --- /dev/null +++ b/tests/cassettes/Repository_forks.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTW/jNhCG/4qhax3TsuzEFrDY7antbQ/ppReDkiiLiCQKJGXDEfLf+1KU9eFFbSfsJUgUzsOXw5nRjBqPJ14YvPjLF9+feyUtmBd6B66zOgoW1dmbe2md5/vuH4ofCnrkslarNZmsEqeSSS9svFwceAnGeCkoZpvVerkNlnOPHqmmcl/LHOsyrSsVEmIfqoWl1orJWJSalXoRi4LUxBp/P37zQTvIjmGwXuyvt8HmOdnu0t1qw553K/9lGzHmJ7uAxukLDK72qni3j4VjM0WuBGe6yK8kWmmtydXiVOS5OIFyfah7G5He0ni6pfDy8EUKLBsidMbgWxzpwziKK/15Ua1VgwtWes8Tw1G4MMmSTwvr7CDLxMdHQySrRAusIxVLXmkuys8LnFiDJuSBlvydfo0GawWIkfZ5Ka0VrNkRsfp5c2vWkEryI43PxjWSxYwf4ewvIq/sQdTnyqT13wgK43qu2Z4mhUnTlOaKfcy9dnuNRe2DObLy0eifloGE9beKDX+edSbKWc4jSeV5lgo548hpmdIYsTo7oczMEK6zP7j+s45mv//86xhAINa99UpuZm7r/EkyTuUY0p07uYlAegIASW/s7MQx9g3Bzy6fYqQ6jYSkWtwrGrcFTkANGf9pYkkzWjgJbwEAZUK4ebIFAMSVqtlDoX374C1HkUv+lHUR2ZL3SNbcRlsCtFKFOl8y5uTBHtKQS1VGOpRx5oa9MBpif2tvmx6cpBp7YKJcRE4cvChJC2mIyqh9D+m9qzpDNYwJVLLUWaph9FAtHe+7lWkgPRIvQY2rd9J5YZCm82hOy0NND27UHoJbN6/qA32/28Tczp2BAqTp4CSPavciN3CMUts7IN/dXDpgBmjbkNxuc+44YNTYtC4oCn6vL7hN7BCTsP8fsCZOr9Hm7/ttzH25htGQoSbbot/RXbzbVf2LTtIMe3TjglNIXBik+a2iOjOVC1tVVDIX0R2CNBFFs7VYLJqM0batLph0zGBLAIrKOEPX6KKzuTDQ9RRUt916amQm6N5zQRMn3/YQAO01umi1hHGMVZhTnQS2gDGx4DlTWpRuNXagjNml0Dzl8SMTy+10m4Ca74qXMZvTPJ8jajWPOeIYvba5RTSczM1DloBj4DOBnVRyhpB28rpkltEQO2nGkmEQSfZUY4BYLf3V0zJ48oNXfxdutuEm+Acnqatksmb9tNw+Lf1XfxP6L2GwMWuqWmUjjF2yfl36YbAMg7VZggrYhSB+wycI/MRnj1/m+9FIYb4awFCpbDD8MZiF//F9pDOLc8TSVdA/vufx+rV03xRSM1GwCm1C96WlP2VQnRfwdILxKxGxWmAGJuZk/B1Lt5tgM2kIYlGXuA9/9zz3TlSjd8Wrd/zw0kj0Q5/Zmqq9TVMv1LI2UyWeDGVg9PDE33g/8dmhraM/b1EluZSi+15UIkkx71es7NiDDDs4Ki80NqMVRvcguztFwlJa53pvm2fITtD156KC7pLpE8a+C9jQxh3H5djbj38BBaUGAj0TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ea5e30e74b3530b366adeb37710518ae\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0446:385F4C3:53DEE674", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Mon, 04 Aug 2014 01:48:36 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407120437"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-04T01:48:37"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/forks?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+3dfW/j2Jbv97dS8L9pt/n8ICC4mZsAMwMEmYMbDwZIEBRIkSrrlG0Zktx1qgv93rNJURLJ/Vt7c6+1BWOuJzm46K7m+nKXJJfLn9kk/99fd9vmbhVFaZGESfbb3Wv10t6t7r5tj0/vdfz728+73+4278/PX4f/8Pe62tfvx93D5Ijdj9d2f7f6dfe8+7Z9VfPnw9R010/jNA1+u6v+qI7V/uv7/lkd8nQ8vh1WDw+nXzz8fgq+H9r9evd6bF+Pv693Lw/vD/3sf/vjfw1V69t+SHTRu3idBOsqq+M6rfIwytq8XGdpXTVRUNRN0qiB2anetsNpTm11rsPDaKlPx5fn2epOq+oPHx242T0/736o6fnvxXSCh8tU95r2he3rN0ZBTf162B2fWvVSqt/CX90Lsz0c3RbTT/xSb+Ph+HXbdI2Dem/2beO0oGFGLaf7BPz162Hfvu362Ht9WO+3b8ft7tVtYZNJVdrtv1Wv2z8r95KaPKhAtyS3JfQTarL9Q30M3UZPI78e3vbbP6r1z+6l2LfrdvuHemEZudmsqh1/vnVfoP+u3vjuZd4e269V89J90W2q50P71293/amP6qD+F35TX2hLPtXTL+imvbx76mR/+3l82r1+ed7W+2r/88tmt/+yVV+i+021Vp/FLz/UHxZf1Mfxyz9vj//yXn/5p7/96x+xWpw67vvd6rh/V4swfiH2r/fl62u6ki5ieQvIcfUVp4bVSr63P9mNbvbXg/p/hy+TtfrKrerdvjrubF//9MImkV8P43/tPjLHtnphL7gfVpGn3Y7/yvXDKrI9HN7bRZ9c+jfbNw4P5y+N1/eX+vSn1pIvCDp7mlZrrA6H7bfXtmW/YpfAr4fzH6jqk/66fuInz/O/Hk7/1L+r1Tf2ErtZlaifdzW7ob6XPfSBXw+Hp+r0beP4VbKqrtjNT4L7diNaYjd/CR73gve1X14XuOTU96ujeovZ6zvPP/waXsHn6vXbe/WNX7wE1LvbfTf9Vv1p/XsF/TVxLahc9/eo/bb725rkD6pro1vh6du6+vrlv4TXxDXY/z3B/DcPw2969HeN/rf98rK1fduma8P45CMtTHafw3m2+3f73y7My+zmfz1c/zw9/WE9lLmv5vCn9Xl9D7+u/eEv5uy3/jz/8Ot/eauOT92fQOo0b9W+5S52GH/4VVfq7z6///77r6e26v82+9LuBV+Vp2mVqfbrJ/WXN+76fp3n1d9EXqpj/xfkTbe8Rv2F+XlXNezX8hJQsdNbxl3jaXr8OXpTP/CxF9YPj2sv2+f2cNy98v+MvBbG3dfdcbvZrpf8YEB/GU0iv/7bYfu6bn+rnp9/U5/K43a9VZ9T9Vfc7h1Tf+lr+a/KaVotX/18ffqh4LlVH1n2q7xvT/O/Hk4/vK33rfo7f/O1Oqq/r0dBmNwHxX0QP0bhKs5XYfD/qN/B+1sDjgkfw3QV5qs47Y55ez88aZnkMQhXYbYKiu4Q9afZ8FFT/6R+gAc/Io/+Ct/9wK2GDoen69D/dh1ZAVAYRtbP6jMz+1AvO9cf828l5jG1vKfdS/umvo0PLnH5XcVvP39Xr2yjfrppduvD7+pHyofud7P9Ux1aKJqYfNNe795f1euvpONHdVR/e1TfJK+/dP5Gf7d6VV8h6pTV4evpS+/6k5r6pevX9fCTU3fcj+337eWo009E1/DLdr/fDapySu/e2tehPVrA6YehbnWj/z5Zbf8vTbup3p+PX09/b1UvSKP+ov28e7v767cBi8IySYJ8ARb92D4/q6+etQWLzod1f5J1GJUVQVlwuWiYhmBU5XEYlGVdx2kelkUTNuu6SNOoaup1Uyfdz6zGn1O7Hw4OD6Plmn+0Hh3oBEaXl40NRrOCBIxG76EAjC4Vf2B0TY6pSb2FzmB0KbmC0WWw//6iTr3kB9rph+jyU7EMjEYrmWCTWpNvMBp9IEZG/BFghFeyGIzAuDMYoYYYjFDUFxihtjMYoQgXjFDLAxihLA+MUEkIRigpASPUcwUj1Oh+buWDEVVkgxEV5IERVeODESrKwAgV+WCEaiIwQsExOnV/U3YDI1QcJa7BxWBkKPYNlXTQHVSby07385Ew2X3hzbNnkFnyYz61TDEYobAnMEJpGRjhYu9NIjBCXQ4YoY4fMEJlHhihkgCMUE4IRijpCYxQ+hZghM4jASPUWwBG+X2YP4bJKohWaUmAkTom6jQoydT/MBidMvEqLVZBbgEjsFIbGNEjFjCiBw8mMAJj6nsGC4ziIvycYBQnaoNRYd9d9LTfHp6239vD00H93wdaixvNjlbvSr/XKEyTKFYn4+02Ok1DPgraTZxs0rpYR1kUbZK2Dqosb9brWP1/UdZtUFrAR/qqzYqkH++ESfOXlG1KOCShpXlRtCVpHvMHTVpZ6k3zoCs7zefd9Wle8LNraV69/eal+RlPzj9sW/wIkjIuaLFM0RVnoDKkxE5laPviKsMpnNXK0OLilSHpwbAMdR5lGYJC0TKUJbBlyLr6liElYy5LmK1dli4PvSxRvn0ZwjICM4T5EmaIikDM0JW5mCEs4zF7mKFkhuhctRyxzFCWmpkhfaY30V4rQ9+ToBnOIIM0Y1juaYY8h9UMOT+6ZjgBD9kMQYG1GapCcjOUPcmb4Qy3ADjD6SQOZ8gu4LjsPg4eg27z1iqhOC67jxTZRasgXUX9Mfr+LXVI8Rgqi4tWUWLhOHrBNpWzTlpwzjpvNDp6mk11WVxy9nYN18p0p/3Pu78rypM4yO1c99/v/8d2/WRRutNBA85FYViqOhPnhmmIc2VYNEFZxXVctYm6JjAP8ior07KponBdJfkynLss1mxyl8OcKG54udgCN5mXwNvlfRPs6Boa/pjtHJTq2tBxRbVhzN3ShkE/hHZZxa13cV0+Ah+8hwutY7GTacPOPKYXxCqmJ31hmF52NjA9waUvveRBvPQoD7r0jtC39KCEtfSaq2bpBRli4R7brnCOR1a4xZcqvScDKr3Hdym9JeIoPSdTKL0nwyeyxzAnvSWkJj0oFSa96AWW9KwnT9LDMkZCPbke6VUOGukVP1akd3lEpHcEMqTHhCCkBz05kB6+Bf/oZ5Goj15bhD0XyImpi/UWYE/am5ECo3SVRBbs0dZpMx5qwEI71JhRdLQhLuTkUa4uJbt+Gx1dEGe8SO9/CsgJsywoFkDO39VX1dNL9WqhnPNhA+bkRRGpOGufVT8LISfP8lxdi7fJgqRsknCdJd0Gq2itNs8FUVGtl0HOaKlmyhkd6IQ5l5eMzTmzggR0Ru+fgHQuFX+oc01KWedScoWdy6A77VxG/eDOaCW35p3RB+KDgQevZDHxgHFn5EENMfOgqC/oQW1n6kERLvaglgfuQVke+KCSkHxQUoI+qOfKPqghgx+qyKYfKsjDH6rG5x9UlAEQKvIJCNVECISCMgZCRRkEGYoMCkI1IQahpJSDUNMLCKGwJxJCaRkK4aKchVCXA0Oo44eGUJmHQ6gk4CGUEwIRSnoiIpS+BRKh80iYCPWWQVHyGMad8AQGKDodk6vDyF1B50NCGxSBldqoiB6xYBE9aOQiMMYFI7Vz5NPu/AniMErjBXd2emm/VT8q242dhqMGLoqTPE3yiAlGwzQkozIJmqDaRGW9LkK18SfdxG2dVdV6kwRRmmyWkdF1tWYxuh7nBEbnl4ztRdOAhIuu755Ai84Rf1h0KUqt6BxypaLznLsUnSf9QNF1Hbd2ousn4YOZCC5ksRLp085IBBJiIwJNX0QE0s5CBBpcIAIpDz4EqjweAiGhDoGiBIdAztWGQEJGQ0SQLUNEjwdDRIzvQiAoYyEQ5KsQiIlQCPRkJgSCMhKigwwRAjEhCIGi1INA0gsHga4nDQJlGQbBoNyCQJZDQSDjR4JAmAdBICRwIFATMhAoelIgUL4FAoHTSAwI5BYQ0HmTTxyvyL1C441AISagSyZZpb0kddfinm5go/5pemNvfaE2ASInLABEzhn9R5/i80/nH59zv1AQhkm45D5Nz+/rn8/b4/HZdoum64HnPUPdtp6cvWvoNA0RKGrTdZY166oqsrRYx3Udqo1DTZzHWRREVb0MgSYLNjvQ5FAnChq9fGwN0hoSEJq8nwITGnX8sdA4KpWhUcsVh0aj7j40GvZDRJPV3FqJJh+PD4Yiai2LrQgGnLkIV8RihLO+0AjXnd0IZ7h0hGse9AiHeYCEW0JDwlEJI+GiqyThigyT6Cbbk+gkj5ToHl+VcFMGS7jJtyXcE/ESTsqECTdlyGRsMpwJ94TUhKNSbcJVL+CE057MCcdl7EQ15fKEyxx8wiU//oTbPILCLYFC4aAQonDUk0Xh+C04Cp9JIlK4uAilov5pc+pmRGF/myHwtLn0/noMsS8pvQ+zbnuTuoYt7e8vbkApuFabS5mGLDRlGjXqFBzkAlUeZmoPzScFqiBO4iy235moOrxU62ZnuZ5tOGqgqe7ysizl0tQwDWkqrspA/f+bqonVDYqCjXqS5Dpsm0Q9iq7cRE2zjKauqzW71PU4J5Q6v2RskZoGJBx1ffcEFnWO+IOoS1GqUOeQK0Gd59z96TzpB5+u67i1PF0/CR/MTnAhi81Jn3YGJ5AQaxNo+qImkHZ2JtDgIhNIeRAmUOXxEggJbQkUJbAEcq6qBBIyUiKCbE8iejxMImJ8SQJBGSOBIN+QQEwESKAn0yMQlNERHWS4EYgJ0QgUpWIEkl64CHQ9WREoy6AIBuVKBLIcIgIZPz4EwjwcAiGBDIGakIVA0ZMJgfItQAicRqJBILeMgsLHsFSbk1ZxbziYgi7H9A+J029c7UJB+kJtDkROWBCInDMKkD71X/yjbst0vgPT3Ur9S9Nuqvfn49fT31PvVuoX/mifd293f/32q3+yW1iWQVZ0j3Z7rV5adYD6jvb0Xg+Pe9q8Pz9/Hf7Dv1SH7ct2b+Gf4aiBf9QD3MKsez4f635GwzTknyJI8zYqi2jTtmUdp22WrzfrJInrrEjCKl7GP9fVmvnnepwT/5xfMjb/TAMS/rm+ewL+OUf88c+lKOWfc8iVf85z7vxznvTDP9d13Jp/rp+ED+YfuJDF/KNPO/MPSIj5BzR98Q9IO/MPaHD5B6Q88A+o8vgHhIT8A4oS/gE5V/4BCRn/EEE2/xA9Hv8QMT7/gKCMf0CQzz8gJuIf0JPxDwjK+IcOMvgHxIT8A4pS/gFJL/wDup74B5Rl/AODcv4BWQ7/gIwf/gFhHv+AkIB/QE3IP6DoiX9A+Rb8A04j4R+QW8Q/YfEYlN0zyYJ+lw/kn+sxHvhHX6iNf8gJC/+Qc0b+0af+i38Y/FPEaVSoh4fZ+OdQvai/fvxh4Z/hqDP/BHEQFty7E0Wnacw/ZbVuqyRtynXatvkmzqo6LoswyqK6aZtgGf9cV2vmn+txTvxzfsnY/DMNSPjn+u4J+Occ8cc/l6KUf84hV/45z7nzz3nSD/9c13Fr/rl+Ej6Yf+BCFvOPPu3MPyAh5h/Q9MU/IO3MP6DB5R+Q8sA/oMrjHxAS8g8oSvgH5Fz5ByRk/EME2fxD9Hj8Q8T4/AOCMv4BQT7/gJiIf0BPxj8gKOMfOsjgHxAT8g8oSvkHJL3wD+h64h9QlvEPDMr5B2Q5/AMyfvgHhHn8A0IC/gE1If+Aoif+AeVb8A84jYR/QG4Z/6TdhWCKf1ID/0yPQbt/gvQxCNVjzFaR7UIwfaE2/iEnLPxDzhn5R5/i808aftKLv0K1gSaIEiU0Nv5pqj+2zcvucLAA0OW4yw6gIM24139FWTcMASiNy3K9LtoyzqukjvKmLdZ1Fqn7FG2COAqqZQA0Xq2ZgMZHOiHQ9YVjM9A8IYGg8fsooKBrxh8GjZpSDrqmXEHoOulOQtdZPyg0XsutWWj8ufhgGCKWspiG0LwzDsGImIdg1RcQwbgzEcEKF4lgzAMTwS4PimBKSEWwKcEiGHTlIhiRgRGZZJMRWeShEZnjsxFMyuAIJvl0BHMiPIJFGR/BpAyQTEkGIcGcEJFgU8pIMOoFkmDZEyXBtgyTiKSck2CYA0ow5IeUYJqHSjAlYCXYE8ISbHqiJdi+BS7BE0l4CQaXApO6RVCknm7W7x3C+4uyTo9SpUcFeXmZMqhI3WZoFZeWOw2hpdqIyTBjQSbDpJGZ0BwXmuKsVBttrt+Iv65376/H/jqt80Vbo186f/9X12T97efxaffanbY6fD19Hd6tNtXzoT390vWrfHXcvw+/+GP7fXs56vTD0/V86kKu/W5/ujP5q7rI67e73Vv7OrRHi+jn+hWO/vtkxUsvM0vSPM0WPAXtv7evbbP9fvy/223zbMGmybEDOIVBmubd9WysS86GaUxOdVglUR1lZVZHTd2mQb0JmzBa5wrR1AakZeQ0X7OZneZHO9HT9KVk8xPKSAhq/g4LGGqa8kdRs66Uo6Y5V5KaTruz1HTeD03N13Rrnpp/Zj6YqAzLWcxUVMOZqsiQmKvIsi+yIk/gzFZkiUtXZNADX5FtHmGROSFjkV0JZZFRV84iQzLSMmbZrGWs8mjLmOTzFpmVEReZ5TMXmRRRF1mVcReZlZGXLctgLzIppC+yK+UvMuyFwMi6JwYj+zIKM2TlHEbGOSRGxvywGJnn0RiZE/AY2RQSGdn1xGRk/xZURp5MwmVkdBGZqc1UisxSdVVe/zQ4TGblY5CvInXn7d7D0J6scHqI+uOQemIctVwbm1nmLHRmmTbyGTXLJrQ8UpuJPiuhxWGRl/a9Wv979fJ/dNu1DrvXv22fd68WRZsfPkBaUSRqJxXT0U7DkNHUVXtVWOd5oTh0UxdVlLTqkr04X5ftZlPU2TJGA4s2SxoYcMK0+bz6Mf35efej3R/Ugk//rFBs+Mp9Oh7fDuppj9XbtvvaVDfU+l39ZeTh/aAOfyBKElLTkt+2AlXTav5gTU9LbU0ruvKaFnAXNi3hB9m07L69tbNppzx9eofbwTXtYb3fnn6mOP9fJb48bxUH7H9+UfD1Zft6bPebaq0+y19+qM/9l+NT++Wft8d/ea+//NPf/vWP7rZsHZDdDf93itOTUYmvlv590L9aJitarG2G35gzuJlaYnMzxX2xm+kczvJminHxzdT04G+mPI/gTEWhwpnSEogzdV0tztSScZytzBY5W5iHcrYq3+VMZRnNmcp8nTNVRUBnCsuMzlSWMd2CMkPqTFUh1pnSUq8ztb2QnekEntTOdAoZ3JnLcrsz9Tl8Z+r5ETzTGXiIZyoKHM+UFVKeKe1J80ynuAXomc4nMT1TdxnrJY9hru6yPjwsD7Je0B+TqJuxk8/cOx0SF/adcIYV22TPPmrBPXvA6HuGcTbxZckn3iUXhEG44HLM6rn9R/XatPtm27Sv360P5ZsdPhBfpm6XFaoXm7VV7jQMiW9d1nmcbuKmbtKkTIumimJ1JWcThlFcN9XCu3PNf4/dB+r48jwjthGvgQEn4pvP84mPKEmIT0uKiE+r+SM+PS0lPq3oSnxawJ34tIQf4tOytyc+7ZQfTnzmFS0mPkPGmfhMLTHxmeK+iM90DmfiM8W4xGdqeiA+U55HfKaikPhMaQnxmbquxGdqyYjPVmYTny3MIz5blU98prKM+ExlPvGZqiLiM4VlxGcqy4hvQZlBfKaqkPhMaSnxmdpeiM90Ak/EZzqFjPjMZTnxmfoc4jP1/BCf6Qw84jMVBcRnygqJz5T2RHymU9yC+EznkxCfqbuM+OLHMFgl2Sqid+4F6phI+Z6J+C6HJJaLXQ0rthGffdRCfPaAkfgM43zii+JPu4tP3RC/LNUN52x3XKuGF36/s910f3TkAHthkIdloq62ZcneMA1pL6uyoAqSYt3EcRJtyqjabOogq9dJ2NRxvVm2e2+6YovqXV+Hy047tY1uyU678UvI3q6nR0SMN3lXBZv0xsvyiHej5Q1/H+7/1tptclTqVr1u/6z6f3d9+Z3JbrQQhtaNpj1B3WQ9t96GR37tf8QOPHIxy2UO/lHmjnI4I/c43PVGcTjvrnC4wwY4nPNhb7jMZDcck4obroqwDSednQ1nhMRGR/m6RjeZsEYHBaaGo0JOw1GBpOGgDNFwU+hnOCqkM2OUo2Y4KAUzXBVbGc76YTLc9iVkuC7EMSrqwcVwmkViOOVJw3CcCWE4JjEwXJTyF676ki9cvwl64VOJvAsnF1BXch9l3U41ddu2uDcqvJst6p8KkJL3dVMZdZGqutB1wX3d8I8LVuWCv8VhygZcplmzbcFJPmvF6urM6zftz3R/t6KMyyxK7azVKENon/+eWy5KPR82gFYSJFmq7kLH8qzTMOSspl5nmzpMozDP8yytqiaqN3kWh5sgyJM2XMZZo8WaLWt0oNPOtMuLxlasWUFCWKN3UOBXl4o/vLompTvOLiVXtroMupvVZdQPWI1WcmutGn0gPvi+bHgli50KjDsjFWqIhQpFffEUajvbFIpwYQq1PKgUyvJICpWEHoWSEoxCPVeJQg0ZQ1FFtkFRQR5AUTW+PqGijJ5Qke9OqCZCJxSUiRMqyrjJUGRYE6oJoQklpcqEml6ICYU9+RJKy3AJF+WyhLocVkIdP6aEyjxQQiWBJqGckJJQ0pMjofQtEAmdRyJIqLeIj9TNycJwFSariH7uZHelo7KhZHg2pX6Ps+ReZdTjK5NCIZNlpxRYqc2O6BELHNGDRjUCY2wySjJ1q/pPSkZFlIfdtZ62nVBP1fp7u39q97vu5xILHE0PHvgoD8oyirhXOg7TCJBOz04w3sbodNMvbVlmKNIOd+Ki2QvGRiPYkdCR9k4KAGnW8sdI87AUk2Y9V1KajbvD0izgh5e0VRHI9G+jTWPqi/GwPbZfq+Zl+zo8muQvdU/M/faP6then2hivMhX+wh9MDmZ1rMYnsiIMz/RJTFC0WlfFEWfwRmk6BSXpeiiB5yi4zyiontCqKLDEq6iq65oRZdkdGXusgHLnOUxlrnJxyy6KyMtusuHLbop4i06K0MuuiujLmuXAV50U8hedFiKX3TZC4HReU8QRp9AxmGmrhzF6DqHxuiaHyCj+zwmo3sCLKOjQjKjw57gjD7BLfiMPpsE0ejqMkpTT89MVol6gGb/9EywE0s5mTom7e4rlkb4cQHaIerPRupxAeR6baBmG7Swmm3ciGvkMJ/Ygk9MbEERpguI7VU9LHRdHS22Nhw1oFocler+Ycw9WadhRGp3itvqdVnGWRJsykTtxirWYbsusjpT101mebNsT9Z1rWZpux7nRGznF4xta9OABNWu751A084Rf4x2KUr97BxyhbPznLuYnSf9UNl1HYSR/bt6LIQXG7t+Ej4YxeBCFmuYPu3MYCAh9i/Q9AVfIO0sXqDBpS6Q8mBcoMrDLRASqhYoSjgL5FwdCyRkgEUE2XJF9HhkRcT4VgWCMqQCQb5OgZiIpUBP5lEgKIMoOsgQKBAT0hMoSs0JJL1gE+h6UiZQlvESDMpdCWQ5oAQyfiQJhHmEBEICOwI1IRqBoictAuVbMBE4jcSHQG4ZDKnnSKq7zZerNKBhKO8u0Ysj5UckDKmMutIvWEWZZY+VvlCbCJETFgoi54wGpE+x8ScuP+3zIosgKONowc3km+5hkU+758M3da+p1mJA04MHClJPilTMpF5p5vV5/TTEoLZqsjAsiyBrgnVahAqBoiwP11HelpswLpZhkLZoswlphzvR0OzlZAsR7EigSHufBV40a/ljo3lYqkeznisizcbdLWkW8ENK2qpuLUvaR+eDgcm0nsXOREacuYkuidWJTvvCJ/oMzgZFp7gURRc9iBQd58EU3RP6FB2WMBVdddUquiRDK3OXbVfmLI+wzE2+ZNFdGWjRXb5r0U0Rb9FZmXLRXRl2WbsM86KbQvqiw1IBo8teIIzOe/Iw+gQyFjN15TpG1zlIRtf8WBnd55EZ3RPIGR0VAhod9uRo9AluwWn02SSqRlcX4Fp8H0XdbdzTbJX0O6rArqvsPgwfFZulwSokdl1phxh2XZHrtRmbbdBCbbZxo7iRw2x4y0p1u6brt/3PdC8sdSupOIjUb992YWP9vm3efz5t2/fQom6jIwdyy/IoDdnbr4ZpSG5JuymqKCviPCmqJq/CTRzU7VqdrGrXm7ReRm7TFZu9bXqsE7aNX0K2tOkRCbNN31WBsY1D/oBtUpXq2jjmSmvjWXdXG0/7QbXpem4tatNPyQdzGrmYxZaGC86QRmTEikZ0fREakXf2M6LDxTMi50HOiDKPzYiY0MyIqgTMiKSrlhEZGZUZomwnMzR5SGYI8oWMiMp4jIjybYwIimCMaMpUjIjKSMwcZXgYERRiGFGVShiR9cJgRNuTgRF1GYCRUbl+EWkOfREpP+5FxHnoRcQE4kUUhdxFVD1ZF1G/BXQRp5IoF5FcRFyh2vgVrGJ1fy1q/1h8fz2GIK74PlBSpq49VHf7yi37x/Bibb5lnLLglnHWKFt4kstaWRiop+p9UtZKo7JIFjy58GX7vf2h7uizP1hU63rggFphUpa5ulqTtY3sNAxJq84q9ZTCOC2raFMldVmHUZ4Xrbrte1m0YbzwNu+T5ZpFa3KoE2iNXjy2Z2kNCWdN3k2BZo06/jBrHJVa1qjlSlmjUXfJGg37gazJam7tWJOPxwczFrWWxYoFA86IhStiw8JZX4SF686ChTNcwMI1D36Fwzy+wi2hXuGoBK9w0dWucEVGV3STLVd0kgdXdI/vVrgpYyvc5KsV7onQCidlZoWbMrIyNhlihXtCsMJRqVfhqheuwmlPWoXjMqyimnKrwmUOVeGSH6nCbR5U4ZbAqXBQyFQ46kmpcPwWSIXPJDEqXFxEVEH+GKlrF8tV1F++CHZhKX/qj0lD8imE2iGGXVhwrTahMg1ZgMo0avQpOMjlqThO1PV+n5SnojxKIqVztl1X/9juXr+tn7bVy3b3h0WoJscOSBXFcaae88gyqn4WElVStuqhg6F6BmEZqxtfreuqSdVljk1eFAodg/WyXVfz9ZqVan60E1RNX0a2VaGMhKvm765ArKYpf2g160rdappzpavptLteTef9ANZ8Tbc2rPln5oMZy7CcxZJFNZwxiwyJPYss+yIt8gTOqkWWuLBFBj3YFtnm8RaZEwoX2ZUgFxl1dS4yJKMuY5atXcYqD7yMSb55kVkZe5FZvnyRSRF+kVWZf5FZGYHZsgwFI5NCCCO7Ugsjw144jKx7EjGyL0MxQ1buYmScQ2NkzI+OkXkekJE5gZGRTSGTkV1PUkb2b4Fl5MkkXkZGF5BZdB8Vj0G0CmMlYgSZnY9JcyVr+K5gl0y5Cm13BaOWa1Mzy5wFzizTRjujZvl81l2190n5LIjSqEjtfPb3l3W1f7O42emg866uTLlkpl5ZFpmFp2mIZmkYFvUmqvNNHmdhUqvrFuOoSrpNXUHetgtvFX9ZrFnLLoc5MdnwcrF9bDIvgbHL+yYQsaHhj8LOQamBDR1X/BrG3NVrGPTDXZdV3Nq5Lh+BDwYutI7FsqUNO5OWXhBblp70hVh62Vmv9ASXrfSSB6/Sozyo0jtCodKDEprSa64mpRdkGIV7bIXCOR4/4RbfnfSeDJz0Hl+a9JaImPSczJb0ngyVyB5Dk/SWkJH0oNSP9KIXONKznsRID8uoCPXkRqRXOTikV/yokN7lcZDeETiQHhMCkB70JD96+Bbko59FYj16bRnyBN01d3G+iqlL95TgqGOyVaTuTkUjT39IWNiRR1unTXeoAQvrUGNGz9GG2JATFeo6tc8JOVkZFmW24DK9ar97qV53f2zXTxbNGR05kE5RhlGmnivIEp3TMASdtkjrvK3XRVOtm6oq0qCJy7Lc5Ossz+IkXrYLarpes+pMj3WinfELyPYdPSJBnul7KpCeccgf90yqUvMZx1zhZzzrrj/jaT8ENF3PrR1o+in5YAwiF7NYhHDBmYWIjNiGiK4vICLyzkpEdLhUROQ8eBFR5qERERPKEVGV8BGRdDUkIiODJEOUrUmGJo+UDEG+KxFRGS4RUb4wEUERMxFNmTURURk4maMMdSKCQnoiqlJ/IrJeEIpoe5Iooi7jKDIqNykizYEpIuVHp4g4j6iImMCpiKIQq4iqJ7Ei6rdgK+JUErsikosAK8w7eYqDVUDdXj26D/udTEmwSgpql9KQURQWW+49hRdrUyzjlIWyjLNGz8KTbNSKA3VrpE+KWlmpru1TDxi0XdxX1e3huLN5Vn/QQFlpWRbqokmWZPWzELKSuoqqdbhZJ3Ub52HUBEmSROu8SNUv5lG7ELLOC7UY1vkwN746vVR8uRrPi9Dq/J5JvOrU8EhVQ1CsVKeOM1Cdxhg2dRr0xFLnVdxcpM4fgY/GKLCO5Q41H3YnKK0g1yct6Q2etLK7OWkJNjdpJR/SpEWZyKR1pL6kBUW0pNWcVUkrCEEJ9viWBHNMRoItgSBpPSEeaT2BG2ktGRlpOaEWaT0hFFE9jhFpLSkPaUGxDGlFPyikZX15kBYWUhDoeVAgrcoCIK3iyX60LpN9tI5EfLSYFHu0oC/n0cI3IR7tLCLd0WrLYEdtKeovP0sS8vKzUB2TKPkZdi+9vR+e2uZrdbxb3UVBmKg7it/PDlF/Zn193z+rA9Q/rR6Gn9N/V3/wPGg/uVtNZ/4bGwZsnEOMmSVnPsRGnChU11h9TsRJiyRJlzwX7/BUffv28/hj1+zeWovlTI4dSCdK0zwNuagzTEPWScu4WgfrrMnaJGvjNA+zom2SsgnauG7bZBnrzNds1p350U7IM30p2daDMhLymb/DAvmZpvwB0KwrdaBpzpWDptPuKjSd94ND8zXd2ojmn5kPpiLDchaLEdVwhiMyJPYjsuyLkcgTOGsSWeKiEhn0YEtkm0dMZE4oTWRXAk5k1NWdyJCMn4xZtkIZqzyMMib5JkVmZTRFZvlCRSZFUEVWZV5FZmVsZcsy9IpMChGL7Eotiwx7IS2y7km2yL4MuAxZuXORcQ53kTE/6kXmefhF5gQGRjaFFEZ2PYkY2b8FjJEnk/gYGV3AZOF92D80T0kZuf9pfExPaTqT9YcE8UphWtpfB2hgMmq5Ni2zzFnQzDJttDNqlk1oQRl/WkJT3pR1gmjbB/V/Va+vL5XFzk4HDWiWhVkS51w0G6YhmrXtul6X67opizqtYvUkvipdl0kZpEHRBvVmGZpdFmvWssthTkw2vFxsH5vMS2Ds8r4JRGxo+KOwc1BqYEPHFb+GMXf1Ggb9cNdlFbd2rstH4IOBC61jsWxpw86kpRfElqUnfSGWXnbWKz3BZSu95MGr9CgPqvSOUKj0oISm9JqrSekFGUbhHluhcI7HT7jFdye9JwMnvceXJr0lIiY9J7MlvSdDJbLH0CS9JWQkPSj1I73oBY70rCcx0sMyKkI9uRHpVQ4O6RU/KqR3eRykdwQOpMeEAKQHPcmPHr4F+ehnkViPXrMhT6xo5j6M+4vcylWSo71Q6JgZ8pwO6ZEnVVzUXwdnQB5tnTbdoQYsrEONGT1HG+JCTvFZbrb9Uh2O7f7ur99+3W2bO8V8SZrGyYJbNLWHan1svx+q2iI51wPPmlOUaanOwLqsLeuHoeUEbdqqq9nSdbIpSrXhKU6jfFME6mF1Sdqm9cIbNE2Wa/acyaFOpjN68diuozUktjN5NwW+M+r4M55xVOo8o5ar9YxG3b1nNOzHfCarubX7TD4eH2w/1FoW+w8MOBsQrogdCGd9WRCuO3sQznBNCNc8uBAO82wIt4Q+hKMSI8JFVyfCFZkV0U22F9FJnhnRPb4b4abMjnCT70e4JzIknJQ5Em7KLMnYZHgS7glNCUelroSrXmwJpz35Eo7LjIlqyp0JlznWhEt+vAm3eeaEWwJ3wkGhPeGoJ3/C8VsYFD6TxKFwcYFFqZ1C2WMUrqJiFfeI9P7WVMfpRXfJfZj2j45T1+X1d1PSNxypm4ori0pXkbqveH9TcYNFwbXaPMo0ZDEp06jRpeAg16bUA8vKT7LJSNOpuLuDuLrVlG2P0dvupd63jdppZLtIb3Tk2adyde8kdT8nnk/1w9Cn0rAIoqjaxE1dpHGYRHW8yZMwDvO0SsMy6L5k+utPn47Ht4O6ArV623Yf5qf3ur8K9f3Q7g8P0/WagWp6rJNQjV9ANlHpEYlRTd9TAVKNQ/6UalKVMtU45upU41l3qBpP+5Gq6XpuTVXTT8kHWxW5mMVYhQvOWkVkxFxFdH15FZF3BiuiwxUrIueBrIgyz6yImBCtiKpErYikK1sRGZlbGaJsuDI0eXJlCPLpiojK7IqI8vGKCIr0imjK+IqIyvzKHGUAFhEUChZRlRIWkfViWETbE2IRdZlikVE5YxFpjmMRKT+QRcR5kkXEBJRFFIWWRVQ9YRZRv4VmEaeScBaRXOZZyWMYrGJ1GynqCXjxfaBuMh53NxmPCM8aH9JfY2fwLLxYG2gZpyyiZZw1khaeZJtWHH2Wp+LNTSvurm3LF1w31+zevz1X+/a7ZcPV5bjBs8KkKMKY+0S8YRqK1iaJ0qQK4zaPirrKkjJKwjbN86xWp0yaeplojddr9qzxkU6adX3p2JY1T0gka/xOChzrmvGnWKOm1LCuKVfBuk66+9V11o9ejddya7safy4+WK6IpSx2KzTvrFYwIjYrWPUlVjDu7FWwwtUqGPNgVbDLkyqYEjoVbEqUCgZdjQpGZEJFJtk+RRZ5OkXm+DYFkzKZgkm+S8GcSKVgUWZSMCkTKVOS4VEwJ9Qo2JRaFIx6kShY9uRQsC1TKCIpNygY5ggUDPnxJ5jm6RNMCewJ9oTyBJue3Am2b6FO8EQSc4LBBeIU3KtnzQXFKlXiFBI7qNT2KHXFn3pkXbYKiFs2jQ+xPbIOLdXmTYYZizYZJo3WhObY0hR1FHL9Rvx1vXt/VbeFVxf8/aiO6ye1x2b0S+fv/2pXzt9+Hp92r91pq8PX09fh3WpTPR/a0y9dv8pXx/378Is/tt+3l6NOPzxdz/ey3e93+9NN51/fn59/u1P3FH8d2qNF9HP9Ckf/fbLi/l+adlO9Px+/nv6Oq1bcqL+MP+/erhf3xUlZBqE61LZ96vWPrW3fVHfIAExFrO6eztwv1c9CXEqyrN3kaRZWQR0GQbNOqzCIQnX5X5lFTVQsw6VhmWZXGg5yIqX+JWJr0mhaAknD+yQwpL7gj49OOakc9RVXNOqH3L2oH/NDRcMKbq1Ew5v+wUCkr2KxDc1GnVloPi8WoXnQFwbNu84ONA9wCWje8aA/8yQPfuYVofnMcxLumbdcpWc+L0MeVGP7DorxaAeV+Kozr8lAZ17jW868JGKceUwmOPOaDG+IGsNt5iUh2cxzUq2Z97xAzTzqyWjmWRnP6DW5zMybHJSZN/x4zLzKo5h5RaAw85QQYOY5T/Yyz96CXebnkIjLvLUMW8IOUtJyeETc/HI1dV8kBTLqWrRwFaeroL+kTb91kjok7K56U/fHTlLL9p7ZKm3Ogg+3EAseMurKbIQLK1EUZp8WVqI4i7qr8myw8vfN80/L9p3ukAFWojxPcq6snIYhrTRJlSfrTRRXm7SIyyou6qgIi3RTq0cAJuXCfTvDQs20MhzkRCv9i8SmldG0hFaGd0pAK33BH62cclJa6SuutNIPudNKP+aHVoYV3JpWhjf9g2lFX8ViWpmNOtPKfF5MK/OgL1qZd51pZR7g0sq844FW5kkercwrQlqZ5yS0Mm+50sp8XkYrqMamFRTj0Qoq8WllXpPRyrzGp5V5SUQr85iMVuY1Ga0QNQatzEtCWpnnpLQy73mhlXnUE63MszJa0WtyWpk3ObQyb/ihlXmVRyvzioBW5ikhrcxznmhlnr0FrczPIaGVeWsRrQThY5D1JgLvBNTTijomVLSibhjUX12FaGXIqLtS266cmq3SRiv4cAut4CEjrcxG+LQSqPvRfNI9K8qVgkA9+8tGK8cfFlg5/jizSprHZfegNtYdfqLTNISVarOpiihro82myOqobRv1ZLE2a7O6XldNUS3bs9Iv1Mwq/SFOqKJeHjapXGYloNK/PwJOUfP+MKWLSSlFNVwhRY24M4oa8oMo/dlvTSj92/zBgDJfw2I+mQw648l0Wkwn05wvOJlWndlkOs5Fk2nFA5lMgzwwmTaEXDKNSbBk9oZV3w7qj/76eVcfTjtHqdvF9X/QPEynZVCit9hMoqd4SKJ3+EQybcmAZNri84i2pv236k+1RVl9BMa44f5JkNHIbFmn76T1aV3j76vu6xpP97/Jl5ftkfFJF6KI/rmaB8+s4f5b9AIi0wV64pBpVIYh85acQqZFDoRMC34YZNrkIQh6M389vL6/qC+pv9RXQS8Z7h80IYDMXu/tc3s47l7bw3hlE71wX+Et8GO6bAl9TEt2+AjK+zjoHselLs5J4C1j1M1gxsegW8b0h0RFd5fkoFyltsdxTdZoYw90sAU90IiRPCYD3c+xu5f2rfrWDve1Vbe1HX48ePv5+76tmuNT2+zWh9/Vj1IP6vDD9k91aBR2T/v+nOARKZpIc7WVxgYe/+f79+pge4766SD1wvZP94qLKE1VmgUfwzSED/Xw9LZtg7QqNkkarcs6DOMmDaOyCNo6aBO1gAX3Nr4s1owfl8OcAGR4udgIMpmXQMjlfRNgyNDwByLnoBRFho4rjAxj7jgyDPoBkssqbo0kl4/AB0MJWsdiLNGGncFEL4jRRE/6ghO97IwneoILKHrJA6LoUR6k6B0hpuhBCajoNdf9J3pBBiu4x8YVnOMBC27xkUXvyaBF7/GxRW+JdqPoORm66D3ZjhSyx9iTorfmXqK+QtQl7Ys1Rw9K96XoRS8Qo2c9YYweloEM6slRRq9yYEav+MEZvcsDGr0j2Keix4RQowc97VXRw7cAG/0sErTRa4vgJlK7UYL+rioRuvPKSWXUMckqzFdhf6WPtmOlg5tTphgy3R96p5971T9d6KN/mo+2ThveUAMWwKHGjIijDfEhp3ta02eFnCLKC3X5jg1yXtSTnZ6fbZIzHDVQThYXecZ+iHo/DCFnHTVJW+exukQo2zRBFefrKNyom/lWZZ2ty4WQc12rWXKuxzlRzvkFY1vONCDBnOt7J9Ccc8Qf51yKUs85h1xB5zznLjrnST+kc13HrU3n+kn4YNSBC1msOvq0M+uAhNh1QNMX7IC0s+yABpd2QMqD7YAqD3dASKg7oCjhHZBz9R2QkAEPEWQLD9HjEQ8R4xsPCMqQBwT5ygNiIuYBPZnzgKAMeuggQ3pATEg9oCi1HpD0gj2g60l7QFnGPTAo9x6Q5YAPyPgRHxDmkQ8ICcwH1IToA4qe1AeUb8E+4DQS9wG5ZfATPEaBur3LKiXg53SpUqCOUf/rn0gO4UfdlTdUt+1dhbaHlusLtckPOWGhH3LOaD/61H/hz+jmwAtvtRsVgbKfBU8qf6n26/agbjtsuXrpctx5L0+UByH3KeVhPwwBKK7zdV7UpbrjbtVu4kL9Q96uizxO6rBY5+WynTzj1VoI6Pz7V2E3BLq8cHwGmiVEEDR6HyUUdMl4xKBrU8xBl5QzCF0mGSR0mfWEQqO13JyFRp+Lj4YhvJTlNATm3XEIReQ8hKregAjF3YkIVdhIhGI+mAh1mVCEUlIqQk0RFqGgMxehiBCMqCSfjKgiE42onICNUFIIRygpoCOUk+ERKgr5CCWFgGRIcggJ5aSIhJpiRkJRP5CEyr4oCbWFmISTHjgJhVmghEKeSAmlmaiEUhJWQj0pLKGmL1pC7ZvgEjqRiJdQcBEwhb0MqV1DaX8TG/02w2rb0PWYjAKmMOgvCYtWcX+IYWcREgUrMYHf3jBjQyZ60sxMYI4PTd1WmE+6yygvcnWrX/suo+rb+/bZgkz9MQMwJQqwgoC7xWiYhsSUlW2eBWVYVkHUFmGZVWWQV3EQrou2UnfLWUZM57Waeel8lBMtnV4qNiuNxyWkdH7HBJx0SvijpKEnZaRTxpWQTlPufHSa80NH5zXcmo3O7/0HkxFYxmIums86U5EWEDORVvRFRFrYmYe0ApeGtJAHFtKaPBLSMkIO0noSCtJirgykBWQEBHNs/oE1Hv3AFJ99tJyMfLQcn3u0lIh6tJqMebScjHioHIN3tJSQdrSelHW0oBfS0aqeOEfryigH5OSMo0U5hKNF/PCNluXRjZYRsI3WEpKN1vPENVr3FlSjnUTCNFpsGdFEj2G6ispVZCCayzEeiGa+TBvPEMdbaIaYMrLMfOa/SIax9yfLwjJR9xe2Xfi1331r90/vFpQZjhpYJo6yIuXu+zkNQ5SJ1bVeURWtN2mWJGmxactovS7CNg3qPFG/tAxlrms1s8z1OCeYOb9gbJqZBiQ4c33vBDxzjvgDmktRSjTnkCvSnOfcmeY86Qdqruu4NdVcPwkfjDVwIYu5Rp92BhuQEJMNaPpCG5B2ZhvQ4MINSHmgG1Dl4Q0ICfkGFCWAA3KuhAMSMsQhgmzGIXo8yCFifMoBQRnmgCCfc0BMBDqgJyMdEJShDh1ksA6ICWEHFKW0A5JecAd0PfEOKMuABwblxAOyHOQBGT/MA8I86AEhAfWAmhB7QNET94DyLcAHnEZCPiC3CH2C/FFd9aXu1my640/xqDbuBMkqJdFHZbo7AqkHiYeWfTn6Qm3sQ05Y4IecM9KPPsXHn/LTPgpcPQk8TYIFd/15+9lUr6+2p4EPRw34k0V8++lnIf1kubpzcxIFTdI0cVJGQZlX6h5A+SZJNnmR5cvo57pSM/1cj3Oin/PLxaafaUBCP9d3TkA/54g/+rkUpfRzDrnSz3nOnX7Ok37o57qOW9PP9ZPwwfQDF7KYfvRpZ/oBCTH9gKYv+gFpZ/oBDS79gJQH+gFVHv2AkJB+QFFCPyDnSj8gIaMfIsimH6LHox8ixqcfEJTRDwjy6QfERPQDejL6AUEZ/dBBBv2AmJB+QFFKPyDphX5A1xP9gLKMfmBQTj8gy6EfkPFDPyDMox8QEtAPqAnpBxQ90Q8o34J+wGkk9ANyC+inuI/S7p4/SXcvZ+KSrNMxsXoQFUk//SGh2jOUreL+ftCGS7L0hdroh5yw0A85Z6QffYpPP5Ha+HL95qru+f/+euxvmvOjOq7VfW4Oo186f0dXDwf728/j0+61O211+Hr6qrtbbarnQ3v6petX9Oq4fx9+8cf2+/Zy1OnHnev5Xrb7/W5/uv/2q3qC3m93u7f2dWiPFtHP9Ssc/ffJihfe8yfMs6J/cJlt38/3ulL/s2z7OR103vWTFbEyJdZzu+JuFsJPlKflOk7SOI7bNmnzTasuJivVM8tD9QTzqF0vg5/LQs3ucznMiX2Gl4qtPpN5Cfpc3jOB+QwNf+RzDkrFZ+i4gs8w5u49w6Af7rms4tbac/kIfDD2oHUsth5t2Jl69IJYevSkL+jRy87Ooye4zKOXPCiPHuUhj94RGo8elBCPXnMVHr0gAx7cY/sOzvF4B7f4uqP3ZLij9/i2o7dEtKPnZLKj92SwQ/YYrqO3hKyjB6Wqoxe9oI6e9WQ6elhGOqgnFx29ygEdveLHc/Quj3P0jkBz9JgQc/SgJ8vRw7egHP0sEsnRawsgJ+8ft55299YJ+v054N46F6XptvHge+sU990eHrXHJ7bv4dHWaXMcasDCONSYUXG0IT7ipAobPiniqOeXR8WCi7f+o63Tpj1sv71aIOd64BlzyjAOSq7m9MOQc7Iib0r1wK5MXbPVtBt1/55NmG7CvC3LoA2yYhnnTJZrJp3JoU6sM3rx2LSjNSS8M3k3BcQz6vhjnnFUSj2jliv3jEbdyWc07Id9Jqsh6Off9t+q1+2f1XHb0/Jhe2y/Vs3L9nVA47/Uzfz32z+qY3u15uPL8/DMxqfj8e0wfWrj5GPywQxErWUxBcGAMwfhipiEcNYXC+G6Mw3hDJeHcM0DEeEwj4lwS0hFOCrhIlx0JSNckbER3WTTEZ3k8RHd4xMSbsoYCTf5lIR7Ik7CSRkp4aaMlYxNBi3hnpCXcFRKTLjqhZlw2hM14biMm6imnJxwmcNOuOSHnnCbx0+4JSAoHBQyFI56oigcvwVH4TNJSAoXF7FUmPWelK6SfmMQYKn8fnaM/kyx/hB1v+coX8W2Z4rBtdpoyjRk4SnTqJGo4CCbqYLs8zJVpO6wnKf2vUY/qupHZbvv8+mggafKLFRP+2Ly1GkY8lSR12lQqkeIJXlepYmyqqJUt64ugmidrjdNtoynLks109TlMCeWGl4sNklN5iUcdXnXBBQ1NPwx1DkoJaih48pPw5g7PQ2DftjpsgqCnP790O69UNPlI/DBzITWsZiYtGFnXtILYlrSk75YSS87k5Ke4HKSXvJASXqUx0h6R0hIelDCR3rNlY70goyNcI9NRjjH4yLc4lOR3pMxkd7jE5HeEvGQnpPRkN6TsRDZY5CQ3hJykB6UUpBe9MJAetYTAelhGf+gnpx+9CqHffSKH/LRuzzu0TsC6tFjQubRg56IRw/fgnf0s0hoR68tYh21TUhdD5aUqzQgWSfKHiN1LyC126inH8Q6p0waqhtOWy4b09ZpIx1qwMI51JiRcrQhPuMUajPMp9ht9NZdAncf3v3126+7bXO3CoMiyYNiAeM87w7KE7offSy7ja4HDpyTZVlSqv1MrGvHTsOQczZBExRFuA7TsI6bsGyzoK2KIItC9TAvteloGedMlmsmncmhTqwzevHYtKM1JLwzeTcFxDPq+GOecVRKPaOWK/eMRt3JZzTsh30mq7k1/Uw+Hh/MP9RaFhMQDDgzEK6IKQhnfXEQrjuTEM5wWQjXPNAQDvN4CLeERISjEibCRVcqwhUZF9FNNhnRSR4b0T0+HeGmjI9wk09IuCdiJJyUURJuyjjJ2GSQEu4JWQlHpbSEq154Cac9EROOy5iJasqpCZc53IRLfsgJt3nshFsCesJBIT/hqCeCwvFbMBQ+k4SicHEBR2X3Ufio7l4dF8QNrJP7ILwPo8cgWEXFKunvTq1zVHYfFo9BtkrVs+X7myGpP+eGyx/UP00vfoBrtZGUacjCUqZRI03BQT5PReqWPp+Cpxr1l/Xn3duEp6J0yZPMXtQlNtWhttjUcNQAU1EW5KG66xILpk7DEKaqdt2EeV0XeZo2WVOu2426n1GyWcdBXKvtRstg6rpWs0pdj3MiqfMLxvaoaUCCUdf3TiBR54g/hroUpQZ1DrkC1HnOXZ/Ok37o6bqOW7vT9ZPwwegEF7JYnPRpZ24CCbE1gaYvaAJpZ2UCDS4xgZQHXwJVHi6BkFCWQFHCSiDnakogIQMlIsjWJKLHoyQixnckEJQhEgjyBQnERHwEejI7AkEZHNFBhhqBmJCMQFHqRSDpBYtA15MUgbKMiWBQbkQgywEikPGjQyDMoyEQErgQqAlRCBQ9iRAo34KDwGkkFgRyiyFI7TlSt6KmLzcL4scg7h5TFpIQFCkrUgqk7oodWSBIX6hNgcgJCwGRc0b/0af4+JN92ttZB1GWRNGCJ5lVz+0/1G2339q9xX+uBw4EVMQ5/1Kz0zAkoCirqzAuwk1ZVUFUV3XRFJsy2Sg1Kpu8Wvgw+8lyzQo0OdQJgkYvHtuCtIaEgybvpkCERh1/KDSOSl1o1HKlodGouw6Nhv0A0WQ1tzaiycfjg5mIWstiKYIBZyzCFbEX4awvMsJ1ZzXCGS4c4ZoHO8JhHh/hllCQcFSCSLjo6ki4IqMkusnWJDrJAyW6xzcl3JSxEm7yZQn3RLiEkzJfwk0ZMRmbDGXCPSE04ajUmnDVCzfhtCdxwnEZOlFNuTvhMoeecMmPPuE2D6BwS2BQOChkKBz1JFE4fguMwmeSeBQuLiCp9D5KHkO17yhfJTG6VE7tTVLHlI9B2O1fCtGNuS+HqAe1qf/ZSAqu1aZSpiELTJlGjTYFB7k8FWdB9mn3JgVFmOQLeGrTvrbfv79bbGo4aoCpsIyjLA2Zm5OGaUhThbrkry6TJqziNsvLOMiTvEzDTbtJ6yQL42W7k66rNbvU9TgnlDq/ZGyRmgYkHHV99wQWdY74g6hLUapQ55ArQZ3n3P3pPOkHn67ruLU8XT8JH8xOcCGLzUmfdgYnkBBrE2j6oiaQdnYm0OAiE0h5ECZQ5fESCAltCRQlsARyrqoEEjJSIoJsTyJ6PEwiYnxJAkEZI4Eg35BATARIoCfTIxCU0REdZLgRiAnRCBSlYgSSXrgIdD1ZESjLoAgG5UoEshwiAhk/PgTCPBwCIYEMgZqQhUDRkwmB8i1ACJxGokEgt4iCwrR7RluQryLqrknZfRB1d02K8+EBbPplaul9rK52U5e6JUPGcJmavlCbA5ETFgQi54wCpE9x+ScKAnX91PWb6+ih9j+6Ow21+8Pol87f0e9Wd3/7eXzqn4j0VB2+nr7qrg9AUr90/YpeHffv7em4H9vv28tRpx931K6f1+PdSi3iZbvf7/anKwdf35+ff7vbvbWvQ3u0iH6unxj99/7fzyvu/0U9vqx6fz5+Pf09Va14fmlaWSZhkqj7Rr1WL+rhTd1li0/vdfz720/1u9qoBXwd/sNLe3yqXluL/gxHXfSnTEt10R/ryrSw7Iah/cRpWIXBJi4jtfg4Sdsmy6sgbcsia9ZJ0yyzn+tazfZzPc7Jfs4vGNt+pgGJ/VzfO4H9nCP+7OdSlNrPOeRqP+c5d/s5T/qxn+s6bm0/10/CB9sPXMhi+9Gnne0HJMT2A5q+7Aekne0HNLj2A1Ie7AdUefYDQkL7AUWJ/YCcq/2AhMx+iCDbfogez36IGN9+QFBmPyDItx8QE9kP6MnsBwRl9kMHGfYDYkL7AUWp/YCkF/sBXU/2A8oy+4FBuf2ALMd+QMaP/YAwz35ASGA/oCa0H1D0ZD+gfAv7AaeR2A/ILbKfoOhuUZSq//VXnYEHoaX33TEKftSdjPrbYSP7OR0SqQ1F/W4ig/3oC7XZDzlhsR9yzmg/+hTXfkIFIJ/VfvIsLpfs/Pl79fPP9vWbxX6Go872k4RFyd740w9D+1lXcVwVTdkWdZkVUbZO1K6fOqjrtCnTplkvs5/rWs32cz3OyX7OLxjbfqYBif1c3zuB/Zwj/uznUpTazznkaj/nOXf7OU/6sZ/rOm5tP9dPwgfbD1zIYvvRp53tByTE9gOavuwHpJ3tBzS49gNSHuwHVHn2A0JC+wFFif2AnKv9gITMfogg236IHs9+iBjffkBQZj8gyLcfEBPZD+jJ7AcEZfZDBxn2A2JC+wFFqf2ApBf7AV1P9gPKMvuBQbn9gCzHfkDGj/2AMM9+QEhgP6AmtB9Q9GQ/oHwL+wGnkdgPyC2wn+Q+Dh673TrlKskI++mPUXuDkvO9p3X7OWXS7sZF1kvA9IXa7IecsNgPOWe0H31KYD/5Z7WfRN3WuVQXvdn2/TTfvm9fisRiP8NRg/3ERRyy9/2chqH9VOuiKqOgLaKmSNWdqasoUhucmrAN6nAdBeUy+7mu1Ww/1+Oc7Of8grHtZxqQ2M/1vRPYzzniz34uRan9nEOu9nOec7ef86Qf+7mu49b2c/0kfLD9wIUsth992tl+QEJsP6Dpy35A2tl+QINrPyDlwX5AlWc/ICS0H1CU2A/IudoPSMjshwiy7Yfo8eyHiPHtBwRl9gOCfPsBMZH9gJ7MfkBQZj90kGE/ICa0H1CU2g9IerEf0PVkP6Assx8YlNsPyHLsB2T82A8I8+wHhAT2A2pC+wFFT/YDyrewH3Aaif2A3CL7CfPuVtKxuiN1f98esO8nuZ8dg+wnzPrtQ+Uqtu370Rdqsx9ywmI/5JzRfvQptv0U5ae95iuMkqK7H7fNfv7eHg7d33abrYV/rgcOApRFSRIVzCu/TsNYgMpyrS4Lq9MqrvI2qdIoUrf+qTZ5XNebOm6XCdBkuWYEmhzq5ECjF49NQVpDokGTd1MAQqOOPxMaR6UsNGq5ytBo1B2HRsN+fGiymlsT0eTj8cFKRK1lMRTBgLMV4YqYi3DWlxjhujMa4QzXjXDNAx3hME+PcEsISDgqMSRcdGUkXJFJEt1kYxKd5HkS3eOTEm7KVAk3+bCEeyJbwkkZL+GmTJiMTQYy4Z7QmXBUSk246kWbcNoTOOG4zJyoppydcJkjT7jkB59wm+dPuCUgKBwUKhSOeoIoHL+FReEzSTgKFxeIVNzdPkiJVJSskv5m00CktGN0kVKHqE1N8SpVNyLqb2ZkuBINrtWGUqYhi0uZRo00BQf5OhV92qvSgqKIigX3o26qp+dtZZGp00GDSin3itmXpHWz0KQ2QRNHdZ5FdZysN+s4ztflpq6CuF7H67ZZ+JC0y0LNHnU5zMmihpeK7VCTeYlBXd4zgT8NDX/2dA5K3WnouJrTMObuTcOgH2u6rOLWznT5CHywMaF1LPYlbdjZlvSC2JX0pC9T0svOnqQnuJaklzw4kh7lGZLeEfqRHpTYkV5zdSO9IDMj3GN7Ec7xrAi3+E6k92RGpPf4PqS3RDak52QupPdkJkT2GB6kt4QWpAelDqQXvRiQnvXkP3pYZj+oJ3cfvcoxH73ix3v0Ls969I7AefSY0Hj0oCff0cO3sB39LBLX0WuLTCcqHqN4FaibS1PPvY/7h4wlq6BYRQW+u5A6pM+ox5WlucV0tHXaPIcasFgONWZ0HG2IbzihUozrt9HPdFdp9XCuPFX7q2w7jJofb9X66X1vZZzzcef9RXGQdFevse4snfXD0HKaoizrOmvTuFX3E8qLKo+6o6Nkva66x4st2190+V11H53jy/Ppdt7qH49vh9XDIFa/q2/BD+Mj3UTn8sLxUWeWELnO6H2U0M4l41F3rk0x8FxSzsZzmWQwz2XWk/SM1nJz7Bl9Lj7ae/BSlpMPmHdXHxSRww+qerMfFHfnH1RhCxCK+UAg1GU6EEpJKQg1RRqEgs4ghCJCE6KSfBaiikwZonICHEJJoQ+hpICIUE6mRKgohCKUFFqRIcnhIpSTihFqitEIRf24ESr7oiPUFuoRTnoAJBRmGRIKeWIklGZKEkpJMAn1pJ6Emr5ICbVvokroRCJYQsGlthSq686iVUo9tUw9oD7qH0mWqgeXYVvSDjHsF0KiYOUl8NsbZmzCRE+akQnM8Z2pu5brUzpTUWTKZxbcxej41h73lq1C/TGDLyV5mHIfXNbPQl2K83oT5EXRBurWS0VWF+sq2qzrqMrWaRaHm2W6dF6nWZbORzmp0ullYovSeFyiSed3SyBJp4Q/RRp6UkE6ZVz16DTlLkenOT9qdF7DrcXo/N5/sBaBZSyWovmssxJpAbEQaUVfOqSFnWVIK3BVSAt5ECGtydMgLSOUIK0nUSAt5ipAWkCmPzDHlh9Y46kPTPHFR8vJtEfL8aVHS4mUR6vJhEfLyXSHyjFkR0sJVUfrSUVHC3rRHK3qSXK0rkxxQE4uOFqUozdaxI/caFme2mgZgdhoLaHWaD1PUqN1b6E02kkkQqPFFulMqJ4Zpm4sXaxi4mquMLoPykf1xLA4XIV458/lEHVdWGi7v9B8mTaZIY63qAwxZRSZ+QxXY6I0/LQakxRJkKf2XT//8dTu28N/VPvmp8VkRkcOMpMHYca+s9BpGNrMOgzWdRJvskRdtpVURaCeQJYnUa5uExU09TpdZjPT9ZqFZnqsk9OMX0C21ugRidlM31OB3IxD/vxmUpUqzjjmajnjWXfRGU/7cZ3pem6tO9NPyQcbD7mYxdKDC87eQ2TE6kN0fdkPkXcWIKLDdSAi50GDiDLPhIiYUIaIqsSHiKSrEhEZmRUZomwxMjR5bmQI8vWIiMoMiYjyJYkIijyJaMpUiYjKbMkcZQgTERQ6E1GVahOR9WJORNuTPBF1mT+RUblCEWmORREpPyJFxHkuRcQEOkUUhUZFVD1JFVG/hVcRp5KoFZFcYFdRd7mZet59lK4i6rlo8X0QPkbq/tmZ4iu8s2h0SFRarlrDi7UJlnHK4ljGWaNm4UmuaYV5pDbDfM4dRkGqbvyz4Eq2l3r3DwtmdYcMilWkacG9E1E/Cw2rDDbhOlE3xg7LqimSNkvWcV20apNR3UZVufDu2MMyzXg1HOSkVv1LxOaq0bTEqYb3SQBUfcGfTJ1yUpLqK64W1Q+5I1Q/5kefhhXcmp2GN/2DvUlfxWJomo06C9N8XkxL86AvU5p3nTFpHuAq0rzjgY/mSZ4bzStCMJrnJFI0b7kS0XxeZkOoxkYhFONpECrxGWhek/nPvMaHn3lJJD7zmIx65jWZ8RA1Bu7MS0LVmeeknDPveXGcedQT4MyzMrnRa3KymTc5VjNv+EGaeZWnM/OKgGXmKaHHzHOeIGaevYXAzM8hoZd5a5G5BOpBYslK/S+i7hSk9gupY5TLqGfR96Ci3/35dEi2CvJhS5Hhaq7ZKm3Ygg+3KAseMvLKbITtKln8We8QlKfqCe6ZIhDbHYLW1f55u7PIyumgwVayIgq7XUi8ewP1w1BXwioOq7Qq6ySt07rKi3WUZc0mLeo0Uld0LdSVy1LNvnI5zElYhheLbSyTeYmyXN41gbMMDX/Scg5KrWXouGrLMObuLcOgH3G5rOLW5nL5CHywuqB1LHYXbdhZXvSC2F70pC990cvO/qInuAKjlzwYjB7lKYzeETqMHpRIjF5ztRi9INMY3GN7DM7xRAa3+Caj92Qqo/f4LqO3RDKj52Q2o/dkOkP2GD6jt4RCowelRqMXvSiNnvXkNHpYJjWoJ7cavcrRGr3ix2v0Lk9s9I7AbPSYUG30oCe30cO3kBv9LBK70WsL9Ca8D+NHZS6p2hDT74aZP7tL3WVHPU0+7PQmjVdJ/8T5md7MDukzBr3R1mnzG2rAIjjUmNFwtCGu4sRJ/Fl3x+TqXjd5qZ7zblOct+p5s29tV3sNRw2OExdp98KyGKefhYrTbJIiz4KqTcMoV8/n6h7bVedRGxZFXmZN0X1h7J/vVpe7NVdv2+5j+/Re93dsfj+0+8PDdaVmxrke5+Q455eLDTnTgERyru+cgHLOEX+WcylKMeccctWc85w755wn/XjOdR23Bp3rJ+GDRQcuZDHp6NPOpgMSYtQBTV+qA9LOrAMaXNcBKQ+wA6o82QEhIe2AosR2QM4Vd0BCpjtEkM07RI/nO0SMDzwgKBMeEOQTD4iJjAf0ZMgDgjLloYMM5gExofOAohR6QNKL9ICuJ+oBZZn1wKAce0CWoz0g44d7QJjnPSAkAB9QE4oPKHoiH1C+hfmA00jQB+QWqU+3H0fd4ydYBVB9uiugOhlSj+6Ky1XY7+vR9+yE3bYedUgUrpL+EIP66Au1sQ85YXEfcs4IP/oUV37CJFX2cf3m+ome8JVHqboRz4I7Lz//bJrda23ZwDMcNchPEaXs57T3s1B+1FVQdVkW61Bt38naMq7KqCrKtm6qLAnTtl4mP9eVmuXnepyT/JxfLrb8TAMS+bm+cwL5OUf8yc+lKJWfc8hVfs5z7vJznvQjP9d13Fp+rp+ED5YfuJDF8qNPO8sPSIjlBzR9yQ9IO8sPaHDlB6Q8yA+o8uQHhITyA4oS+QE5V/kBCZn8EEG2/BA9nvwQMb78gKBMfkCQLz8gJpIf0JPJDwjK5IcOMuQHxITyA4pS+QFJL/IDup7kB5Rl8gODcvkBWY78gIwf+QFhnvyAkEB+QE0oP6DoSX5A+RbyA04jkR+Qs8lPdK9uyxwFj0GoLsNSF2Oh/T5n+VHP3uoe/47u7txnuptEp+r5XfartfSF2uSHnLDIDzlnlB99ii0/cfZp5Scooiwv7Xt+XsPvgYV9ukMG81EEk+TM3T79LDSfdRAl3ePbkyjdpOoR7mmQh3WiLt0KmnVU1uUy8xmWaQaf4SAn7elfIjb1jKYlzjO8TwLk6Qv+hOeUk/JOX3G1nX7IHXb6MT+qM6zg1qQzvOkf7Dn6KhZjzmzUWXLm82LGmQd9Gc686ww48wBXb+YdD3QzT/LcZl4Ros08JxGbecuVa+bzMqtBNTbUoBhPaVCJTzTzmsxn5jU+zsxLIpmZx2QsM6/JTIaoMUBmXhJqzDwnpZh5z4vDzKOeEGaelQmMXpPzy7zJsZd5ww+8zKs8dZlXBOQyTwm9ZZ7zhC3z7C2kZX4OCbPMW4uMRT0dq9tdkwzbYubXVJ2MJX8Mu+03q6h/yhbaXRNeDrE9QWu2Shuw4MMtuoKHjLQyG2G7Shp+2jviBEGhbrRsd5Xquf179drsd992L+2fFmGZHny2lqAMYiU4rEurkn4YaksbFGnblGkeJ21QbuIqy6o8KddJu67KdbXw2iptyWZ30Q53EpjZi8m2GNiRqIz2Lgt8ZtbyJzXzsNRsZj1XvZmNuzvOLOBHdLRV3dp2tI/OByuPaT2LvYeMOMsPXRIbEJ32pUH0GZxdiE5xhYguerAiOs5TI7on9CM6LJEkuupqSnRJpkvmLtuZzFmeOJmbfHuiuzKFort8j6KbIpmiszKjorsyrbJ2GW5FN4WCRYellkWXvagWnffkW/QJZNJl6srNi65z9Iuu+XEwus8TMbonsDE6KlQyOuzJy+gT3ELO6LNJDI2uLtO0ZHheV0hcqxYG91HaaVqYqf9BTZscYtM0cr02V7MNWoTNNm60NnKYq25R0D1R/fpt/xNdx5alZZmFC+5D3ey2h5f2+bl+378q17Gw2+zowd2U74WheqVZ7nYahu5WJt0OqErd12i9idRVbU0bZmkabpow3FRtmyzb5aSv2Qxv+vFO8jZ/Qdn0hkMSe5sXv20F+DaP+dM3rSzlt3nQ1d/m8+4ANy/4Ebh5dd/emuDmZ1R/PVc3EIt/f/upvhab9rDeb08/V6zu/vbz+LR7/fK8VTqw//lFgdiX7eux3W+qtfoMf/mhJr8cn9ov/7w9/st7/eWf/vavf8Qq0sHZ3eq4f28tNyzr34QH44IWIxxdcVY4Q0rMcIa2L4cznMIZ4gwtrsQZkh4ozlDnWZwhKMQ4Q1micYasK8cZUjKPs4TZIGfp8kTOEuWTnCEsMzlDmI9yhqhI5QxdGcsZwjKXs4cZMGeICmXOUJbSnCHtxeYMfU84ZziDTOeMYTnPGfIcnzPk/ACd4QQ8oTMEBURnqAqNzlD2hHSGM9xC6QynkzCdIbvA6dTNoNQlgdkqKVZxb3Bg11vZ30k8WaXqWXHY6YLxIbY7idMLtkGdddIiddZ5I9XR02yrC5PPskPuZbf+fvfXb7/uts3dKlP32gqiBVD3Vr0/H35U+6Nta9z1wIHnojApuzOweO40DHkuX9dhnlTVOm7KNl7X66Ct6yApsmKTh0GTLeO5yXLNMjc51AnlRi8e2+O0hoTiJu+mQOFGHX8AN45K7W3UcmW30ai7uI2G/WDbZDW3drbJx+ODiY1ay2JdgwFnWMMVsanhrC9Ow3VnScMZLqLhmgc/w2EeneGWUM1wVAJmuOhqZbgiYzK6yRYyOsnDMbrHdzHclJEYbvI1DPdEEIaTMgPDTRl/GZsM+cI9IXrhqNS7cNULdeG0J+XCcRlwUU25beEyh7VwyY9o4TYPs3BL4Fg4KCQsHPWkVzh+C7jCZ5KYFS4u4KrgPg4ew7ijKPIW6Mqi1M2yopX6X5rDbWWKq7prPVUjG67jVH/OfT09Kkz90+ph2BHUPyQMrtUmVaYhC1KZRo0+BQf5NJV+lgfhTWkqyII0i+1Xbq73u8Phbfdm2Tx2PmxgqbDM8jRW6MdyqWEawlS8TtatuhlWXtVJFedVWyVFq3bD5c2mzeqoWQZTo+WaWWp0oBNKXV42NknNChKQGr2HAo66VPxh1DUppahLyRWiLoPuDHUZ9YNQo5UQBPVv+2/V6/bP6rjdvarP+WF7bL9Wzcv29W61qZ4P7V/qQv399o/q2A6/8Jt6IuTL8/An/tPx+HaY/pk/+mB8METhlSxmKDDujFCoISYoFPUFUKjtzE8owsUn1PJATyjLgydUErITSkrQCfVcyQk1ZOBEFdncRAV52ETV+NSEijJoQkU+M6GaCJlQUEZMqCgDJkORwUuoJsQllJTSEmp6gSUU9sRKKC1DJVyUkxLqckAJdfxwEirzMAmVBJSEckJIQklPjITSt0AkdB4JIaHeIkAK4g6QYrXfqb+DF9jvpJ6hFz2G0SpROtRvZprd5UvdRj24D9TljepGYOdtUwZAAiu18RE9YsEjetBIR2CMC0dhUKpbf1+/5Z6vP1R7cX5Ux/VTuz+Mfun8jf7ufO1Md9rq8PX05Xf9aU390vVre7hSpjvux/b79nLU6aei9e799Xi3Cn67e9nu97v96ae81/fn59/udm/t69AeXRfZz/UTo//e//t5xXcrtfym3ajtSMevp7/FqhW/VAd1bc91V5Pa0pTGC276dVB/Sa8OFjg6HTSwURQEWcK9yddpGKJRlUTrpG7U1YV1lKdhkVZpntRRXKRJWFTxQjS6LNX8Q/XlMCcwGl4sNhdN5iVYdHnXBFQ0NPxB0TkoZaKh44pEw5g7EQ2DfoDosgqCh/79oL5KfbDQ5SPwwSiE1rGYhLRhZxDSC2IO0pO+MEgvO1OQnuBCkF7ywEB6lIdAekdIQHpQAkB6zZV/9IIMf3CPTT84x4Mf3OKzj96ToY/e45OP3hKBj56TcY/ek2EP2WNQj94SQo8elDKPXvSCPHrWE/HoYRnwoJ6cd/QqB3f0ih/a0bs82NE7AtbRY0LU0YOeSEcP3wJ09LNIOEev2TFHbePpdgOVqzhcJfCxeMl9kN1H4aN6Jp7a7ROj3UDoEAPmaOu0UQ41YIEcaszIONoQF3HiHN9ESuHGHHHUL/2nQRy1VhviqL0/QVak9v0/fz8oUVJ7Cl7V/9NaLGdy7EA6SRlnCff+UadhSDpRGYRhEidZGBVVmSfNutgkQR4UubpmrYjzjjz3z0qvztseqrdt9xlWt7Tpt7u9qx+WDw/zFZtlZ360E/BMX0i286CMhHvm769AfaYpf/gz60oNaJpzpaDptLsITef9wNB8Tbf2ofln5oOZyLCcxVpENZzRiAyJ7Ygs+yIk8gTOkkSWuKBEBj24Etnm8RKZEyoT2ZVgExl1NScyJKMnY5YtUMYqD6KMSb5HkVkZS5FZvk6RSRFSkVWZVZFZGVnZsgy5IpNCwCK7Usciw144i6x7Ui2yL8MtQ1ZuXGScQ11kzI94kXkefJE5gX+RTSGDkV1PGkb2b4Fi5MkkNkZGFxBZcR+rezel3f2d0sC036l/pOEqSuF+p+CcSfPhujsDkVHLtUmZZc4CZpZpo5tRs1w+y0N1AZm+BWq0oWi0++g/jZ6p5Vv1LC6LNFUblV6rF3Wtzd3JlYZbJW8UmH0d/kNT/dE+/+NF3cx4csjux6vaqrH6dfe8+9ZdvXN3Oe6sZkWcFRnz8rmkH4ZqFiZhlTZx2dZxugk2dblp0nSzrrK4rtRNnsJlajZerVnMxkc6adn1hWNL2TwhUbLx+ygQsmvGn46NmlIZu6ZcVew66S5i11k/GjZey60lbPy5+GAFI5ayWMDQvLN+wYhYvmDVl3rBuLN4wQpXu2DMg3TBLk+5YEooXLAp0S0YdJUtGJGpFplkixZZ5GkWmeNLFkzKFAsm+YIFcyK9gkWZXMGkTK1MSYZYwZxQq2BTKlUw6kWpYNmTUMG2TKeIpFymYJijUjDkR6RgmqdRMCWQKNgTKhRsehIo2L6FPsETSeQJBhepU6iusotWYbEKelHCV9kpmVIHqAvt0MasSN2Z/P6UURfahban/6Gl2sTJMGPRJsOkUZrQHFeZsgw+6O9//gvt1O6noiyWKNOuqWzApA4ZbCnM4ixO1MWLvHsznaaxLq3rvKw2YRKVaR7EeZsVYRwHZduUTRJH0UJdOi3VAkung9xMqXuZ+Jx0nRZJ0um9kiBSV/DoR31OTEddxVmNuiEGGHVjnqzotIKbM9HpTf9oIdJWsRyHpqPuLjSbl5PQLOhNg2ZddwiaBdgGNOv44J9Zkik/s4oUfWY5kffM37zq20F9z6mfd/VhdhO02W7g8wMnJ99Hu2+pD/3wr4fDU/WXSnX/58AOabg1PvDMfmvd0pi2A0oC1pnVhKIzqwkwR1+Xunnen2rPt3oXxwTDeSeFhDNf2ul7b31a2/g7MWdt4/n+t/rysj2yPq9SswGfs3nyrC2c36gfqZkt0hfSzLJCn9FqHmhm1mSpzKzhCWRmVabFwDf218Pr+4v6Quv+KO8hhfPBkwrM/JXfPreH4+61Vd9lrqubsAlnlTdxl9nSReQyay3Qlvw+yLs9Pqm6XxHUFnWNm3rOW/IYxP0en34fkHZPoyDv75udqv+u7nzUHWLY49NMV2mFFni4zVjgkJlXpiPq9/C0e2nfqm/dZpTugqfLbV7jt5+/79uqUU/jbnbrw+/qR7QHdfhh+6c6NE0Vouj7d9SmnvnVb+qX/tPs31Frte3fSRJ1TVq04BZGw66dt58WXrkcp17b7slvYV6omyRxN/AM09BY4jJr46ZN4zgKqnrT7UNqyjBaN+pBbUkcbtQCFlz3Nl6vGVrGRzppy/WlY5PLPCFxl/E7KcCXa8afwIyaUoa5plwt5jrpDjLXWT8qM14LQTPeb4U9/nx8sNMQS1mMNWjeWWxgRMw2sOrLbmDcGXBghas4MOaBcmCX5zkwJUQd2JTIDgy67uSBEfWLAuMhk2zoIYs87SFzfPKBSZn7wCQff2BOtJMHFmUMBJOynTymJGMnD8zNCUcdpDb5L0Ym2FS/+DDvutAQjHrxIVj2hESwLZMiIinnIhjmmBEM+YEjmObpEUwJdvLAntCRYNPTTh7YvoUowRNJWAkGF9hSeh/lj1G4CrNV0O/Sme/kUbaU3Efpo7p+jHrgGjpErWfQO/VP04fvoKXagMkwY1Emw6SRmtCc7k3X5wr14HTcNJ00XaApKYvPdrPs/+//B48urzxw3QQA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"19f2284d68e37b7618fba7197a0ca02d\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0446:385F4D8:53DEE674", "cache-control": "public, max-age=60, s-maxage=60", "date": "Mon, 04 Aug 2014 01:48:37 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407120437"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/forks?per_page=100"}, "recorded_at": "2014-08-04T01:48:37"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 38e8d1f3d..ee21d557b 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -159,6 +159,18 @@ def test_events(self): for event in events: assert isinstance(event, github3.events.Event) + def test_forks(self): + """Test that a user can iterate over the forks of a repository.""" + cassette_name = self.cassette_name('forks') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + forks = list(repository.forks()) + + assert len(forks) > 0 + for fork in forks: + assert isinstance(fork, github3.repos.Repository) + def test_ignore(self): """Test that a user can ignore the notifications on a repository.""" self.basic_login() diff --git a/tests/test_repos.py b/tests/test_repos.py index 37c4ba531..e755712cf 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -549,21 +549,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_forks(self): - self.response('repo', _iter=True) - self.get(self.api + 'forks') - self.conf = {'params': {'per_page': 100}} - - r = next(self.repo.iter_forks()) - assert isinstance(r, repos.Repository) - self.mock_assertions() - - self.conf['params']['sort'] = 'newest' - forks_params = self.conf['params'].copy() - forks_params.pop('per_page') - next(self.repo.iter_forks(**forks_params)) - self.mock_assertions() - def test_iter_hooks(self): self.response('hook', _iter=True) self.get(self.api + 'hooks') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 9648e6216..161503fac 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -337,3 +337,14 @@ def test_events(self): params={'per_page': 100}, headers={} ) + + def test_forks(self): + """Test the ability to iterate over forks of a repository.""" + i = self.instance.forks() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('forks'), + params={'per_page': 100}, + headers={} + ) From ee6bd1ee051c36e21c171d3d635f63336d96c0d9 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 4 Aug 2014 20:30:15 -0500 Subject: [PATCH 338/972] Rename Repository#iter_hooks to Repository#hooks --- HISTORY.rst | 1 + github3/repos/repo.py | 26 +++++++++++------------ tests/cassettes/Repository_hooks.json | 1 + tests/integration/test_repos_repo.py | 13 ++++++++++++ tests/test_repos.py | 12 ----------- tests/unit/test_repos_repo.py | 30 +++++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 25 deletions(-) create mode 100644 tests/cassettes/Repository_hooks.json diff --git a/HISTORY.rst b/HISTORY.rst index 2898096d0..9c77e1852 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -76,6 +76,7 @@ Old name New name ``Repository#iter_contributor_statistics`` ``Repository#contributor_statistics`` ``Repository#iter_contributors`` ``Repository#contributors`` ``Repository#iter_forks`` ``Repository#forks`` +``Repository#iter_hooks`` ``Repository#hooks`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index dba34f6fa..167940734 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1222,6 +1222,19 @@ def hook(self, id_num): json = self._json(self._get(url), 200) return Hook(json, self) if json else None + @requires_auth + def hooks(self, number=-1, etag=None): + r"""Iterate over hooks registered on this repository. + + :param int number: (optional), number of hoks to return. Default: -1 + returns all hooks + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Hook `\ s + """ + url = self._build_url('hooks', base_url=self._api) + return self._iter(int(number), url, Hook, etag=etag) + @requires_auth def ignore(self): """Ignore notifications from this repository for the user. @@ -1310,19 +1323,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - @requires_auth - def iter_hooks(self, number=-1, etag=None): - r"""Iterate over hooks registered on this repository. - - :param int number: (optional), number of hoks to return. Default: -1 - returns all hooks - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Hook `\ s - """ - url = self._build_url('hooks', base_url=self._api) - return self._iter(int(number), url, Hook, etag=etag) - def iter_issues(self, milestone=None, state=None, diff --git a/tests/cassettes/Repository_hooks.json b/tests/cassettes/Repository_hooks.json new file mode 100644 index 000000000..07b18b73c --- /dev/null +++ b/tests/cassettes/Repository_hooks.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YzW7rNhCFX8XQto5pWXZiCyhuu2q7u4vbTTcGJVEWEUkUSMqGI+Tdeyjq1xe1k7BAYNgK5+PhcIaaYePxxAuDF3/94vtLr6QF80LvxHVWR8GqunpLL63z/Nj9Q/FTQc9c1mqzJbNR4lIy6YWNl4sTL8GYDgXFTLPZrvfBeunRM9VUHmuZY1ymdaVCQuxDtbLUWjEZi1KzUq9iUZCaWONv5183oJ1kxzBYL/a3+2D3nOwP6WGzY8+Hjf+yjxjzk0NA4/QFBjdzVbybx8IxmSI3gjNd5DcSrbTW5GZwKvJcXEC5XdSjichgaTzdUnh5+iIFlg0ROmPwLZb0bhzFlf68qNaqwQYrfeSJ4ShsmGTJp4V1dpBl4uO9IZJVogXWkYolrzQX5ecFzqxBE/JES/5Gv0aDtQLESPu8lNYK1uyMWP28uTVrSCX5mcZX4xrJYsbPcPYXkTf2IOprZdL6bwSFcT3X7EiTwqRpSnPF3pdeO73GoPbBEln50eifHwMJG3YVE36/6kyUi5xHksrrIhVywZHTMqUxYnVxwTGzQLgu/uD6zzpa/P79r3MAgRj3Oii5m7mt82fJOJdjSA/25C4C6QkAJL2yqxPH2DcEn10+xUh1GglJtXh0aNwXOAM1ZPrTxJJmtHAS3gIAyoRw82QLAIgrVbMPhfb9hbccRfr8KesiskfeR7LmPtoSoJUqnPMlY04eHCAN6U9lpEMZZ27YntEQ+63dbXpykmrsgYlyETlx8KIkLaQhKqP2PaSPruoM1TBmUMlSZ6mGMUC1dNzvVqaBDEi8BDW23klnzyBN59GclqeantyoAwS7bl7VJ/r2sIi5nzsjBUhTwUke1e6H3MgxSm3tgHx3c+mIGaFtQXK/zHnggElh07qgKPijuuA+sUPMwv5/wJo4vUWb34/LmMdyDaMh45lsD/2O7uLd7tTvdZJmnKNrF5xComeQ5peK6sycXJiqopK5iO4QpIkoiq3VatVkjLZldcGkYwZbAlBUxhmqRhedTc9A1VNQ3VbrqZGZoHrPBU2cfDtAALTb6KLVEqYxVqFPdRLYAqbEgudMaVG6nbEjZcouheYpjz/SsdxPtxmo+aZ4GbMlzfMlolbzmCOOUWubXUTBydw8ZAlYBq4JbKeSM4S0k9cls4yG2E4zlgyNSHKkGg3EZu1vntbBkx/88A/hbh/ugn+wkrpKZmO2T+v909r/4e9C/yUMdmZMVatsgrFDtj/Wfrg94M8MwQnYhSC+4QoCn7j2+Km/n7QU5tYAhkplo+Fvo1n4H/cjnVmcI5Zugv7jc55vX0uPTSE1EwWrUCZ0Ny3DKoPquoKnE7RfiYjVCj0wMSvjbxi63wW7WUEQi7rEfviH56V3oRq1K16904d9ITE0fWZqqo42Tb1Qy9p0lXgyHgOThxf+yoeOzzZtHf15j1OSSym6+6ISSYp+v2Jlxx5l2MZReaGxmYwwukfZ3SoSltI610dbPEN2gqo/F5WJHCYL6DYXE+ZCq+uU7QpMVPWrMeeF/Y4GumT6gl6xV2MkTMuU3lf7938BSR9EynITAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e2d160b418e2b200cb96b13ac9d2292d\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4988", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E4C:D73D7:53E032BD", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Tue, 05 Aug 2014 01:26:21 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407204490"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-05T01:26:21"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/hooks?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA8VVXW+bMBT9L36cIICBEHjay6RpnbSvaJpaVcgBA14AU3+Asmr/fdfAMtKumiZRNS+Yy/W1c86959zcIy1qlKBKqU4mjkM6timZqvRhk/HGEbTj0pGsbEjPhJY4cKav/qY7ORXnR+ngGAcxRhZSVKp0pXKOKQY1WY6S6QALtaShcFVBSa4qmvNMQgLJFOshrISmFqI9bZVEyQ3qtKzQrYUy3hasRMn9TwvVBC4oqOx4K2HLPXzM4Yld10JSEaVh5++CFmqolKQ0J364QrBbdzlRNE+JghB2vcB2d7Yb7F0vCeIkdK/hNhlcbpmDbXdre/7e2yW+n7jxNRRaAXLf8+MoXg3yqdwS8ilyhnygh/+BGjHAN9OCplKa5vIMMrxVwE2qTp2BtOCigeifboHeG4Zh813XJ1XxdsNFaZrR6b254yAbigpq0H81/wwtL0Qq3u1dnLjhSPw6pGIcrThH/ljugtQxciZVCZjpf46QBZNU1zA1d3qeSCk1TUEcGqATSOn0oWYZLBraHKi4mDmU84awFhgzXEv4mqClmEBU8SM1CS9OaWS74Tin2yQIVqLU20aBhyPzN1fRxrnektQ5dGZVdoK1qj7BmU9Jo+GOqQWFk2rBjpzWVFGz4ENbc5LDsuB1zYdxIY7zIyVdNx5RslGlS8jRZp7Zg+YY302Pzc2xaJcHbTXqtcGJNCnJzcEDUZkJLROhD3tGh8XdZ91eKj2i0HRGd0pBigKq8Lphbcn712BjrDbGBmVBXNIjPUGa/vLpa5Rt7977Vf+jkELu7968iwsZvf387arMP5o7CJ7rTKXGjpAXYT96VukJJ1l57CfgOZ7tYeM5eJeEa/kJCEMYRcGI/yoePtW7MPEpdO7TmrS5zAiYwdON+sjDETHwPyv0xsq9v1k5QB/aXrx3Y/DxJNiBRNz+AkvDPhM/CQAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ab59ab64e4086d1c8b1fc2377ea5f6f6\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4987", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E4C:D73E0:53E032BD", "cache-control": "private, max-age=60, s-maxage=60", "date": "Tue, 05 Aug 2014 01:26:21 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407204490"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/hooks?per_page=100"}, "recorded_at": "2014-08-05T01:26:21"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index ee21d557b..b3c3c2ab3 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -171,6 +171,19 @@ def test_forks(self): for fork in forks: assert isinstance(fork, github3.repos.Repository) + def test_hooks(self): + """Test that a user can iterate over the hooks of a repository.""" + self.basic_login() + cassette_name = self.cassette_name('hooks') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + hooks = list(repository.hooks()) + + assert len(hooks) > 0 + for hook in hooks: + assert isinstance(hook, github3.repos.hook.Hook) + def test_ignore(self): """Test that a user can ignore the notifications on a repository.""" self.basic_login() diff --git a/tests/test_repos.py b/tests/test_repos.py index e755712cf..d8e80cac0 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -549,18 +549,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_hooks(self): - self.response('hook', _iter=True) - self.get(self.api + 'hooks') - self.conf = {'params': {'per_page': 100}} - - self.assertRaises(github3.GitHubError, self.repo.iter_hooks) - - self.login() - h = next(self.repo.iter_hooks()) - assert isinstance(h, repos.hook.Hook) - self.mock_assertions() - def test_iter_issues(self): self.response('issue', _iter=True) self.get(self.api + 'issues') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 161503fac..12065c7b6 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -1,6 +1,8 @@ """Unit tests for Repositories.""" import datetime +import pytest +from github3 import GitHubError from github3.repos.repo import Repository from .helper import (UnitHelper, UnitIteratorHelper, create_url_helper) @@ -348,3 +350,31 @@ def test_forks(self): params={'per_page': 100}, headers={} ) + + def test_hooks(self): + """Test the ability to iterate over hooks of a repository.""" + i = self.instance.hooks() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('hooks'), + params={'per_page': 100}, + headers={} + ) + + +class TestRepositoryRequiresAuth(UnitHelper): + + """Unit test for regular Repository methods.""" + + described_class = Repository + example_data = repo_example_data + + def after_setup(self): + """Set-up the session to not be authenticated.""" + self.session.has_auth.return_value = False + + def test_hooks(self): + """Show that a user must be authenticated to list hooks.""" + with pytest.raises(GitHubError): + self.instance.hooks() From 4f8e2047cb2e5d8c3c9d4abb49e70610dccb6e6a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 4 Aug 2014 20:32:09 -0500 Subject: [PATCH 339/972] Rename parameter for consistency --- github3/repos/repo.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 167940734..e7f19e95b 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1209,16 +1209,16 @@ def git_commit(self, sha): return Commit(json, self) if json else None @requires_auth - def hook(self, id_num): + def hook(self, hook_id): """Get a single hook. - :param int id_num: (required), id of the hook + :param int hook_id: (required), id of the hook :returns: :class:`Hook ` if successful, otherwise None """ json = None - if int(id_num) > 0: - url = self._build_url('hooks', str(id_num), base_url=self._api) + if int(hook_id) > 0: + url = self._build_url('hooks', str(hook_id), base_url=self._api) json = self._json(self._get(url), 200) return Hook(json, self) if json else None From 49d16508701c313b2eef4c8faeddd78c735bb183 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 4 Aug 2014 20:41:05 -0500 Subject: [PATCH 340/972] Experiment with the default ReadTheDocs theme --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 0262cdbe8..3d1ec55c8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -96,7 +96,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'nature' +#html_theme = 'nature' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From 1d1cd6c05f6c2ec16a9d588c06e15e2b9dde0a86 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 4 Aug 2014 22:12:01 -0500 Subject: [PATCH 341/972] Rename Repository#iter_issues to Repository#issues --- HISTORY.rst | 1 + github3/repos/repo.py | 82 +++++++++---------- .../Repository_issues_ascending.json | 1 + tests/integration/test_repos_repo.py | 20 ++++- tests/test_repos.py | 21 ----- tests/unit/test_repos_repo.py | 11 +++ 6 files changed, 68 insertions(+), 68 deletions(-) create mode 100644 tests/cassettes/Repository_issues_ascending.json diff --git a/HISTORY.rst b/HISTORY.rst index 9c77e1852..56a2b9fff 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -77,6 +77,7 @@ Old name New name ``Repository#iter_contributors`` ``Repository#contributors`` ``Repository#iter_forks`` ``Repository#forks`` ``Repository#iter_hooks`` ``Repository#hooks`` +``Repository#iter_issues`` ``Repository#issues`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index e7f19e95b..9e3660675 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1287,6 +1287,43 @@ def issue(self, number): json = self._json(self._get(url), 200) return Issue(json, self) if json else None + def issues(self, milestone=None, state=None, assignee=None, mentioned=None, + labels=None, sort=None, direction=None, since=None, number=-1, + etag=None): + r"""Iterate over issues on this repo based upon parameters passed. + + .. versionchanged:: 0.9.0 + + The ``state`` parameter now accepts 'all' in addition to 'open' + and 'closed'. + + :param int milestone: (optional), 'none', or '*' + :param str state: (optional), accepted values: ('all', 'open', + 'closed') + :param str assignee: (optional), 'none', '*', or login name + :param str mentioned: (optional), user's login name + :param str labels: (optional), comma-separated list of labels, e.g. + 'bug,ui,@high' + :param sort: (optional), accepted values: + ('created', 'updated', 'comments', 'created') + :param str direction: (optional), accepted values: ('asc', 'desc') + :param since: (optional), Only issues after this date will + be returned. This can be a `datetime` or an `ISO8601` formatted + date string, e.g., 2012-05-20T23:10:27Z + :type since: datetime or string + :param int number: (optional), Number of issues to return. + By default all issues are returned + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Issue `\ s + """ + url = self._build_url('issues', base_url=self._api) + + params = repo_issue_params(milestone, state, assignee, mentioned, + labels, sort, direction, since) + + return self._iter(int(number), url, Issue, params, etag) + @requires_auth def key(self, id_num): """Get the specified deploy key. @@ -1323,51 +1360,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_issues(self, - milestone=None, - state=None, - assignee=None, - mentioned=None, - labels=None, - sort=None, - direction=None, - since=None, - number=-1, - etag=None): - r"""Iterate over issues on this repo based upon parameters passed. - - .. versionchanged:: 0.9.0 - - The ``state`` parameter now accepts 'all' in addition to 'open' - and 'closed'. - - :param int milestone: (optional), 'none', or '*' - :param str state: (optional), accepted values: ('all', 'open', - 'closed') - :param str assignee: (optional), 'none', '*', or login name - :param str mentioned: (optional), user's login name - :param str labels: (optional), comma-separated list of labels, e.g. - 'bug,ui,@high' - :param sort: (optional), accepted values: - ('created', 'updated', 'comments', 'created') - :param str direction: (optional), accepted values: ('asc', 'desc') - :param since: (optional), Only issues after this date will - be returned. This can be a `datetime` or an `ISO8601` formatted - date string, e.g., 2012-05-20T23:10:27Z - :type since: datetime or string - :param int number: (optional), Number of issues to return. - By default all issues are returned - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Issue `\ s - """ - url = self._build_url('issues', base_url=self._api) - - params = repo_issue_params(milestone, state, assignee, mentioned, - labels, sort, direction, since) - - return self._iter(int(number), url, Issue, params, etag) - def iter_issue_events(self, number=-1, etag=None): r"""Iterate over issue events on this repository. diff --git a/tests/cassettes/Repository_issues_ascending.json b/tests/cassettes/Repository_issues_ascending.json new file mode 100644 index 000000000..ffe690639 --- /dev/null +++ b/tests/cassettes/Repository_issues_ascending.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/betamax"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA6WY346rNhDGXyXittk4Idn8QapOq75AVZ32ojeRAQPWAqa2SZpF++79bEMgUU+yC9JqN0s8P38ez9gzNB6PvWC12qwPu/Vm7pW0YF7ghUzTgv7rzb2kzvNj+1TxtKAnLmvlb0g/RJxLJr2g8XKR8hLWw3FAmBn8zXK/Xs49eqKaymMtc4zLtK5UQIh7qBYp11kd1orJSJSalXoRiYLUxBl/O/3sg5bKlmGwXrTa7Nev23h/SA7+K9se/NVuHzK2ig9rGiU7GNzNVfF2HgfHZIrcCc50kd9JdNKsyd3gROS5OINyv6hnE5GrpXGzpfAyHUmBZUOEzhh8iyV9GEdxpb8uylo1xPw58thwFDZMsvjLwlo7yDLx8dEQySphgXWoIskrzUX5dYE31qAJmdKSv9NxNFgrQIy0r0uxVrBmJ8Tq182dWUMqyU80uhjXSBYxfoKzRyLv7EHUl8ok9J8ICuN6rtmRxoVJ04Tmin3MPTu9xiD7YI6s/Gz0D86AmF23FLP9Ovvrtz9mvODabssM3/K0ZPFMlPlllgg5qy46E+WLZP/UDAG3gDY8fruKeJi01u83eThQYjBP9uLH9shJWEPMG7uMhxjjhuB3m0ERkpuGQlItnh0TD6TdUBoy/NeEjma0GC/ZWoOSCTHBe9YaFK5UzT4Vww/WayGKdFlS1kXoDrbP5MYDrjOHSqpsVLLxXrsSGtKduqGkZZRNYHaAhrhPdm9pOl6kMQYjzEU4HoL7j1hCQ1RG3fWij5N0GaQB3BAlS6aJNIArUcspu2sFGsKVhytNY6PHK+wApGm9mNMyrWk6AXklYI/NlZvS96fFyIPs6BHgmTJM8rCeeG71EKPR3f7I5Qlu7Bk90dYTj6uUR+seFCV25QVur/EKW/ub2J7KNPF4zzX/Py8+Hqy7AzSkP2Dd8d1+M9qj7fndTUCafoK2vJ/iXtsfKNL8VFGdmfMI81RUstFyW3vShBRl0WKxaDJGbQFcMDklQZ05OFRGGYq70QqbDoAipaDaVtSJERijws4Fjcf780oAze3baJXOfBhOFVrI8dKs9RBX8BwloygnnJk9YgguheYJjz7TSTxIqBtK803xMmJzmudzRKfmEUe8olkz24aakE1wjDPHAtCyu94hZwjd8Z6WzAEa4hq/SDL0BfGRapT0/nK1flnuXlbb78t14OPH/xtrqKv4ZszGjPEP35f7YLkN/K0ZU9UqG2C6IatDsD4E/soMwdHWBhw+4Y3AD9rtrsw3HTyslMp6q196m+D/XlS0NlGOyLkL7k/Odrq/XZ7YQWEmClbhem9fdmBl7WuThdRJvED3aZbB3zFgtd2tb27wSNQlPP96mHtnqlFT4sIcPOvufaB/t82UmY6qo8s/L9CyNs0cnvTJPXh45m/82m25nqmF4y1QwaUU7VuaEvmHLrtiZYvuROxcy6a8ABaD770A33SKnf6YJbTO9dFVtFBcUKVtQ1oyfUbL1TFBGtYHraLtx3/YfmXzpxIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f02da883c63df37ba10256a6669662b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:533C:8E69F0:53E04B62", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 29 Jul 2014 08:06:26 GMT", "date": "Tue, 05 Aug 2014 03:11:30 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407211890"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/betamax"}, "recorded_at": "2014-08-05T03:11:31"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/betamax/issues?per_page=100&direction=asc"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1dbW/jNhL+K4T7YRM0sV78EttIUmx7RRvcFbfYZu9wtylsWaJjXWTJ1UuyabD72+8ZkpIlS3bsWN7dFg6w2EQih8MhOfPMkBy9f2okodcYNKZxPI8GmmbN3eatG0+TcdMOZlrI50GkRe7tzLp3wyQy29qYx9bM+qC5UZTwSGs1ThqeNeZeNNyVkibpPGm+NeMfQRcczLgf10A5pQSi/L4ekpIOCE7jmbfU95wEn5Od6zQGRq/VaplG56ThJ7MxDxuD1kkjdmOPY2ReOw77W2AnJAkrdgMfTSYRFXpqeMGt66NMvhG8JppmW++19JOGdW/FVrg8NuJhpEaaqNmBH6MBMeiJJit/d39hgtptqGgQ2YZttHutTtfp9Sd9s8O7fdM46405N5x+y7InZ8TduhlFjRVn1FYiROFJ4HnBA6gsd6o4dcsNaVnNjIrr376QCmo+aUE85ZAtukTT9daNnpurFUyJWk8a/Td0HaITYWxC7mzNmKoHth58cPQkVq8gmIwjO3TnNHu2l1qhNqgF4a3lu3+Iubg9NdSOQEQolq17KGqh9iZruELUstqTNg/de8t+JNGE3ObuPYT9QpJL9UExfpzTsn1HSxSid2M+tJwZLdOJ5UX8Y6ouG4P3L1e+UlNqP/pTy7c5qQa0RWoTLRcf2oEXQFc0eu1xl48bH092btT1v52HwW3IIxoK1ajrs9zDtFFu2Xobjf4mJnVM3AVzThrMiqCzfI4nfuJ5J42Z6/EoDvzsQaaxB1BidshR2xlaMSiYutE61XunpnGtm4NWZ2C0/guKydxZLtM/NdrXpjHomIPOGZWxvSBSZGSz48B5HJICB93zxGO2B8YubhqxFd2deliSN43LG//cc8tvTjGyM/na9edJzGjgUdWecvtuHHy4aayoc5or4biRNfa4c5mpeIaOz7G2xq7nxo/sAbaY3duhhn/nmud+bm6klZdsJBGUHrOYDRnxOOYMkz8IHe6w8eOX5PH1m6svIRr+Yc5tzEo25lOgoyD5IgPEP1izOdZOKgEt8S4x08XEjvkHWjApelgztW78G38xBbcd9GJtDEfxQVlQy+9lFxTb4PiUvWe/bbIkbsIbf6nw1syXSVAPyk8rulFVSPVlF0WroHUXAqkHWnf3Bq27Wu3QuqvVAK1JdgJa981+T+8ZC2jdXUDrn4PgjmzYAU4f4HTJLdEOcDofCTjAaYGxl+H0HpAtUCuQbWvQbg063WpkaxinZv/a6AH6Dtqd55Ht/PLc4d7lucWmIZ8ApKbhnoeHh2bIAXSn1nwunH+FNbV7zTztnOqaE9iRNiVFCaz7kmrnmnV5ronmx+HWLPRexkKxmmRhDuwMLP9FUf73fBKEKXD+jKBVtTv3rMexZd99/pZp5sBf+B0hw/gztv56EvOQfanGwyDxncrWK1D6S9bWZnWW1hAWAcB+YSbmn6RzJP8sL0DxvCxX+bjc4wWo//RpM3aLWufTJ4Lim9Vc6ijqLWB8sb8ZcF9aGKXyhZ5ntSq6v3hXIYManAGDQrH1eAOGuTd3AKRr9wdAswaHQMhPBMZb7X6/0zMXHoGB3/PR9hmPp4HD4oDdcgRSEVVahDwo3BWxSRjM2DVU2Q9WxJnrAyoiDHdwJQ6Redo+ObgSWwf2D5H5OiLziJI7j1BzKiaf/pn6LLpudyZ8x2h8uyoar/yR7kDvDgwRaV+OxrdP9fZpSyefxexCB2/ks9iBwy8T30WsmVCj+JO5Ee00jBE2f2RR7Hoew64BCyYMe3FsFkQxwwKE9kYVCld77ji0QhdKG1sUbx6h2X12ZAGWuTHFQ0mZByEUOucyyG35j2kxodc9T2x0HTfZ1YQ9Bgl7CBH4p99C0UbEUCOeyqbuOJsGD+xKFZo9yiIngrcoDhM7TgD/0YXIxY6HBRLB4FxTnonj3mdbBlP3durhX8yy307ngnu4YefzkF+eR3PLz8rf0XN3Ng9CCIreXLJiAZ8KLGQpihBmg0dUJIRiYhdkBRkb71PLp4oUCcxR4KjyTQUHxaoBqjZXVn221WOIUvWL4afcL4dPVvRqgpZpNIeTIKhkYHWvxvQq4l5KuiyNJb6qecOepJ8OXZlEtUDXN71emq6zup/Hx5kgqyeIu0qOEMVwSOpnOKyWNDF1cVH9jiIMr4bDmeX6w+GrleytG+Udpxg1vbLdo4VUsGRpBWpYsTKoML9U2iFMfLHYSVcxaxzc8xPSFa+gpiLOF2td1BcKLe1wM53fzXQi3vhN7G7U8nPjv4WyMIQ6IkWoN3XdjGhw//l3aACpWmWvxIjPL49ex8zjliwuNQ8zm2ffnkC7SbWL3VsBkgVNaEChYbOSXWZ5UFfJ7VTIoxh6wkEjiis1ZekmzgRoZhObFEJXP2qpmmrSzux3mQK8SJ9/kxXIZOY6mDxEk2I9YMRxbcLtUPIRmPAc9hCEdxhApWrnl/+GQpZvrLSjMCv3Lg0bUx4ATIUco+/lmafUBHkuFL18k3oIw3RTVMz+tODD1LXRf+sOZuYobeeYxQ8BC8RpDMtjVngrzvZEi8mxLkSlZg15IMMl07iIq+QLTRLfpqayQZabyBSBwDBfY2xgAGeIkjyQLSVeYdEyn4YMq+xpSeaK4Ak7cpu8eaKKSU2oTLVcC2qLUi6HY1DHtEGzMKwUnFk0Sw9TbpvsP7C1thg6PPcZtlhzy2f/plLFqlIzWDKTG9lbdVYu06Zf2Gb/fH395vt1Gq5S9+2oU/dttnEU4d28kvG92uxdbG+EozNiRVYBNWEhq1/RSCzNy20A1K+FZitAxsLAEUYp45Rd+qzOiuCMxAs6nelfUbeC88rx34Xd4hCVW9ynqJZMyZby2qXXS4O0zeRaZQhrHDFaz3lkWp6gdwQCngf5t7xepC0YK8LSat7oNFf1AvhCowZXOUMulWvopTp0vfNRNcMr1lhZpGWxCp1YLdM1mnQXca9TDeu7vf28Ey4R7UEAMdN/Y9cXaBmUVjtIz+kmWiV0hG9lqCAn0m1UAB3xTKIhYb81A7LCts1ctGrquqq5KjRx8DxLnuePuNAgdyRIvcAHk3hd4SKBxPPgvOk65MlKhI79SRykx+6FE7GHKXw5cl0R86JwlvDrUjyOmFWTXZOTl6J5gdvlwdz8mVCqDb9Q8qAAJw4iIrSCOdv8X5Q5IhQFk82p06TK+2uyX2VszHs8yZon9wlug/TLomPhDaDViPvYf4GLArfNxxbOo3AuHqgPPhiNQ8sm1xSelzy7Su1FOLSKQnMrhKMGBwQBp88Wf9uLU1EdotnVDK4NppHS/XOA2KL+kgBaHFre3mZQ5ZcB0bK4KoxdpviqbVyVyVwKca6xdxUd30az1wLuiAcRtlhEJCrAYb4T5cFLFclKrFK0fUUCZPdWI7AdRbQDkqKWq4a3YpKUEVFZRi+b2X8yVFMe2QOiye8H1RRLf3a9rQ+KC8DwIIJ42VGK3P2RAlaowgjCNqsTROlthjQO+dfbCCRDLrfwWNpJCYPFflx23uSoFIk9HuBIFn5g8wVqo12sIwrEpi/opdhgEk8FAjyWpN0JSzds2MUFW2y/KJJZW7Q1cqQqbbbXQQ18BZsbxEbNmxm0z7Byj4Ha23BzQaEJ7FEj6F5tY4HKt9lCoMYLWwPqz9Tk3vibBPxLEyyL8dP0oW0eAtL1hfVzEz9FyNlKUCH0Z1eGcjXWLw7hE5VWhlgTyv6xi/SUatRU8VKa9bSA6EcUTaNkKKtGUC4rRWK5eMG0o06BRrN62CWPJBdqNVvXcKFK3IsbgkWaeSwiWSvwkNcKRD5MmVIdAE/x0aqoQ6530uKysJlz/EmJwIvfQbmU3FkxaCeyi6S5oBz35LRWuqtfjZ+60SqhQoXpkg728/O7clqLjQo15ssTOa2wag4XwP5Fat8VMTFtMwqFGbtyssqJKljaZI7uPD9TllO7txmcKQCZ5uL88yhVq6O/IHRRZ61Ho5E6pYQHy1hGlaEz1hsgGpQq6L4cplGv6HUJ1eQaWYNtFIVldIPH6AExSP82hDmqtKq4BvGgYFMcMK/lhyhVHupQ/OBgR7E7NYOg94SCfjtSwenaj3McrwZYqoMbgqyRstEjCbNG1QZ3tC3QUkycslEBb4nJkz5MUVc2ozYBX5mayA4EjTL4NSI7D/VROwBTvalavhkiQxm1olNMtniS+SuKUHGNr8NmqJAu8wI6U8/p3fP4bLlwpSlbgLxjYo8oZ9SXTdsWGE31OO1EZjOIBIxvrqUXIbVcfWpiS6yWq73OGqo+ELO7Ks0SfMOcBX7DHBaTV/ieo/1BuFElhhMW96vYbCARK71cMpTrV1pacxndqSFei+9UmcploRCeKrK8EF6K8RS5LVBebqpujvNUpdrmdg7xgXQOC2wG/UYF7Ddq7nSoX2WBMCmlVj0Xv8yzvV38AunaL36BZg0Xv4T8xMWvLlKVtfq5i1/m2eLi11s0FcbimCguFLB3b6/YzIqRqoeyOB0SRBwSRBxudf3pb3XVnawBl5qQiKFNyRrM3kA3Vlx8KpVZn4ZsfimvF9P1LXEOQ1wnEJkwSTOVkzjksk2m2RvS5Jw9I5eGTDxEVjMfG6FMXHhFJoh//fCWOYH/KhbBmFvfBZAQB9STEJjJwnmP3xNky/OodWBDYiY7OhExG/nnbjk9dUMmttWb2MxUXHzT6hniOP4VaFue+wcVxFmMK5ZeHUAkT545EWr3ijmuI65jre1jZUZNEpAba+3OpO2Y7Z7DdaT9QWqyM707blvtfq/T6rQnhtVvG71Ox8pJRdZUYrk8j+NLReRcw++F1BG45ZFdGkBWTgv9eGC/SCtBNyEgDMejTkJyIjUk3RvmzTc8RHqN6IQOpqg7B7hkb4vbCXDlcN0gcBLUK2yHidMrOH0uz+mQUOY8QKIvake5YXTWJeSUOBItgRaBraods7XTKTdW24+TkhQFHT+HZKRMxAzZTBiL4NtaGaTZBdYupO2lU0G2lrmrXIjPIfGRFPloG5nXkOzA7NeHefv7w7z9PWDefi2Yl+QnMG+/2+50W8h5lmYWNvvFZAcI3C1SC+MykkhZIr0+0kuHpAaHdMOUFuqQ1GD7bMVfW1KDPcDf1qnRu6YkZK2BIfKQVdz771AWXpRBIl5df/bevzLZ6WmfhQWn+Fcd8ZSWXpttael7sy0gXXs8BTRriKcI+ZFtaZl6zzwzYE+yrPVI1Zwm0vnFRd543MC9Ep8JINT6kxv/wxrTHKHU2Ifs9VumyT9kr39RvvlD9vr0Wx4VJhw4L5/9Hmtzi+z1O5kTRGGXk7qLFDFm69o4G7TNgW6uMCco07k2jEHrbNDZKI3MO1wRkZ8/IC00U3pJpYkWmbygmX5OxvS2MvCA4LtIjVnlvCHaIfVaGihYsl/bNJ4pSEreLT8hsDHj72VluR9PH3KBL7uO7+NaTKlRnyk19mdKjT2YUqMWU0ryk6a0ret6P29KkbE6NaXpMVEn4BEF6nCpKcEtq0cEj2wvQcIK7FzQmSim7HDZwiZ0OQqZHWgvg9rrtc46Z/jGzIs+DiMrV34cxrCc3tl4rLf0ltnqcd4761pG+8yxbKfTObOouxtYvTy36z+uky+5lZ+WVXy5VV0mscsHYRa0dvoazIJMfbmrczTzX5HBSG79HZgFqW0/ArOouf0XYBZ16/HH8rx8KesJ5VBtPXv0uRMTztjqJGxIHK3r5LC1+886YzLRmAhB39CncsTXPoYUZ75pDNhNQx0E0p6UBvp406jOJkQZz5AZjfLKsCCJ8bmUE9pboGuaY7qSiRusdHG1lJ86F5EtWN/0qMRpHAQePj4Wa3N8RkYze89td/wEZyR6nVAHLtdT/MbsrbDpm4tCHNndqOvP8qJwBWABHQPamAUVK96MiecC1iuljpyC/wcuQfXJSm4AAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"68c8e96cb3fa06d1842114b73da40e3b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:533C:8E6A24:53E04B62", "cache-control": "public, max-age=60, s-maxage=60", "date": "Tue, 05 Aug 2014 03:11:31 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407211890"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/betamax/issues?per_page=100&direction=asc"}, "recorded_at": "2014-08-05T03:11:31"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index b3c3c2ab3..8631e82d4 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -195,13 +195,29 @@ def test_ignore(self): subscription = repository.ignore() assert subscription.ignored is True - def test_iter_issues_accepts_state_all(self): + def test_issues_sorts_ascendingly(self): + """Test that issues will be returned in ascending order.""" + cassette_name = self.cassette_name('issues_ascending') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'betamax') + assert repository is not None + issues = list(repository.issues(direction='asc')) + + assert len(issues) > 0 + last_issue = None + for issue in issues: + assert isinstance(issue, github3.issues.Issue) + if last_issue: + assert last_issue.number < issue.number + last_issue = issue + + def test_issues_accepts_state_all(self): """Test that the state parameter accets 'all'.""" cassette_name = self.cassette_name('issues_state_all') with self.recorder.use_cassette(cassette_name): repository = self.gh.repository('sigmavirus24', 'betamax') assert repository is not None - for issue in repository.iter_issues(state='all'): + for issue in repository.issues(state='all'): assert issue.state in ('open', 'closed') def test_iter_languages(self): diff --git a/tests/test_repos.py b/tests/test_repos.py index d8e80cac0..5f8d530fe 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -549,27 +549,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_issues(self): - self.response('issue', _iter=True) - self.get(self.api + 'issues') - params = {'per_page': 100} - self.conf = {'params': params} - - i = next(self.repo.iter_issues()) - assert isinstance(i, github3.issues.Issue) - self.mock_assertions() - - params['milestone'] = 'none' - next(self.repo.iter_issues('none')) - self.mock_assertions() - - params['state'] = 'open' - - request_params = params.copy() - request_params.pop('per_page') - next(self.repo.iter_issues(**request_params)) - self.mock_assertions() - def test_iter_issue_events(self): self.response('issue_event', _iter=True) self.get(self.api + 'issues/events') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 12065c7b6..e36a64a5d 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -362,6 +362,17 @@ def test_hooks(self): headers={} ) + def test_issues(self): + """Test the ability to iterate over a repository's issues.""" + i = self.instance.issues() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('issues'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From 5b6613630332271871665a57bc8d0d6a37195fcd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 5 Aug 2014 22:11:16 -0500 Subject: [PATCH 342/972] Rename Repository#iter_issue_events --- HISTORY.rst | 1 + github3/repos/repo.py | 26 ++++++++++---------- tests/cassettes/Repository_issue_events.json | 1 + tests/integration/test_repos_repo.py | 11 +++++++++ tests/test_repos.py | 9 ------- tests/unit/test_repos_repo.py | 11 +++++++++ 6 files changed, 37 insertions(+), 22 deletions(-) create mode 100644 tests/cassettes/Repository_issue_events.json diff --git a/HISTORY.rst b/HISTORY.rst index 56a2b9fff..9cd9c7610 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -78,6 +78,7 @@ Old name New name ``Repository#iter_forks`` ``Repository#forks`` ``Repository#iter_hooks`` ``Repository#hooks`` ``Repository#iter_issues`` ``Repository#issues`` +``Repository#iter_issue_events`` ``Repository#issue_events`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 9e3660675..bff4e2a33 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1287,6 +1287,19 @@ def issue(self, number): json = self._json(self._get(url), 200) return Issue(json, self) if json else None + def issue_events(self, number=-1, etag=None): + r"""Iterate over issue events on this repository. + + :param int number: (optional), number of events to return. Default: -1 + returns all available events + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`IssueEvent `\ s + """ + url = self._build_url('issues', 'events', base_url=self._api) + return self._iter(int(number), url, IssueEvent, etag=etag) + def issues(self, milestone=None, state=None, assignee=None, mentioned=None, labels=None, sort=None, direction=None, since=None, number=-1, etag=None): @@ -1360,19 +1373,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_issue_events(self, number=-1, etag=None): - r"""Iterate over issue events on this repository. - - :param int number: (optional), number of events to return. Default: -1 - returns all available events - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of - :class:`IssueEvent `\ s - """ - url = self._build_url('issues', 'events', base_url=self._api) - return self._iter(int(number), url, IssueEvent, etag=etag) - @requires_auth def iter_keys(self, number=-1, etag=None): r"""Iterate over deploy keys on this repository. diff --git a/tests/cassettes/Repository_issue_events.json b/tests/cassettes/Repository_issue_events.json new file mode 100644 index 000000000..18cecaafd --- /dev/null +++ b/tests/cassettes/Repository_issue_events.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTW/jNhCG/4qhax3TsmzHFrDY7antbQ/ppReDkiiLiCQKJGXDEfLf+1KU9eFF7STsJUgUzsOXw5nRjBqPJ14YPPvLZ9+feyUtmBd6R66zOgoW1cWbe2md54fuH4ofC3rislarNZmsEueSSS9svFwceQnGeCkoZpvVerkLlnOPnqim8lDLHOsyrSsVEmIfqoWl1orJWJSalXoRi4LUxBp/P31bgXaUHcNgvdhf74LNNtnt0/1qw7b7lf+8ixjzk31A4/QZBjd7Vbzbx8KxmSI3gjNd5DcSrbTW5GZxKvJcnEG5PdSjjUhvaTzdUnh5/CIFlg0ROmPwLY70bhzFlf68qNaqwQUrfeCJ4ShcmGTJp4V1dpBl4uO9IZJVogXWkYolrzQX5ecFTqxBE/JIS/5Gv0aDtQLESPu8lNYK1uyEWP28uTVrSCX5icYX4xrJYsZPcPYXkTf2IOpLZdL6bwSFcT3X7ECTwqRpSnPF3udeu73GovbBHFn50eifloGE9beKDX9edCbKWc4jSeVllgo548hpmdIYsTo7o8zMEK6zP7j+s45mv//86xRAINa99kruZm7r/EkyTuUY0oM7uYtAegIASa/s4sQx9g3Bzy6fYqQ6jYSkWjwqGvcFTkANGf9pYkkzWjgJbwEAZUK4ebIFAMSVqtmHQvv+wVuOItf8KesisiXvI1lzH20J0EoV6nzJmJMHe0hDrlUZ6VDGmRv2ymiI/a29bXp0kmrsgYlyETlx8KIkLaQhKqP2PaQPruoM1TAmUMlSZ6mG0UO1dLzvVqaB9Ei8BDWu3knnlUGazqM5LY81PbpRewhu3byqj/TtYRNzP3cGCpCmg5M8qt2L3MAxSm3vgHx3c+mAGaBtQ3K/zXnggFFj07qgKPijvuA+sUNMwv5/wJo4vUWbvx+3MY/lGkZDhppsi35Hd/FuV/WvOkkz7NGNC04hcWWQ5reK6sxULmxVUclcRHcI0kQUzdZisWgyRtu2umDSMYMtASgq4wxdo4vO5spA11NQ3XbrqZGZoHvPBU2cfNtDALTX6KLVEsYxVmFOdRLYAsbEgudMaVG61diBMmaXQvOUxx+ZWO6n2wTUfFe8jNmc5vkcUat5zBHH6LXNLaLhZG4esgQcA58J7KSSM4S0k9cls4yG2EkzlgyDSHKgGgPEaumvnpbBkx+8+Ptwsws3wT84SV0lkzXrp+Xuaem/+JvQfw6DjVlT1SobYeySzcsyCP1VuNyZJaiAXQjiN3yCwE989vhlvh+NFOarAQyVygbDH4NZ+B/fRzqzOEcs3QT9x/c83b6WHptCaiYKVqFN6L609KcMqssCnk4wfiUiVgvMwMScjL9h6X69DSYNQSzqEvfh77dz70w1ele8escPr41EP/SZrak62DT1Qi1rM1XiyVAGRg/P/JX3E58d2jr6do8qyaUU3feiEkmKeb9iZcceZNjBUXmhsRmtMLoH2d0pEpbSOtcH2zxDdoKuPxcVdJdMnzH2XcGGNu44rsfevf8LRSQt6T0TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"5c01dfdfc77c6fae14e7694342e70153\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E51:31D77BF:53E19CB6", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Wed, 06 Aug 2014 03:10:46 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407298246"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-06T03:10:47"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/issues/events?per_page=50"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"53428d8f4b2c25863e34b61e8f519e4f\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E51:31D77F3:53E19CB6", "cache-control": "public, max-age=60, s-maxage=60", "link": "; rel=\"next\", ; rel=\"last\"", "date": "Wed, 06 Aug 2014 03:10:47 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407298246"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/issues/events?per_page=50"}, "recorded_at": "2014-08-06T03:10:47"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 8631e82d4..494683f14 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -195,6 +195,17 @@ def test_ignore(self): subscription = repository.ignore() assert subscription.ignored is True + def test_issue_events(self): + """Test that a user can iterate over issue events in a repo.""" + cassette_name = self.cassette_name('issue_events') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + events = list(repository.issue_events(number=50)) + + for ev in events: + assert isinstance(ev, github3.issues.event.IssueEvent) + def test_issues_sorts_ascendingly(self): """Test that issues will be returned in ascending order.""" cassette_name = self.cassette_name('issues_ascending') diff --git a/tests/test_repos.py b/tests/test_repos.py index 5f8d530fe..4651416ce 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -549,15 +549,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_issue_events(self): - self.response('issue_event', _iter=True) - self.get(self.api + 'issues/events') - self.conf = {'params': {'per_page': 100}} - - e = next(self.repo.iter_issue_events()) - assert isinstance(e, github3.issues.event.IssueEvent) - self.mock_assertions() - def test_iter_keys(self): self.response('key', _iter=True) self.get(self.api + 'keys') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index e36a64a5d..4c454ce0d 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -362,6 +362,17 @@ def test_hooks(self): headers={} ) + def test_issue_events(self): + """Test the ability to iterate over a repository's issue events.""" + i = self.instance.issue_events() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('issues/events'), + params={'per_page': 100}, + headers={} + ) + def test_issues(self): """Test the ability to iterate over a repository's issues.""" i = self.instance.issues() From e77cde168f2b2dfb6fcf5bd668a746e49ce03302 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 6 Aug 2014 20:41:43 -0500 Subject: [PATCH 343/972] Rename Repository#iter_keys - Also test Repository#key while we are at it --- HISTORY.rst | 1 + github3/repos/repo.py | 26 +++++++++++----------- tests/cassettes/Repository_key.json | 1 + tests/cassettes/Repository_keys.json | 1 + tests/integration/test_repos_repo.py | 23 +++++++++++++++++++ tests/test_repos.py | 23 ------------------- tests/unit/test_repos_repo.py | 33 ++++++++++++++++++++++++++++ 7 files changed, 72 insertions(+), 36 deletions(-) create mode 100644 tests/cassettes/Repository_key.json create mode 100644 tests/cassettes/Repository_keys.json diff --git a/HISTORY.rst b/HISTORY.rst index 9cd9c7610..2c752a713 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -79,6 +79,7 @@ Old name New name ``Repository#iter_hooks`` ``Repository#hooks`` ``Repository#iter_issues`` ``Repository#issues`` ``Repository#iter_issue_events`` ``Repository#issue_events`` +``Repository#iter_keys`` ``Repository#keys`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index bff4e2a33..6f12de63e 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1350,6 +1350,19 @@ def key(self, id_num): json = self._json(self._get(url), 200) return Key(json, self) if json else None + @requires_auth + def keys(self, number=-1, etag=None): + r"""Iterate over deploy keys on this repository. + + :param int number: (optional), number of keys to return. Default: -1 + returns all available keys + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Key `\ s + """ + url = self._build_url('keys', base_url=self._api) + return self._iter(int(number), url, Key, etag=etag) + def label(self, name): """Get the label specified by ``name``. @@ -1373,19 +1386,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - @requires_auth - def iter_keys(self, number=-1, etag=None): - r"""Iterate over deploy keys on this repository. - - :param int number: (optional), number of keys to return. Default: -1 - returns all available keys - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Key `\ s - """ - url = self._build_url('keys', base_url=self._api) - return self._iter(int(number), url, Key, etag=etag) - def iter_labels(self, number=-1, etag=None): r"""Iterate over labels on this repository. diff --git a/tests/cassettes/Repository_key.json b/tests/cassettes/Repository_key.json new file mode 100644 index 000000000..3bab5450b --- /dev/null +++ b/tests/cassettes/Repository_key.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY/qNhSG/wrKtgwmZGAgUnXbVdvdXdxuukFO4hBrkjiyHRATzX/v6zifXBVmxt0gCD6PXx+f45zjxuOJFwYv/vrF95deSQvmhd6J66yOglV19ZZeWuf5sftD8VNBz1zWavNMZqPEpWTSCxsvFydegjEdCoqZZvO83gfrpUfPVFN5rGWOcZnWlQoJsQ/VylJrxWQsSs1KvYpFQWpijb+df92AdpIdw2C92H/eB9tdsj+kh82W7Q4b/2UfMeYnh4DG6QsMbuaqeDePhWMyRW4EZ7rIbyRaaa3JzeBU5Lm4gHK7qEcTkcHSeLql8PL0RQosGyJ0xuBbLOndOIor/XlRrVWDDVb6yBPDUdgwyZJPC+vsIMvEx3tDJKtEC6wjFUteaS7KzwucWYMm5ImW/I1+jQZrBYiR9nkprRWs2Rmx+nlza9aQSvIzja/GNZLFjJ/h7C8ib+xB1NfKpPXfCArjeq7ZkSaFSdOU5oq9L712eo1B7YMlsvKj0T8/BhI27Com/H7VmSgXOY8klddFKuSCI6dlSmPE6uKCY2aBcF38wfWfdbT4/ftf5wACMe51UHI3c1vnz5JxLseQHuzJXQTSEwBIemVXJ46xbwg+u3yKkeo0EpJq8ejQuC9wBmrI9KeJJc1o4SS8BQCUCeHmyRYAEFeqZh8K7fsLbzmK9PlT1kVkj7yPZM19tCVAK1U450vGnDw4QBrSn8pIhzLO3LA9oyH2W7vb9OQk1dgDE+UicuLgRUlaSENURu17SB9d1RmqYcygkqXOUg1jgGrpuN+tTAMZkHgJamy9k86eQZrOozktTzU9uVEHCHbdvKpP9O1hEXM/d0YKkKaCkzyq3Q+5kWOU2toB+e7m0hEzQtuC5H6Z88ABk8KmdUFR8Ed1wX1ih5iF/f+ANXF6iza/H5cxj+UaRkPGM9ke+h3dxbvdqd/rJM04R9cuOIVEzyDNLxXVmTm5MFVFJXMR3SFIE1EUW6vVqskYbcvqgknHDLYEoKiMM1SNLjqbnoGqp6C6rdZTIzNB9Z4Lmjj5doAAaLfRRaslTGOsQp/qJLAFTIkFz5nSonQ7Y0fKlF0KzVMef6RjuZ9uM1DzTfEyZkua50tEreYxRxyj1ja7iIKTuXnIErAMXBPYTiVnCGknr0tmGQ2xnWYsGRqR5Eg1GojN2t88rYMnP/jhH8LtPtwG/2AldZXMxjw/rfdPa/+Hvw39lzDYmjFVrbIJxg7Z/VgHoe+H240ZghOwC0F8wxUEPnHt8VN/P2kpzK0BDJXKRsPfRrPwP+5HOrM4RyzdBP3H5zzfvpYem0JqJgpWoUzoblqGVQbVdQVPJ2i/EhGrFXpgYlbG3zD08LwLZgVBLOoS++EfdkvvQjVqV7x6pw/7QmJo+szUVB1tmnqhlrXpKvFkPAYmDy/8lQ8dn23aOvrugFOSSym6+6ISSYp+v2Jlxx5l2MZReaGxmYwwukfZ3SoSltI610dbPEN2gqo/F5WJHCYL6DYXE+ZCq+uU7QpMVPWrMeeF/Y4GumT6gl6xV2MkTMuU3lf7938B6KoW/HITAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"4c90acbf3da7c96cc08f9464177f732d\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4958", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552C:1B8EB4D:53E2D8DA", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Thu, 07 Aug 2014 01:39:39 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407376821"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-07T01:39:39"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/keys/8820641"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA33RyXKbQBQF0F9JscUxMwHtGIRxIySEGAw7hmYIIFA3IMCVfw+u8tpvd1/duzqfRJ0TB0liaZFnXogGrsSBwLj6jXDyS9lP5c5bojFrxh6/oq5cFfXrrVy1lm8Zgff4HMITts0S0t7w1INcQK0eBathIM5xuLgISTcGionZa/5Mh6I/hn4Cuima4dBTJwmgsrVK5vTWyXLtUg+35M4pkppAO1uklwqpr14EkKB79O5Vz61yl6SL4RovaTdEhhlyYb85QNdJwxcfpRhfCybrb4+P7K5wPisbqspphTlJctUUwWzN9hu4x61hQqXxJh3VKCw3o+lI7cMThfCPXwEr1tl3VSVBF9Fhs6SzmKzQ6ddcswqHHC6xu9w8rNime/vrFkc39QQ5gIWVsKMCcvZpg5Lmw6wtN+rBoIXy5CrQEuYiWFIHgXry9cURcTLYrY14N8prWnfR455FdMoQL8SE2h2hGscBHygqGerXsh6rKX3N+o6aMETUzoSpb7R9MNZjC39020szRHVRw117RBP89x+XlqKP+QEAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"f763346b21698e4af4bb4a2eda1e49f2\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4957", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552C:1B8EB55:53E2D8DB", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Thu, 07 Aug 2014 01:30:50 GMT", "date": "Thu, 07 Aug 2014 01:39:39 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407376821"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/keys/8820641"}, "recorded_at": "2014-08-07T01:39:39"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/cassettes/Repository_keys.json b/tests/cassettes/Repository_keys.json new file mode 100644 index 000000000..5407a2ca4 --- /dev/null +++ b/tests/cassettes/Repository_keys.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY/qNhSG/wrKtgwmZGAgUnXbVdvdXdxuukFO4hBrkjiyHRATzX/v6zifXBVmxt0gCD6PXx+f45zjxuOJFwYv/vrF95deSQvmhd6J66yOglV19ZZeWuf5sftD8VNBz1zWavNMZqPEpWTSCxsvFydegjEdCoqZZvO83gfrpUfPVFN5rGWOcZnWlQoJsQ/VylJrxWQsSs1KvYpFQWpijb+df92AdpIdw2C92H/eB9tdsj+kh82W7Q4b/2UfMeYnh4DG6QsMbuaqeDePhWMyRW4EZ7rIbyRaaa3JzeBU5Lm4gHK7qEcTkcHSeLql8PL0RQosGyJ0xuBbLOndOIor/XlRrVWDDVb6yBPDUdgwyZJPC+vsIMvEx3tDJKtEC6wjFUteaS7KzwucWYMm5ImW/I1+jQZrBYiR9nkprRWs2Rmx+nlza9aQSvIzja/GNZLFjJ/h7C8ib+xB1NfKpPXfCArjeq7ZkSaFSdOU5oq9L712eo1B7YMlsvKj0T8/BhI27Com/H7VmSgXOY8klddFKuSCI6dlSmPE6uKCY2aBcF38wfWfdbT4/ftf5wACMe51UHI3c1vnz5JxLseQHuzJXQTSEwBIemVXJ46xbwg+u3yKkeo0EpJq8ejQuC9wBmrI9KeJJc1o4SS8BQCUCeHmyRYAEFeqZh8K7fsLbzmK9PlT1kVkj7yPZM19tCVAK1U450vGnDw4QBrSn8pIhzLO3LA9oyH2W7vb9OQk1dgDE+UicuLgRUlaSENURu17SB9d1RmqYcygkqXOUg1jgGrpuN+tTAMZkHgJamy9k86eQZrOozktTzU9uVEHCHbdvKpP9O1hEXM/d0YKkKaCkzyq3Q+5kWOU2toB+e7m0hEzQtuC5H6Z88ABk8KmdUFR8Ed1wX1ih5iF/f+ANXF6iza/H5cxj+UaRkPGM9ke+h3dxbvdqd/rJM04R9cuOIVEzyDNLxXVmTm5MFVFJXMR3SFIE1EUW6vVqskYbcvqgknHDLYEoKiMM1SNLjqbnoGqp6C6rdZTIzNB9Z4Lmjj5doAAaLfRRaslTGOsQp/qJLAFTIkFz5nSonQ7Y0fKlF0KzVMef6RjuZ9uM1DzTfEyZkua50tEreYxRxyj1ja7iIKTuXnIErAMXBPYTiVnCGknr0tmGQ2xnWYsGRqR5Eg1GojN2t88rYMnP/jhH8LtPtwG/2AldZXMxjw/rfdPa/+Hvw39lzDYmjFVrbIJxg7Z/VgHoe+H240ZghOwC0F8wxUEPnHt8VN/P2kpzK0BDJXKRsPfRrPwP+5HOrM4RyzdBP3H5zzfvpYem0JqJgpWoUzoblqGVQbVdQVPJ2i/EhGrFXpgYlbG3zD08LwLZgVBLOoS++EfdkvvQjVqV7x6pw/7QmJo+szUVB1tmnqhlrXpKvFkPAYmDy/8lQ8dn23aOvrugFOSSym6+6ISSYp+v2Jlxx5l2MZReaGxmYwwukfZ3SoSltI610dbPEN2gqo/F5WJHCYL6DYXE+ZCq+uU7QpMVPWrMeeF/Y4GumT6gl6xV2MkTMuU3lf7938B6KoW/HITAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"4c90acbf3da7c96cc08f9464177f732d\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4960", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E4E:2BA3F61:53E2D860", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 15:17:35 GMT", "date": "Thu, 07 Aug 2014 01:37:37 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407376821"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-07T01:37:37"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/keys?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA33RyXKbQBQF0F9JscUxMwHtGIRxIySEGAypLBiaIYBA3YAAV/49uCrrvN19de/q/Pwk6pw4SBJLizzzQjRwJQ4ExtV3hJNvyn4qd94SjVkz9vgVdeWqqF9v5aq1fMsIvMfnEJ6wbZaQ9oanHuQCavUoWA0DcY7DxUVIujFQTMxe82c6FP0x9BPQTdEMh546SQCVrVUyp7dOlmuXergld06R1ATa2SK9VEh99SKABN2jd696bpW7JF0M13hJuyEyzJAL+80Buk4avvgoxfhaMFl/e3xkd4XzWdlQVU4rzEmSq6YIZmu238A9bg0TKo036ahGYbkZTUdqH54ohD/8Clixzr6rKgm6iA6bJZ3FZIVOv+aaVTjkcInd5eZhxTbd22+3OLqpJ8gBLKyEHRWQs08blDQfZm25UQ8GLZQnV4GWMBfBkjoI1JOvL46Ik8FubcS7UV7Tuose9yyiU4Z4ISbU7gjVOA74QFHJUL+W9VhN6WvWd9SEIaJ2Jkz9Q9sHYz228L9ue2mGqC5quGuPaIJ/fv0F/p+dkPsBAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"bd1cbbfe8dea1e6c0cb86663f041577c\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4959", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E4E:2BA3F73:53E2D861", "cache-control": "private, max-age=60, s-maxage=60", "date": "Thu, 07 Aug 2014 01:37:37 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407376821"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/keys?per_page=100"}, "recorded_at": "2014-08-07T01:37:37"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 494683f14..f3349cdec 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -231,6 +231,29 @@ def test_issues_accepts_state_all(self): for issue in repository.issues(state='all'): assert issue.state in ('open', 'closed') + def test_key(self): + self.basic_login() + cassette_name = self.cassette_name('key') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + key = repository.key(8820641) + + assert isinstance(key, github3.users.Key) + + def test_keys(self): + """Test that the user can retrieve all deploy keys.""" + self.basic_login() + cassette_name = self.cassette_name('keys') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + keys = list(repository.keys()) + + assert len(keys) > 0 + for key in keys: + assert isinstance(key, github3.users.Key) + def test_iter_languages(self): """Test that a repository's languages can be retrieved.""" cassette_name = self.cassette_name('iter_languages') diff --git a/tests/test_repos.py b/tests/test_repos.py index 4651416ce..c880d17a8 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -528,18 +528,6 @@ def test_issue(self): assert isinstance(self.repo.issue(2), github3.issues.Issue) self.mock_assertions() - def test_key(self): - self.response('key') - self.get(self.api + 'keys/2') - - self.assertRaises(github3.GitHubError, self.repo.key, 2) - - self.login() - assert self.repo.key(-2) is None - self.not_called() - assert isinstance(self.repo.key(2), github3.users.Key) - self.mock_assertions() - def test_label(self): self.response('label') self.get(self.api + 'labels/name') @@ -549,17 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_keys(self): - self.response('key', _iter=True) - self.get(self.api + 'keys') - - self.assertRaises(github3.GitHubError, self.repo.iter_keys) - - self.login() - k = next(self.repo.iter_keys()) - assert isinstance(k, github3.users.Key) - self.mock_assertions() - def test_iter_labels(self): self.response('label', _iter=True) self.get(self.api + 'labels') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 4c454ce0d..4a545e44f 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -151,6 +151,18 @@ def test_asset(self): url, headers={'Accept': 'application/vnd.github.manifold-preview'} ) + def test_key(self): + """Test the ability to fetch a deploy key.""" + self.instance.key(10) + + self.session.get.assert_called_once_with(url_for('keys/10')) + + def test_key_requires_positive_id(self): + """Test that a positive key id is required.""" + self.instance.key(-10) + + assert self.session.get.called is False + def test_latest_pages_build(self): """Test retrieving the most recent pages build.""" url = self.example_data['url'] + '/pages/builds/latest' @@ -384,6 +396,17 @@ def test_issues(self): headers={} ) + def test_keys(self): + """Test the ability to iterate over a repository's keys.""" + i = self.instance.keys() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('keys'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): @@ -400,3 +423,13 @@ def test_hooks(self): """Show that a user must be authenticated to list hooks.""" with pytest.raises(GitHubError): self.instance.hooks() + + def test_key(self): + """Show that a user must be authenticated to fetch a key.""" + with pytest.raises(GitHubError): + self.instance.key(10) + + def test_keys(self): + """Show that a user must be authenticated to list keys.""" + with pytest.raises(GitHubError): + self.instance.keys() From cdf5e7b71d855a22da401cd6a8639996c70a1efe Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 7 Aug 2014 20:17:04 -0500 Subject: [PATCH 344/972] Rename Repository#iter_labels --- github3/repos/repo.py | 22 +++++++++++----------- tests/cassettes/Repository_labels.json | 1 + tests/integration/test_repos_repo.py | 12 ++++++++++++ tests/test_repos.py | 8 -------- tests/unit/test_repos_repo.py | 11 +++++++++++ 5 files changed, 35 insertions(+), 19 deletions(-) create mode 100644 tests/cassettes/Repository_labels.json diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 6f12de63e..37374b90d 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1376,17 +1376,7 @@ def label(self, name): json = self._json(self._get(url), 200) return Label(json, self) if json else None - @requires_auth - def latest_pages_build(self): - """Get the build information for the most recent Pages build. - - :returns: :class:`PagesBuild ` - """ - url = self._build_url('pages', 'builds', 'latest', base_url=self._api) - json = self._json(self._get(url), 200) - return PagesBuild(json) if json else None - - def iter_labels(self, number=-1, etag=None): + def labels(self, number=-1, etag=None): r"""Iterate over labels on this repository. :param int number: (optional), number of labels to return. Default: -1 @@ -1398,6 +1388,16 @@ def iter_labels(self, number=-1, etag=None): url = self._build_url('labels', base_url=self._api) return self._iter(int(number), url, Label, etag=etag) + @requires_auth + def latest_pages_build(self): + """Get the build information for the most recent Pages build. + + :returns: :class:`PagesBuild ` + """ + url = self._build_url('pages', 'builds', 'latest', base_url=self._api) + json = self._json(self._get(url), 200) + return PagesBuild(json) if json else None + def iter_languages(self, number=-1, etag=None): """Iterate over the programming languages used in the repository. diff --git a/tests/cassettes/Repository_labels.json b/tests/cassettes/Repository_labels.json new file mode 100644 index 000000000..cfb8ed909 --- /dev/null +++ b/tests/cassettes/Repository_labels.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YzW7rNhCFX8XQto5pWU5sCyhuu2q7u4vbTTcGJVEWEUkUSMqGI+Tdeyjq1xe1k7CbIFE4Hw+HM6MZNR5PvDDY+eud7y+9khbMC70T11kdBavq6i29tM7zY/cPxU8FPXNZq82WzFaJS8mkFzZeLk68BGO6FBSzzWa73gfrpUfPVFN5rGWOdZnWlQoJsQ/VylJrxWQsSs1KvYpFQWpijb+df92AdpIdw2C92N/ug+eXZH9ID5tn9nLY+Lt9xJifHAIapzsY3OxV8W4fC8dmitwIznSR30i00lqTm8WpyHNxAeX2UI82IoOl8XRL4eXpixRYNkTojMG3ONK7cRRX+vOiWqsGF6z0kSeGo3BhkiWfFtbZQZaJj/eGSFaJFlhHKpa80lyUnxc4swZNyBMt+Rv9Gg3WChAj7fNSWitYszNi9fPm1qwhleRnGl+NaySLGT/D2V9E3tiDqK+VSeu/ERTG9VyzI00Kk6YpzRV7X3rt9hqL2gdLZOVHo39eBhI23Co2/H7VmSgXOY8klddFKuSCI6dlSmPE6uKCMrNAuC7+4PrPOlr8/v2vcwCBWPc6KLmbua3zZ8k4l2NID+7kLgLpCQAkvbKrE8fYNwQ/u3yKkeo0EpJq8aho3Bc4AzVk+qeJJc1o4SS8BQCUCeHmyRYAEFeqZh8K7fsHbzmK9PlT1kVkS95HsuY+2hKglSrU+ZIxJw8OkIb0VRnpUMaZG7ZnNMT+1t42PTlJNfbARLmInDh4UZIW0hCVUfse0kdXdYZqGDOoZKmzVMMYoFo63ncr00AGJF6CGlfvpLNnkKbzaE7LU01PbtQBgls3r+oTfXvYxNzPnZECpOngJI9q9yI3coxS2zsg391cOmJGaNuQ3G9zHjhg0ti0LigK/qgvuE/sELOw/x+wJk5v0ebvx23MY7mG0ZCxJtui39FdvNtV/V4nacY9unHBKSR6Bml+qajOTOXCVhWVzEV0hyBNRNFsrVarJmO0basLJh0z2BKAojLO0DW66Gx6Brqeguq2W0+NzATdey5o4uTbAQKgvUYXrZYwjbEKc6qTwBYwJRY8Z0qL0q3GjpQpuxSapzz+yMRyP91moOab4mXMljTPl4hazWOOOEavbW4RDSdz85Al4Bj4TGAnlZwhpJ28LpllNMROmrFkGESSI9UYIDZrf/O0Dp784Id/CJ/34XPwD05SV8lszfZpvX9a735s1uHzS7ht11S1yiaYfsnaD7ebcLs2S1ABuxDEb/gEgZ/47PHTfD8ZKcxXAxgqlY2Gv41m4X98H+nM4hyxdBP0H9/zfPtaemwKqZkoWIU2ofvSMpwyqK4reDrB+JWIWK0wAxNzMv6GpYftSzBrCGJRl7gP/7Bbeheq0bvi1Tt92DcSw9BntqbqaNPUC7WszVSJJ2MZmDy88Fc+THx2aOvoLwdUSS6l6L4XlUhSzPsVKzv2KMMOjsoLjc1khdE9yu5OkbCU1rk+2uYZshN0/bmooLtk+oKxrwcb2rTj6I+9f/8X6a3U0j0TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"cdda77ad71abaca970c4445bd0810d9e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E4F:57BB490:53E424AC", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Thu, 07 Aug 2014 20:56:43 GMT", "date": "Fri, 08 Aug 2014 01:15:24 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407464124"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-08T01:15:24"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/labels?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA7WUy27DIBBFf8Vi6yhgJ6nbLJuHlF3bbdUFxhMHyQbEI01U5d9L6trQPTWrOUg+XGbs9y/kdIfW6GStMmuMqeLzltuTq+dM9liDkgYb3vb0zLUz5RIPu4u5uuKO1tAZvHWq44xaQDMkaA/+dTFispPaM/bzoNsshfMgzrTjTTAGMPrg4b4S+V4dGMulCMKIhISLokqV8G2/CbKhGD2kJiUUiZLtqLkG0W81mbyHpEq0EycqGPQgbCT8A6feNeBXooRbUBr8fPr25QdjXDynYSsbt8YzHCv2wKpEZ3h2bcg8FFPWomjKVN18oVznn/4Dzg80GtY7zu44G/DUX/L0SEiijBpoE43SWAYXWx0hkYuLXGnZajAm3CsXWQSn+6WMLOtUXgZ5LS+Rk0E2gH+Z3T2/5BvZ99xa/z1M/1ePsxiP7pJUDazQ7eMbOOzAndkFAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"3353df61c7c3ac3a89e6fee788d32dff\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E4F:57BB4C2:53E424AC", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 08 Aug 2014 01:15:24 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407464124"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/labels?per_page=100"}, "recorded_at": "2014-08-08T01:15:25"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index f3349cdec..b5b0fd8ba 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -254,6 +254,18 @@ def test_keys(self): for key in keys: assert isinstance(key, github3.users.Key) + def test_labels(self): + """Test that a user can retrieve a repository's labels.""" + cassette_name = self.cassette_name('labels') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + labels = list(repository.labels()) + + assert len(labels) > 0 + for label in labels: + assert isinstance(label, github3.issues.label.Label) + def test_iter_languages(self): """Test that a repository's languages can be retrieved.""" cassette_name = self.cassette_name('iter_languages') diff --git a/tests/test_repos.py b/tests/test_repos.py index c880d17a8..6e0823905 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,14 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_labels(self): - self.response('label', _iter=True) - self.get(self.api + 'labels') - - l = next(self.repo.iter_labels()) - assert isinstance(l, github3.issues.label.Label) - self.mock_assertions() - def test_iter_languages(self): #: repos/:login/:repo/languages is just a dictionary, so _iter=False self.response('language') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 4a545e44f..8e8888ca8 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -407,6 +407,17 @@ def test_keys(self): headers={} ) + def test_labels(self): + """Test the ability to iterate over a repository's labels.""" + i = self.instance.labels() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('labels'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From c31d1452a452897c3158b1599b85f0f795479729 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 7 Aug 2014 20:32:26 -0500 Subject: [PATCH 345/972] Add mention of Repository#iter_labels to HISTORY --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index 2c752a713..7625c623e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -80,6 +80,7 @@ Old name New name ``Repository#iter_issues`` ``Repository#issues`` ``Repository#iter_issue_events`` ``Repository#issue_events`` ``Repository#iter_keys`` ``Repository#keys`` +``Repository#iter_labels`` ``Repository#labels`` ========================================== ============================================== From c1a2ae2ea51a081dce302b5383526f5f7fa66079 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 7 Aug 2014 20:39:14 -0500 Subject: [PATCH 346/972] Rename Repository#iter_languages --- HISTORY.rst | 1 + github3/repos/repo.py | 22 +++++++++---------- ...nguages.json => Repository_languages.json} | 0 tests/integration/test_repos_repo.py | 6 ++--- tests/test_repos.py | 11 ---------- tests/unit/test_repos_repo.py | 11 ++++++++++ 6 files changed, 26 insertions(+), 25 deletions(-) rename tests/cassettes/{Repository_iter_languages.json => Repository_languages.json} (100%) diff --git a/HISTORY.rst b/HISTORY.rst index 7625c623e..a253896b3 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -81,6 +81,7 @@ Old name New name ``Repository#iter_issue_events`` ``Repository#issue_events`` ``Repository#iter_keys`` ``Repository#keys`` ``Repository#iter_labels`` ``Repository#labels`` +``Repository#iter_languages`` ``Repository#languages`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 37374b90d..58e9e8104 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1388,17 +1388,7 @@ def labels(self, number=-1, etag=None): url = self._build_url('labels', base_url=self._api) return self._iter(int(number), url, Label, etag=etag) - @requires_auth - def latest_pages_build(self): - """Get the build information for the most recent Pages build. - - :returns: :class:`PagesBuild ` - """ - url = self._build_url('pages', 'builds', 'latest', base_url=self._api) - json = self._json(self._get(url), 200) - return PagesBuild(json) if json else None - - def iter_languages(self, number=-1, etag=None): + def languages(self, number=-1, etag=None): """Iterate over the programming languages used in the repository. :param int number: (optional), number of languages to return. Default: @@ -1410,6 +1400,16 @@ def iter_languages(self, number=-1, etag=None): url = self._build_url('languages', base_url=self._api) return self._iter(int(number), url, tuple, etag=etag) + @requires_auth + def latest_pages_build(self): + """Get the build information for the most recent Pages build. + + :returns: :class:`PagesBuild ` + """ + url = self._build_url('pages', 'builds', 'latest', base_url=self._api) + json = self._json(self._get(url), 200) + return PagesBuild(json) if json else None + def iter_milestones(self, state=None, sort=None, direction=None, number=-1, etag=None): r"""Iterate over the milestones on this repository. diff --git a/tests/cassettes/Repository_iter_languages.json b/tests/cassettes/Repository_languages.json similarity index 100% rename from tests/cassettes/Repository_iter_languages.json rename to tests/cassettes/Repository_languages.json diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index b5b0fd8ba..e423a6d87 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -266,13 +266,13 @@ def test_labels(self): for label in labels: assert isinstance(label, github3.issues.label.Label) - def test_iter_languages(self): + def test_languages(self): """Test that a repository's languages can be retrieved.""" - cassette_name = self.cassette_name('iter_languages') + cassette_name = self.cassette_name('languages') with self.recorder.use_cassette(cassette_name): repository = self.gh.repository('sigmavirus24', 'github3.py') assert repository is not None - for l in repository.iter_languages(): + for l in repository.languages(): assert 'ETag' not in l assert 'Last-Modified' not in l assert isinstance(l, tuple) diff --git a/tests/test_repos.py b/tests/test_repos.py index 6e0823905..11660ab06 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,17 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_languages(self): - #: repos/:login/:repo/languages is just a dictionary, so _iter=False - self.response('language') - self.get(self.api + 'languages') - - l = next(self.repo.iter_languages()) - assert isinstance(l, tuple) - self.assertNotIn('ETag', l) - self.assertNotIn('Last-Modified', l) - self.mock_assertions() - def test_iter_milestones(self): self.response('milestone', _iter=True) self.get(self.api + 'milestones') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 8e8888ca8..5caedb288 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -418,6 +418,17 @@ def test_labels(self): headers={} ) + def test_languages(self): + """Test the ability to iterate over the languages used in a repo.""" + i = self.instance.languages() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('languages'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From ff15031290948f848ca797a884b175e3b7b0035e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 7 Aug 2014 20:50:16 -0500 Subject: [PATCH 347/972] Rename Repository#iter_milestones --- HISTORY.rst | 1 + github3/repos/repo.py | 58 +++++++++++----------- tests/cassettes/Repository_milestones.json | 1 + tests/integration/test_repos_repo.py | 30 +++++++---- tests/test_repos.py | 8 --- tests/unit/test_repos_repo.py | 23 +++++++++ 6 files changed, 75 insertions(+), 46 deletions(-) create mode 100644 tests/cassettes/Repository_milestones.json diff --git a/HISTORY.rst b/HISTORY.rst index a253896b3..be9212bc5 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -82,6 +82,7 @@ Old name New name ``Repository#iter_keys`` ``Repository#keys`` ``Repository#iter_labels`` ``Repository#labels`` ``Repository#iter_languages`` ``Repository#languages`` +``Repository#iter_milestones`` ``Repository#milestones`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 58e9e8104..95743ab9b 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,35 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_milestones(self, state=None, sort=None, direction=None, - number=-1, etag=None): - r"""Iterate over the milestones on this repository. - - :param str state: (optional), state of the milestones, accepted - values: ('open', 'closed') - :param str sort: (optional), how to sort the milestones, accepted - values: ('due_date', 'completeness') - :param str direction: (optional), direction to sort the milestones, - accepted values: ('asc', 'desc') - :param int number: (optional), number of milestones to return. - Default: -1 returns all milestones - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of - :class:`Milestone `\ s - """ - url = self._build_url('milestones', base_url=self._api) - accepted = {'state': ('open', 'closed'), - 'sort': ('due_date', 'completeness'), - 'direction': ('asc', 'desc')} - params = {'state': state, 'sort': sort, 'direction': direction} - for (k, v) in list(params.items()): - if not (v and (v in accepted[k])): # e.g., '' or None - del params[k] - if not params: - params = None - return self._iter(int(number), url, Milestone, params, etag) - def iter_network_events(self, number=-1, etag=None): r"""Iterate over events on a network of repositories. @@ -1671,6 +1642,35 @@ def milestone(self, number): json = self._json(self._get(url), 200) return Milestone(json, self) if json else None + def milestones(self, state=None, sort=None, direction=None, number=-1, + etag=None): + r"""Iterate over the milestones on this repository. + + :param str state: (optional), state of the milestones, accepted + values: ('open', 'closed') + :param str sort: (optional), how to sort the milestones, accepted + values: ('due_date', 'completeness') + :param str direction: (optional), direction to sort the milestones, + accepted values: ('asc', 'desc') + :param int number: (optional), number of milestones to return. + Default: -1 returns all milestones + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`Milestone `\ s + """ + url = self._build_url('milestones', base_url=self._api) + accepted = {'state': ('open', 'closed'), + 'sort': ('due_date', 'completeness'), + 'direction': ('asc', 'desc')} + params = {'state': state, 'sort': sort, 'direction': direction} + for (k, v) in list(params.items()): + if not (v and (v in accepted[k])): # e.g., '' or None + del params[k] + if not params: + params = None + return self._iter(int(number), url, Milestone, params, etag) + @requires_auth def pages(self): """Get information about this repository's pages site. diff --git a/tests/cassettes/Repository_milestones.json b/tests/cassettes/Repository_milestones.json new file mode 100644 index 000000000..4fae3ab90 --- /dev/null +++ b/tests/cassettes/Repository_milestones.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTW/jNhCG/4qhax3TspzYFrDY7antbQ/ppReDkiiLiCQKJGXDEfLf+1KU9eFFbSfsJUgUzsOXw5nRjBqPJ14YbPzlxvfnXkkL5oXegeusjoJFdfbmXlrn+b77h+KHgh65rNVqTSarxKlk0gsbLxcHXoIxXgqK2Wa1Xm6D5dyjR6qp3Ncyx7pM60qFhNiHamGptWIyFqVmpV7EoiA1scbfj99WoB1kxzBYL/bX2+D5Jdnu0t3qmb3sVv5mGzHmJ7uAxukGBld7Vbzbx8KxmSJXgjNd5FcSrbTW5GpxKvJcnEC5PtS9jUhvaTzdUnh5+CIFlg0ROmPwLY70YRzFlf68qNaqwQUrveeJ4ShcmGTJp4V1dpBl4uOjIZJVogXWkYolrzQX5ecFTqxBE/JAS/5Ov0aDtQLESPu8lNYK1uyIWP28uTVrSCX5kcZn4xrJYsaPcPYXkVf2IOpzZdL6bwSFcT3XbE+TwqRpSnPFPuZeu73GovbBHFn5aPRPy0DC+lvFhj/POhPlLOeRpPI8S4WcceS0TGmMWJ2dUGZmCNfZH1z/WUez33/+dQwgEOveeiU3M7d1/iQZp3IM6c6d3EQgPQGApDd2duIY+4bgZ5dPMVKdRkJSLe4VjdsCJ6CGjP80saQZLZyEtwCAMiHcPNkCAOJK1eyh0L598JajyCV/yrqIbMl7JGtuoy0BWqlCnS8Zc/JgD2nIpSojHco4c8NeGA2xv7W3TQ9OUo09MFEuIicOXpSkhTREZdS+h/TeVZ2hGsYEKlnqLNUweqiWjvfdyjSQHomXoMbVO+m8MEjTeTSn5aGmBzdqD8Gtm1f1gb7fbWJu585AAdJ0cJJHtXuRGzhGqe0dkO9uLh0wA7RtSG63OXccMGpsWhcUBb/XF9wmdohJ2P8PWBOn12jz9/025r5cw2jIUJNt0e/oLt7tqv5FJ2mGPbpxwSkkLgzS/FZRnZnKha0qKpmL6A5Bmoii2VosFk3GaNtWF0w6ZrAlAEVlnKFrdNHZXBjoegqq2249NTITdO+5oImTb3sIgPYaXbRawjjGKsypTgJbwJhY8JwpLUq3GjtQxuxSaJ7y+JGJ5Xa6TUDNd8XLmM1pns8RtZrHHHGMXtvcIhpO5uYhS8Ax8JnATio5Q0g7eV0yy2iInTRjyTCIJHuqMUCslv7qaRk8+cGrvwuft+Fz8A9OUlfJZM36abl9Wm5eV8vw+SVct2uqWmUjjF2yfV36ob8Jl1uzBBWwC0H8hk8Q+InPHr/M96ORwnw1gKFS2WD4YzAL/+P7SGcW54ilq6B/fM/j9WvpvimkZqJgFdqE7ktLf8qgOi/g6QTjVyJitcAMTMzJ+DuW7tYvwaQhiEVd4j783WbunahG74pX7/jhpZHohz6zNVV7m6ZeqGVtpko8GcrA6OGJv/F+4rNDW0d/2aFKcilF972oRJJi3q9Y2bEHGXZwVF5obEYrjO5BdneKhKW0zvXeNs+QnaDrz0UF3SXTJ4x9F7ChjTuOy7G3H/8CUGbCOz0TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"4de60f19e0ac52aea6f06e8fbedf8b95\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E4F:58319ED:53E42B51", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Thu, 07 Aug 2014 20:56:43 GMT", "date": "Fri, 08 Aug 2014 01:43:45 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407464124"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-08T01:43:45"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/milestones?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1WTY+bMBD9K8jnJOYzAaSq5963l1ZV5MCEWDIY+YNVivLfO4ZklZDdVqxy6CE3Mpn3PPM88+BnT6wSJCcHY1qdU8pavqq4OdjdqpA1VdBKTTWvatZxZXUY0/HfaNUeac0FaCMb0HRDFkSwHQi9fRAhHemQl5ckTzZhHKwXpLH1DhTJNwtiuBGApfurbOVjWgm6ULw1XDYYxUChgBmJyT0RsuIuet3JmTmM/TTyF4R1zDA1rX4I6rMkVoMqZGOgMYM6lo7gr92XENkqdeZwBZMiiNMoWZdpts/CBNZZGGzSHUBQZhEr9k6wvyrlDruVHhEHU4tJiVe3NeluL4WQr8gyber2ju8Pom9IPHJ85k31SRZE9lSaA6C22NLJCcW1mV/UgOpx/rTZ8tLxaLwbBeXsws44LOu1wYr6YcwHQrt7m6H5Bd6gkU2qijX8N3MTOZ8N0RpJhg2c3eGAQjR0OKvz4SOsp63iHSuOThoFBfAOxf4k5QSPjObYuvX9jkPhpOcGtqys3ZrumdBwQgFbaLZcawua5AEutJAaK7hE4mECjCNxmUgybDxmMIOx0A/ipR8ug/TFD/PYRw/5gTm2Lac5Eaa9BEkeR3kSuZzSwta5SGOFOC0e5ZFrZH6oR65vPRINMnROdvFItMuLRwbvOOS3QVhPKm+PqlmFzwqE08Yz0sOFdT+BafDk3uvQRnCMvZHo6axPZ8XX390bij6d9frr6R2B/kdnje6cFSP/cFa0zHQZBYNrJnmSfeCsqXNWdN9ok0f+nbP++gPf0g7HfwoAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ae0d61c2a0519fd6cccab22687aacaab\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:1E4F:5831A1A:53E42B51", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 08 Aug 2014 01:43:45 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407464124"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/milestones?per_page=100"}, "recorded_at": "2014-08-08T01:43:46"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index e423a6d87..ae35f273e 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -277,6 +277,27 @@ def test_languages(self): assert 'Last-Modified' not in l assert isinstance(l, tuple) + def test_milestone(self): + """Test the ability to retrieve a milestone on a repository.""" + cassette_name = self.cassette_name('milestone') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + milestone = repository.milestone(7) + assert isinstance(milestone, github3.issues.milestone.Milestone) + + def test_milestones(self): + """Test the ability to retrieve the milestones in a repository.""" + cassette_name = self.cassette_name('milestones') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + milestones = list(repository.milestones()) + + assert len(milestones) > 0 + for milestone in milestones: + assert isinstance(milestone, github3.issues.milestone.Milestone) + def test_iter_pulls_accepts_sort_and_direction(self): """Test that iter_pulls now takes a sort parameter.""" cassette_name = self.cassette_name('pull_requests_accept_sort') @@ -299,15 +320,6 @@ def test_iter_releases(self): for release in repository.iter_releases(): assert isinstance(release, github3.repos.release.Release) - def test_milestone(self): - """Test the ability to retrieve a milestone on a repository.""" - cassette_name = self.cassette_name('milestone') - with self.recorder.use_cassette(cassette_name): - repository = self.gh.repository('sigmavirus24', 'github3.py') - assert repository is not None - milestone = repository.milestone(7) - assert isinstance(milestone, github3.issues.milestone.Milestone) - def test_release(self): """Test the ability to retrieve a single release.""" cassette_name = self.cassette_name('release') diff --git a/tests/test_repos.py b/tests/test_repos.py index 11660ab06..3be98714d 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,14 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_milestones(self): - self.response('milestone', _iter=True) - self.get(self.api + 'milestones') - - m = next(self.repo.iter_milestones()) - assert isinstance(m, github3.issues.milestone.Milestone) - self.mock_assertions() - def test_iter_network_events(self): self.response('event', _iter=True) self.get(self.api.replace('repos', 'networks', 1) + 'events') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 5caedb288..a5d5409e0 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -169,6 +169,18 @@ def test_latest_pages_build(self): self.instance.latest_pages_build() self.session.get.assert_called_once_with(url) + def test_milestone(self): + """Test retrieving a specific milestone.""" + self.instance.milestone(20) + + self.session.get.assert_called_once_with(url_for('milestones/20')) + + def test_milestone_requires_positive_id(self): + """Test that a positive milestone id is required.""" + self.instance.milestone(-1) + + assert self.session.get.called is False + def test_pages(self): """Test retrieving information about a repository's page.""" url = self.example_data['url'] + '/pages' @@ -429,6 +441,17 @@ def test_languages(self): headers={} ) + def test_milestones(self): + """Test the ability to iterate over the milestones in a repo.""" + i = self.instance.milestones() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('milestones'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From dce55e4181c807cbfd0d7188d36fc9333479346d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 7 Aug 2014 21:33:17 -0500 Subject: [PATCH 348/972] Rename Repository#iter_network_events --- HISTORY.rst | 1 + github3/repos/repo.py | 26 +++++++++---------- .../cassettes/Repository_network_events.json | 1 + tests/integration/test_repos_repo.py | 12 +++++++++ tests/test_repos.py | 8 ------ tests/unit/test_repos_repo.py | 11 ++++++++ 6 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 tests/cassettes/Repository_network_events.json diff --git a/HISTORY.rst b/HISTORY.rst index be9212bc5..dc60ed283 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -83,6 +83,7 @@ Old name New name ``Repository#iter_labels`` ``Repository#labels`` ``Repository#iter_languages`` ``Repository#languages`` ``Repository#iter_milestones`` ``Repository#milestones`` +``Repository#iter_network_events`` ``Repository#network_events`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 95743ab9b..2d9aefef3 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,19 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_network_events(self, number=-1, etag=None): - r"""Iterate over events on a network of repositories. - - :param int number: (optional), number of events to return. Default: -1 - returns all available events - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Event `\ s - """ - base = self._api.replace('repos', 'networks', 1) - url = self._build_url('events', base_url=base) - return self._iter(int(number), url, Event, etag) - @requires_auth def iter_notifications(self, all=False, participating=False, since=None, number=-1, etag=None): @@ -1671,6 +1658,19 @@ def milestones(self, state=None, sort=None, direction=None, number=-1, params = None return self._iter(int(number), url, Milestone, params, etag) + def network_events(self, number=-1, etag=None): + r"""Iterate over events on a network of repositories. + + :param int number: (optional), number of events to return. Default: -1 + returns all available events + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Event `\ s + """ + base = self._api.replace('repos', 'networks', 1) + url = self._build_url('events', base_url=base) + return self._iter(int(number), url, Event, etag) + @requires_auth def pages(self): """Get information about this repository's pages site. diff --git a/tests/cassettes/Repository_network_events.json b/tests/cassettes/Repository_network_events.json new file mode 100644 index 000000000..11458d992 --- /dev/null +++ b/tests/cassettes/Repository_network_events.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTW/jNhCG/4qhax3TsuzYFrDY7antbQ/ppReDkiiLiCQKJGXDEfLf+1KU9eFF7STsJUgUzsOXw5nRjBqPJ14YbP3l1vfnXkkL5oXekeusjoJFdfHmXlrn+aH7h+LHgp64rNVqTSarxLlk0gsbLxdHXoIxXgqK2Wa1Xu6C5dyjJ6qpPNQyx7pM60qFhNiHamGptWIyFqVmpV7EoiA1scbfT99WoB1lxzBYL/bXu2DznOz26X61Yc/7lb/dRYz5yT6gcbqFwc1eFe/2sXBspsiN4EwX+Y1EK601uVmcijwXZ1BuD/VoI9JbGk+3FF4ev0iBZUOEzhh8iyO9G0dxpT8vqrVqcMFKH3hiOAoXJlnyaWGdHWSZ+HhviGSVaIF1pGLJK81F+XmBE2vQhDzSkr/Rr9FgrQAx0j4vpbWCNTshVj9vbs0aUkl+ovHFuEaymPETnP1F5I09iPpSmbT+G0FhXM81O9CkMGma0lyx97nXbq+xqH0wR1Z+NPqnZSBh/a1iw58XnYlylvNIUnmZpULOOHJapjRGrM7OKDMzhOvsD67/rKPZ7z//OgUQiHWvvZK7mds6f5KMUzmG9OBO7iKQngBA0iu7OHGMfUPws8unGKlOIyGpFo+Kxn2BE1BDxn+aWNKMFk7CWwBAmRBunmwBAHGlavah0L5/8JajyDV/yrqIbMn7SNbcR1sCtFKFOl8y5uTBHtKQa1VGOpRx5oa9Mhpif2tvmx6dpBp7YKJcRE4cvChJC2mIyqh9D+mDqzpDNYwJVLLUWaph9FAtHe+7lWkgPRIvQY2rd9J5ZZCm82hOy2NNj27UHoJbN6/qI3172MTcz52BAqTp4CSPavciN3CMUts7IN/dXDpgBmjbkNxvcx44YNTYtC4oCv6oL7hP7BCTsP8fsCZOb9Hm78dtzGO5htGQoSbbot/RXbzbVf2rTtIMe3TjglNIXBmk+a2iOjOVC1tVVDIX0R2CNBFFs7VYLJqM0batLph0zGBLAIrKOEPX6KKzuTLQ9RRUt916amQm6N5zQRMn3/YQAO01umi1hHGMVZhTnQS2gDGx4DlTWpRuNXagjNml0Dzl8UcmlvvpNgE13xUvYzaneT5H1Goec8Qxem1zi2g4mZuHLAHHwGcCO6nkDCHt5HXJLKMhdtKMJcMgkhyoxgCxWvqrp2Xw5Acv/j7c7MJN8A9OUlfJZM36abl7Wm5fVstw8xyu2zVVrbIRxi7ZvSz9cLMMVyuzBBWwC0H8hk8Q+InPHr/M96ORwnw1gKFS2WD4YzAL/+P7SGcW54ilm6D/+J6n29fSY1NIzUTBKrQJ3ZeW/pRBdVnA0wnGr0TEaoEZmJiT8Tcs3a+fg0lDEIu6xH34++3cO1ON3hWv3vHDayPRD31ma6oONk29UMvaTJV4MpSB0cMzf+X9xGeHto7+vEeV5FKK7ntRiSTFvF+xsmMPMuzgqLzQ2IxWGN2D7O4UCUtpneuDbZ4hO0HXn4sKukumzxj7rmBDG3cc12Pv3v8FBnzTJD0TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"4f7a3004d490272f6a229984f3ee9a9e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "54", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44B75:53E436AE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Thu, 07 Aug 2014 20:56:43 GMT", "date": "Fri, 08 Aug 2014 02:32:14 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-08T02:32:15"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d621789dd104f8958679e25e8d8421aa\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "53", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44BA7:53E436AE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Thu, 07 Aug 2014 18:50:22 GMT", "link": "; rel=\"next\"", "date": "Fri, 08 Aug 2014 02:32:14 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100"}, "recorded_at": "2014-08-08T02:32:15"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=2"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"94df33920f2de32af9b45d2a905e1382\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "52", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44BC7:53E436AE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 01 Aug 2014 06:41:09 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:14 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=2"}, "recorded_at": "2014-08-08T02:32:15"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=3"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"3279965ab3d80cafeb27f95ae595ee12\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "51", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44BEE:53E436AE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sun, 27 Jul 2014 20:01:21 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:14 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=3"}, "recorded_at": "2014-08-08T02:32:15"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=4"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c436b2b44345c72ff906059f604991e7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0fb37d3f2a5f57aaf1bc3072380c91d7\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "50", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44C0C:53E436AE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 23 Jul 2014 12:45:46 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:14 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=4"}, "recorded_at": "2014-08-08T02:32:15"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=5"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"fb2541631dcda033e3b7279e2b1f733b\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "49", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44C36:53E436AE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 19 Jul 2014 13:59:03 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:14 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=5"}, "recorded_at": "2014-08-08T02:32:15"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=6"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"3554656f714a3d1aac6442911a47b649\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "48", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44C5C:53E436AE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 05 Jul 2014 19:05:50 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:15 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=6"}, "recorded_at": "2014-08-08T02:32:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=7"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"3f84d3a7a17e8f03e2ad1f42e9e88079\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "47", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44D18:53E436AF", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 24 Jun 2014 06:43:05 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:15 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=7"}, "recorded_at": "2014-08-08T02:32:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=8"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"c7bb510908d833b037b6fad8d6f7a18a\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "46", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44D43:53E436AF", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 20 Jun 2014 13:58:19 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:15 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=8"}, "recorded_at": "2014-08-08T02:32:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=9"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "03d91026ad8428f4d9966d7434f9d82e", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"1e243ac773771693351e49d88f5980d9\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "45", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44D71:53E436AF", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 27 May 2014 13:46:02 GMT", "link": "; rel=\"next\", ; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:15 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=9"}, "recorded_at": "2014-08-08T02:32:16"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=10"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"e4b356fe306e57e0b9d3da5304206866\"", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "44", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:552F:6E44D9D:53E436AF", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Mon, 19 May 2014 07:31:42 GMT", "link": "; rel=\"first\", ; rel=\"prev\"", "date": "Fri, 08 Aug 2014 02:32:15 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407467727"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/networks/sigmavirus24/github3.py/events?per_page=100&page=10"}, "recorded_at": "2014-08-08T02:32:16"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index ae35f273e..c0fe8a561 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -298,6 +298,18 @@ def test_milestones(self): for milestone in milestones: assert isinstance(milestone, github3.issues.milestone.Milestone) + def test_network_events(self): + """Test that a user can retrieve the events of a repo's network.""" + cassette_name = self.cassette_name('network_events') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + events = list(repository.network_events()) + + assert len(events) > 0 + for event in events: + assert isinstance(event, github3.events.Event) + def test_iter_pulls_accepts_sort_and_direction(self): """Test that iter_pulls now takes a sort parameter.""" cassette_name = self.cassette_name('pull_requests_accept_sort') diff --git a/tests/test_repos.py b/tests/test_repos.py index 3be98714d..4e306a54d 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,14 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_network_events(self): - self.response('event', _iter=True) - self.get(self.api.replace('repos', 'networks', 1) + 'events') - - e = next(self.repo.iter_network_events()) - assert isinstance(e, github3.events.Event) - self.mock_assertions() - def test_iter_notifications(self): self.response('notification', _iter=True) self.get(self.api + 'notifications') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index a5d5409e0..61a7a4aa0 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -452,6 +452,17 @@ def test_milestones(self): headers={} ) + def test_network_events(self): + """Test the ability to iterate over the network events for a repo.""" + i = self.instance.network_events() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('events').replace('repos', 'networks'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From 88bc89afeff1c1eba2c82725d3fd0d5de32626a2 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 7 Aug 2014 21:36:57 -0500 Subject: [PATCH 349/972] Update other tests to match the current style --- tests/unit/test_repos_repo.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 61a7a4aa0..92d93c424 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -142,15 +142,19 @@ def test_asset(self): The Releases section of the API is still in Beta and uses custom headers """ - assert self.instance.asset(0) is None - assert self.session.get.call_count == 0 - self.instance.asset(1) - url = self.example_data['url'] + '/releases/assets/1' + self.session.get.assert_called_once_with( - url, headers={'Accept': 'application/vnd.github.manifold-preview'} + url_for('releases/assets/1'), + headers={'Accept': 'application/vnd.github.manifold-preview'} ) + def test_asset_requires_a_positive_id(self): + """Test that a positive asset id is required.""" + self.instance.asset(0) + + assert self.session.get.called is False + def test_key(self): """Test the ability to fetch a deploy key.""" self.instance.key(10) @@ -165,9 +169,11 @@ def test_key_requires_positive_id(self): def test_latest_pages_build(self): """Test retrieving the most recent pages build.""" - url = self.example_data['url'] + '/pages/builds/latest' self.instance.latest_pages_build() - self.session.get.assert_called_once_with(url) + + self.session.get.assert_called_once_with( + url_for('pages/builds/latest') + ) def test_milestone(self): """Test retrieving a specific milestone.""" @@ -183,9 +189,9 @@ def test_milestone_requires_positive_id(self): def test_pages(self): """Test retrieving information about a repository's page.""" - url = self.example_data['url'] + '/pages' self.instance.pages() - self.session.get.assert_called_once_with(url) + + self.session.get.assert_called_once_with(url_for('pages')) class TestRepositoryIterator(UnitIteratorHelper): From 0a074925889785f4673f30f6fa1d7b2df461906f Mon Sep 17 00:00:00 2001 From: John Barbuto Date: Sat, 9 Aug 2014 11:17:47 -0700 Subject: [PATCH 350/972] Add contributions attribute to User object The repo contributors endpoint returns an extra ``contributions`` attribute, which this captures in the `User` objects returned from ``Repository#contributors``. https://developer.github.com/v3/repos/#list-contributors --- github3/users.py | 3 +++ tests/integration/test_repos_repo.py | 1 + 2 files changed, 4 insertions(+) diff --git a/github3/users.py b/github3/users.py index f8c8a2b9e..55645be8a 100644 --- a/github3/users.py +++ b/github3/users.py @@ -178,6 +178,9 @@ def __init__(self, user, session=None): #: Subscriptions URL (not a template) self.subscriptions_url = user.get('subscriptions_url', '') + #: Number of repo contributions. Only appears in ``repo.contributors`` + self.contributions = user.get('contributions', 0) + self._uniq = user.get('id', None) def __str__(self): diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index c0fe8a561..1765a5d82 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -100,6 +100,7 @@ def test_contributors(self): assert repository is not None for contributor in repository.contributors(): assert isinstance(contributor, github3.users.User) + assert contributor.contributions > 0 def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" From 890de824ca7f09b9cf443b1b6f2e4e0a7aa374f2 Mon Sep 17 00:00:00 2001 From: John Barbuto Date: Sat, 9 Aug 2014 12:06:44 -0700 Subject: [PATCH 351/972] Guard against user.contributions being overwritten by refresh method --- github3/users.py | 5 ++++- tests/integration/test_repos_repo.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/github3/users.py b/github3/users.py index 55645be8a..57b309040 100644 --- a/github3/users.py +++ b/github3/users.py @@ -179,7 +179,10 @@ def __init__(self, user, session=None): self.subscriptions_url = user.get('subscriptions_url', '') #: Number of repo contributions. Only appears in ``repo.contributors`` - self.contributions = user.get('contributions', 0) + contributions = user.get('contributions') + # Guard against this attribute being overwritten by refresh method + if contributions is not None: + self.contributions = contributions self._uniq = user.get('id', None) diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 1765a5d82..6ac7b4efc 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -100,7 +100,7 @@ def test_contributors(self): assert repository is not None for contributor in repository.contributors(): assert isinstance(contributor, github3.users.User) - assert contributor.contributions > 0 + assert isinstance(contributor.contributions, int) def test_create_empty_blob(self): """Test the ability to create an empty blob on a repository.""" From c70eda6b8f2439f06e385c40e8b2b9fe867bdb0c Mon Sep 17 00:00:00 2001 From: John Barbuto Date: Sat, 9 Aug 2014 12:14:22 -0700 Subject: [PATCH 352/972] Expand comment for User.contributions attribute --- github3/users.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/github3/users.py b/github3/users.py index 57b309040..09c2a73b9 100644 --- a/github3/users.py +++ b/github3/users.py @@ -180,7 +180,10 @@ def __init__(self, user, session=None): #: Number of repo contributions. Only appears in ``repo.contributors`` contributions = user.get('contributions') - # Guard against this attribute being overwritten by refresh method + # The refresh method uses __init__ to replace the attributes on the + # instance with what it receives from the /users/:username endpoint. + # What that means is that contributions is no longer returned and as + # such is changed because it doesn't exist. This guards against that. if contributions is not None: self.contributions = contributions From 00233ac94970b20bea1f44b4184d13005eac00f0 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 9 Aug 2014 21:49:33 -0500 Subject: [PATCH 353/972] Rename Repository#iter_notifications --- HISTORY.rst | 1 + github3/repos/repo.py | 54 +++++++++---------- tests/cassettes/Repository_notifications.json | 1 + tests/integration/test_repos_repo.py | 13 +++++ tests/test_repos.py | 12 ----- tests/unit/test_repos_repo.py | 16 ++++++ 6 files changed, 57 insertions(+), 40 deletions(-) create mode 100644 tests/cassettes/Repository_notifications.json diff --git a/HISTORY.rst b/HISTORY.rst index dc60ed283..80b044a3a 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -84,6 +84,7 @@ Old name New name ``Repository#iter_languages`` ``Repository#languages`` ``Repository#iter_milestones`` ``Repository#milestones`` ``Repository#iter_network_events`` ``Repository#network_events`` +``Repository#iter_notifications`` ``Repository#notifications`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 2d9aefef3..7d1dde576 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,34 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - @requires_auth - def iter_notifications(self, all=False, participating=False, since=None, - number=-1, etag=None): - r"""Iterate over the notifications for this repository. - - :param bool all: (optional), show all notifications, including ones - marked as read - :param bool participating: (optional), show only the notifications the - user is participating in directly - :param since: (optional), filters out any notifications updated - before the given time. This can be a `datetime` or an `ISO8601` - formatted date string, e.g., 2012-05-20T23:10:27Z - :type since: datetime or string - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Thread ` - """ - url = self._build_url('notifications', base_url=self._api) - params = { - 'all': all, - 'participating': participating, - 'since': timestamp_parameter(since) - } - for (k, v) in list(params.items()): - if not v: - del params[k] - return self._iter(int(number), url, Thread, params, etag) - @requires_auth def iter_pages_builds(self, number=-1, etag=None): """Iterate over pages builds of this repository. @@ -1671,6 +1643,32 @@ def network_events(self, number=-1, etag=None): url = self._build_url('events', base_url=base) return self._iter(int(number), url, Event, etag) + @requires_auth + def notifications(self, all=False, participating=False, since=None, + number=-1, etag=None): + r"""Iterate over the notifications for this repository. + + :param bool all: (optional), show all notifications, including ones + marked as read + :param bool participating: (optional), show only the notifications the + user is participating in directly + :param since: (optional), filters out any notifications updated + before the given time. This can be a `datetime` or an `ISO8601` + formatted date string, e.g., 2012-05-20T23:10:27Z + :type since: datetime or string + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Thread ` + """ + url = self._build_url('notifications', base_url=self._api) + params = { + 'all': all, + 'participating': participating, + 'since': timestamp_parameter(since) + } + self._remove_none(params) + return self._iter(int(number), url, Thread, params, etag) + @requires_auth def pages(self): """Get information about this repository's pages site. diff --git a/tests/cassettes/Repository_notifications.json b/tests/cassettes/Repository_notifications.json new file mode 100644 index 000000000..904c4bc7f --- /dev/null +++ b/tests/cassettes/Repository_notifications.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YXY+rNhCG/0rEbbNxCNlsglSd9qrt3bk4velNZMAEawEj2yTKov3vfY2BQI6aj3WlVZSwnsevxzNmxo3HEy8M3vzlm+/PvZIWzAu9A9dZHQWL6uzNvbTO8333D8UPBT1yWavVmkxGiVPJpBc2Xi4OvARjPBQUM81qvdwGy7lHj1RTua9ljnGZ1pUKCbEP1cJSa8VkLErNSr2IRUFqYo2/HX9dgXaQHcNgvdhfb4PXTbLdpbvVK9vsVv7bNmLMT3YBjdM3GFzNVfFuHgvHZIpcCc50kV9JtNJak6vBqchzcQLlelH3JiKDpfF0S+Hl4YsUWDZE6IzBt1jSp3EUV/p5Ua1Vgw1Wes8Tw1HYMMmSp4V1dpBl4uOzIZJVogXWkYolrzQX5fMCJ9agCXmgJf+gX6PBWgFipD0vpbWCNTsiVp83t2YNqSQ/0vhsXCNZzPgRzv4i8soeRH2uTFr/jaAwruea7WlSmDRNaa7Y59xrp9cY1D6YIysfjf7pMZCwYVcx4fezzkQ5y3kkqTzPUiFnHDktUxojVmcnHDMzhOvsD67/rKPZ79//OgYQiHHvg5Kbmds6f5KMUzmGdGdPbiKQngBA0js7O3GMfUPw2eVTjFSnkZBUi3uHxm2BE1BDxj9NLGlGCyfhLQCgTAg3T7YAgLhSNXsotG8vvOUo0udPWReRPfIeyZrbaEuAVqpwzpeMOXlwgDSkP5WRDmWcuWF7RkPst3a36cFJqrEHJspF5MTBi5K0kIaojNr3kN67qjNUw5hAJUudpRrGANXScb9bmQYyIPES1Nh6J509gzSdR3NaHmp6cKMOEOy6eVUf6MfdIuZ27lwoQJoKTvKodj/kLhyj1NYOyHc3l14wF2hbkNwuc+44YFTYtC4oCn6vLrhN7BCTsP8fsCZOr9Hm9/0y5r5cw2jI5Uy2h35Hd/Fud+r3OklzmaNrF5xComeQ5peK6sycXJiqopK5iO4QpIkoiq3FYtFkjLZldcGkYwZbAlBUxhmqRhedTc9A1VNQ3VbrqZGZoHrPBU2cfDtAALTb6KLVEsYxVqFPdRLYAsbEgudMaVG6nbEXyphdCs1THj/SsdxOtwmo+aZ4GbM5zfM5olbzmCOOUWubXUTBydw8ZAlYBq4JbKeSM4S0k9cls4yG2E4zlgyNSLKnGg3EaumvXpbBix/88Hfh6zZ8Df7BSuoqmYxZvyy3+Pvhv4WrVfi6NGOqWmUjjB2yMxgM8TdmCE7ALgTxDVcQ+MS1x0/9/ailMLcGMFQquxj+djEL/+N+pDOLc8TSVdA/Pufx+rV03xRSM1GwCmVCd9MyrDKozgt4OkH7lYhYLdADE7My/oGhu/UmmBQEsahL7Ie/28y9E9WoXfHqHT/sC4mh6TNTU7W3aeqFWtamq8STyzEwenji73zo+GzT1tE3O5ySXErR3ReVSFL0+xUrO/YgY2sbR+WFxmY0Arrxv152t4qEpbTO9d4Wz5CdoOrPRWUih8kCus3FhLnQ6jpluwITVf1qzHlhv6OBLpk+oVfs1RgJ4zKl99X2819he1kIchMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "971af40390ac4398fcdd45c8dab0fbe7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d788d2d447e1f828e4e0672c124149ef\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4987", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7B5D:26B4A60:53E6DCD0", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Fri, 08 Aug 2014 17:22:50 GMT", "date": "Sun, 10 Aug 2014 02:45:36 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407641433"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-10T02:45:37"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/notifications?participating=False&per_page=100&all=False"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YXY/iNhSG/wrKbVkMAWaGkapV1Yt2b6rRqr3pqkJO4iTuJHFqOyA2mv/e9zgBAlUzw3huEBCfx+fbx/nWBjIJHoPlarXehJv7YBo0lRYc/1ndiGmA70ZVWGGayMRaRiKhNXXCrUi23OJJOF+sPs3vPi0Wv4fh43L1uF79iTUFN3ZLKLeqaopiSpC/RYyfbWClLQSkfxP7CbcW5MYKM0mVnjxh7VfxTyOM/Sp2Uux/VmUpKjsRO3wa2l8XEM2trc0jY7yWs0zavIlmsSqZFrUyzMis5DupGxOuWPd0OasPTBoDMAvXZGsBK6AlpIi//SisPdRk2hfaKnghJ0IjaZU+kOXk8OX9Yn6/WEyDipe09KwgtEph/7Z/8D9mYJXaV0ITr1CZdBEaWIzntE24mj8s59OA77jl+to+96fpXdcYoWNVWfjBebFhnfDn3Y8haJnuGS5d4sXqYbm+Sx426SZci7tNuLh/iIRYJJslj1OXRmMhos0uQwSJ3JbFlYqDqF5Zl6qiUHtQro26zIX/bsROkuRpR5FV9k4KJFumbC7gW5j0Qo6Sxt6ulJNqkafIRpkQxyA2GiV2ox9ZLwe1KD9eWlcODtgVcG2lqm5X8EIaNKUzXsnv/H00SFMZu7q42UInBemuG9ws3om1rNZyx+MDuUaLWMgdnP1O5JU8iH0H+ANJQa6XVmx5UlKZprwwAj3BbW9R++6PW7J/0M3ATgS1ZRdVFObTweaqmhQy0lwfXDeVqGmd8hi5OtmjS06QrpNfpP21iSY/PX3ZLQHBuueTJqMZN9pce9IrIR1FoDz1M0X3WRy8OCTfMnz29RSj1HmkNEcb9gJfgFo2/Em5ZAUvvfgOAFCu1LMXyAEAcifem1J7PDL9yXmsn6opo67lvaVqxtGng50b9PlKCC/DT5CWHbsyyqGKcz/skdGy7puLNs+8VCV5YKJCRV4cHJTMQVpmct6dQ3brqx1RiXEB1SL1VpUYJ6jVnvF2ahLkhMQhaBF6Lz2PDNb2Hi14lTU886OeIIg6HdUZ//7qEDNeO2cKkDTBuVHau8mdOaTpcfj3a50DzBnqjq7xU/wVBwwGG+eCspSvjWDjxB5xkfYfgKU8vUb3Vw+vTD0yWnbuyV3T/7iLzXEP1p736K8Lnrq7K4dh7Q81tzl1LmxVcy18UqJHsDbiGLZms1mb4yJK8FJozwruCEBxHeeYGn30bI8MTD0lt25aT0nNBNN7oXji5dsTBMDu8PbRtSMMc6zGPdVLQQcYEktZ4D6uKr8ee6YM2ZWyMpXxW24s493hAtR+NrKKxZTj9Qay1spYIo8xa1MUMXAKPw91BJiB1wTdTaXACxk/92jRMVpGN01cRUYH/gtrmc3pjY5hg/dFw5vheH6No9gQFLz89S/mnOF4mxIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "nil", "access-control-allow-credentials": "true", "x-poll-interval": "60", "status": "200 OK", "x-ratelimit-remaining": "4986", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7B5D:26B4A89:53E6DCD0", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Wed, 11 Jun 2014 22:34:54 GMT", "date": "Sun, 10 Aug 2014 02:45:36 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407641433"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/notifications?participating=False&per_page=100&all=False"}, "recorded_at": "2014-08-10T02:45:37"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 6ac7b4efc..b17ddf69d 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -311,6 +311,19 @@ def test_network_events(self): for event in events: assert isinstance(event, github3.events.Event) + def test_notifications(self): + """Test that a user can retrieve their repo notifications.""" + self.basic_login() + cassette_name = self.cassette_name('notifications') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + notifications = list(repository.notifications()) + + assert len(notifications) > 0 + for notification in notifications: + assert isinstance(notification, github3.notifications.Thread) + def test_iter_pulls_accepts_sort_and_direction(self): """Test that iter_pulls now takes a sort parameter.""" cassette_name = self.cassette_name('pull_requests_accept_sort') diff --git a/tests/test_repos.py b/tests/test_repos.py index 4e306a54d..659e78407 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,18 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_notifications(self): - self.response('notification', _iter=True) - self.get(self.api + 'notifications') - self.conf.update(params={'per_page': 100}) - - self.assertRaises(github3.GitHubError, self.repo.iter_notifications) - - self.login() - n = next(self.repo.iter_notifications()) - assert isinstance(n, github3.notifications.Thread) - self.mock_assertions() - def test_iter_pulls(self): self.response('pull', _iter=True) self.get(self.api + 'pulls') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 92d93c424..23940b7ea 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -469,6 +469,17 @@ def test_network_events(self): headers={} ) + def test_notifications(self): + """Test the ability to iterate over the notifications for a repo.""" + i = self.instance.notifications() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('notifications'), + params={'per_page': 100, 'participating': False, 'all': False}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): @@ -495,3 +506,8 @@ def test_keys(self): """Show that a user must be authenticated to list keys.""" with pytest.raises(GitHubError): self.instance.keys() + + def test_notifications(self): + """Show that a user must be authenticated to list notifications.""" + with pytest.raises(GitHubError): + self.instance.notifications() From 97c765181ccb46541ad24595427f729f14b45c6c Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 10 Aug 2014 13:17:27 -0500 Subject: [PATCH 354/972] Add reprs to PagesInfo and PagesBuild --- github3/repos/pages.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/github3/repos/pages.py b/github3/repos/pages.py index 33132a1a2..5c64a565e 100644 --- a/github3/repos/pages.py +++ b/github3/repos/pages.py @@ -1,4 +1,6 @@ -from ..models import GitHubObject +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +from github3.models import GitHubObject class PagesInfo(GitHubObject): @@ -15,6 +17,13 @@ def __init__(self, info): #: Boolean indicating whether there is a custom 404 for the pages site self.custom_404 = info.get('custom_404') + def _repr(self): + info = self.cname or '' + if info: + info += '/' + info += self.status or '' + return ''.format(info) + class PagesBuild(GitHubObject): def __init__(self, build): @@ -43,3 +52,6 @@ def __init__(self, build): #: Datetime the build was updated self.updated_at = self._strptime(build.get('updated_at')) + + def _repr(self): + return ''.format(self.commit, self.status) From f07767ace8993f80493b861ca3400bf7ee9ea009 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 10 Aug 2014 13:30:20 -0500 Subject: [PATCH 355/972] Rename Repository#iter_pages_builds --- HISTORY.rst | 1 + github3/repos/repo.py | 20 ++++++++++---------- tests/integration/test_repos_pages.py | 4 ++-- tests/unit/test_repos_repo.py | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 80b044a3a..f85ad0f3d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -85,6 +85,7 @@ Old name New name ``Repository#iter_milestones`` ``Repository#milestones`` ``Repository#iter_network_events`` ``Repository#network_events`` ``Repository#iter_notifications`` ``Repository#notifications`` +``Repository#iter_pages_builds`` ``Repository#pages_builds`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 7d1dde576..38d22586b 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,16 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - @requires_auth - def iter_pages_builds(self, number=-1, etag=None): - """Iterate over pages builds of this repository. - - :returns: generator of :class:`PagesBuild - ` - """ - url = self._build_url('pages', 'builds', base_url=self._api) - return self._iter(int(number), url, PagesBuild, etag=etag) - def iter_pulls(self, state=None, head=None, base=None, sort='created', direction='desc', number=-1, etag=None): r"""List pull requests on repository. @@ -1679,6 +1669,16 @@ def pages(self): json = self._json(self._get(url), 200) return PagesInfo(json) if json else None + @requires_auth + def pages_builds(self, number=-1, etag=None): + """Iterate over pages builds of this repository. + + :returns: generator of :class:`PagesBuild + ` + """ + url = self._build_url('pages', 'builds', base_url=self._api) + return self._iter(int(number), url, PagesBuild, etag=etag) + def pull_request(self, number): """Get the pull request indicated by ``number``. diff --git a/tests/integration/test_repos_pages.py b/tests/integration/test_repos_pages.py index 0c31d95aa..4a93f2bb4 100644 --- a/tests/integration/test_repos_pages.py +++ b/tests/integration/test_repos_pages.py @@ -28,12 +28,12 @@ def test_pages(self): assert isinstance(pages_info, github3.repos.pages.PagesInfo) - def test_iter_pages_builds(self): + def test_pages_builds(self): """Test the ability to list the pages builds.""" self.basic_login() cassette_name = self.cassette_name('pages_builds') with self.recorder.use_cassette(cassette_name): repository = self.gh.repository('sigmavirus24', 'github3.py') assert repository is not None - for build in repository.iter_pages_builds(): + for build in repository.pages_builds(): assert isinstance(build, github3.repos.pages.PagesBuild) diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 23940b7ea..ba13683b0 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -480,6 +480,17 @@ def test_notifications(self): headers={} ) + def test_pages_builds(self): + """Test the request for the GitHub Pages builds for a repo.""" + i = self.instance.pages_builds() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('pages/builds'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): @@ -511,3 +522,8 @@ def test_notifications(self): """Show that a user must be authenticated to list notifications.""" with pytest.raises(GitHubError): self.instance.notifications() + + def test_pages_builds(self): + """Show that a user must be authenticated to list their builds.""" + with pytest.raises(GitHubError): + self.instance.pages_builds() From 2890cd7a18fac0ab42269e2734a819e55ff31f3e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 10 Aug 2014 14:37:57 -0500 Subject: [PATCH 356/972] Rename Repository#iter_pulls --- HISTORY.rst | 1 + github3/repos/repo.py | 80 +++++++++++++++------------- tests/integration/test_repos_repo.py | 21 ++++++-- tests/test_repos.py | 31 ----------- tests/unit/test_repos_repo.py | 22 ++++++++ 5 files changed, 82 insertions(+), 73 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index f85ad0f3d..2fe189efd 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -86,6 +86,7 @@ Old name New name ``Repository#iter_network_events`` ``Repository#network_events`` ``Repository#iter_notifications`` ``Repository#notifications`` ``Repository#iter_pages_builds`` ``Repository#pages_builds`` +``Repository#iter_pulls`` ``Repository#pull_requests`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 38d22586b..1c047eec4 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,44 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_pulls(self, state=None, head=None, base=None, sort='created', - direction='desc', number=-1, etag=None): - r"""List pull requests on repository. - - .. versionchanged:: 0.9.0 - - - The ``state`` parameter now accepts 'all' in addition to 'open' - and 'closed'. - - - The ``sort`` parameter was added. - - - The ``direction`` parameter was added. - - :param str state: (optional), accepted values: ('all', 'open', - 'closed') - :param str head: (optional), filters pulls by head user and branch - name in the format ``user:ref-name``, e.g., ``seveas:debian`` - :param str base: (optional), filter pulls by base branch name. - Example: ``develop``. - :param str sort: (optional), Sort pull requests by ``created``, - ``updated``, ``popularity``, ``long-running``. Default: 'created' - :param str direction: (optional), Choose the direction to list pull - requests. Accepted values: ('desc', 'asc'). Default: 'desc' - :param int number: (optional), number of pulls to return. Default: -1 - returns all available pull requests - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of - :class:`PullRequest `\ s - """ - url = self._build_url('pulls', base_url=self._api) - params = {} - if state and state.lower() in ('all', 'open', 'closed'): - params['state'] = state.lower() - params.update(head=head, base=base, sort=sort, direction=direction) - self._remove_none(params) - return self._iter(int(number), url, PullRequest, params, etag) - def iter_refs(self, subspace='', number=-1, etag=None): r"""Iterate over references for this repository. @@ -1691,6 +1653,48 @@ def pull_request(self, number): json = self._json(self._get(url), 200) return PullRequest(json, self) if json else None + def pull_requests(self, state=None, head=None, base=None, sort='created', + direction='desc', number=-1, etag=None): + r"""List pull requests on repository. + + .. versionchanged:: 0.9.0 + + - The ``state`` parameter now accepts 'all' in addition to 'open' + and 'closed'. + + - The ``sort`` parameter was added. + + - The ``direction`` parameter was added. + + :param str state: (optional), accepted values: ('all', 'open', + 'closed') + :param str head: (optional), filters pulls by head user and branch + name in the format ``user:ref-name``, e.g., ``seveas:debian`` + :param str base: (optional), filter pulls by base branch name. + Example: ``develop``. + :param str sort: (optional), Sort pull requests by ``created``, + ``updated``, ``popularity``, ``long-running``. Default: 'created' + :param str direction: (optional), Choose the direction to list pull + requests. Accepted values: ('desc', 'asc'). Default: 'desc' + :param int number: (optional), number of pulls to return. Default: -1 + returns all available pull requests + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`PullRequest `\ s + """ + url = self._build_url('pulls', base_url=self._api) + params = {} + + if state: + state = state.lower() + if state in ('all', 'open', 'closed'): + params['state'] = state + + params.update(head=head, base=base, sort=sort, direction=direction) + self._remove_none(params) + return self._iter(int(number), url, PullRequest, params, etag) + def readme(self): """Get the README for this repository. diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index b17ddf69d..e79ec27b4 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -324,15 +324,28 @@ def test_notifications(self): for notification in notifications: assert isinstance(notification, github3.notifications.Thread) - def test_iter_pulls_accepts_sort_and_direction(self): - """Test that iter_pulls now takes a sort parameter.""" + def test_pull_requests(self): + """Test that a user can retrieve the pull requests from a repo.""" + cassette_name = self.cassette_name('pull_requests') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + pulls = list(repository.pull_requests()) + + assert len(pulls) > 0 + for pull in pulls: + assert isinstance(pull, github3.pulls.PullRequest) + + def test_pull_requests_accepts_sort_and_direction(self): + """Test that pull_requests now takes a sort parameter.""" cassette_name = self.cassette_name('pull_requests_accept_sort') with self.recorder.use_cassette(cassette_name): repository = self.gh.repository('sigmavirus24', 'betamax') assert repository is not None last_pr = None - for pr in repository.iter_pulls(sort='updated', direction='asc'): - assert pr + for pr in repository.pull_requests(sort='updated', + direction='asc'): + assert pr is not None if last_pr: assert last_pr.updated_at < pr.updated_at last_pr = pr diff --git a/tests/test_repos.py b/tests/test_repos.py index 659e78407..1a50a6b76 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,37 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_pulls(self): - self.response('pull', _iter=True) - self.get(self.api + 'pulls') - base_params = {'per_page': 100, 'sort': 'created', 'direction': 'desc'} - self.conf.update(params=base_params) - - p = next(self.repo.iter_pulls()) - assert isinstance(p, github3.pulls.PullRequest) - self.mock_assertions() - - next(self.repo.iter_pulls('foo')) - self.mock_assertions() - - params = {'state': 'open'} - params.update(base_params) - self.conf.update(params=params) - next(self.repo.iter_pulls('Open')) - self.mock_assertions() - - params = {'head': 'user:branch'} - params.update(base_params) - self.conf.update(params=params) - next(self.repo.iter_pulls(head='user:branch')) - self.mock_assertions() - - params = {'base': 'branch'} - params.update(base_params) - self.conf.update(params=params) - next(self.repo.iter_pulls(base='branch')) - self.mock_assertions() - def test_iter_refs(self): self.response('ref', _iter=True) self.get(self.api + 'git/refs') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index ba13683b0..f358c9fd9 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -491,6 +491,28 @@ def test_pages_builds(self): headers={} ) + def test_pull_requests(self): + """Test the request for the retrieving pull requests.""" + i = self.instance.pull_requests() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('pulls'), + params={'per_page': 100, 'sort': 'created', 'direction': 'desc'}, + headers={} + ) + + def test_pull_requests_ignore_invalid_state(self): + """Test the method ignores invalid pull request states.""" + i = self.instance.pull_requests(state='invalid') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('pulls'), + params={'per_page': 100, 'sort': 'created', 'direction': 'desc'}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From 258db7338a49c8d283318947e2ad790a75e09655 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 10 Aug 2014 20:24:35 -0500 Subject: [PATCH 357/972] Add missing cassette --- tests/cassettes/Repository_pull_requests.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/cassettes/Repository_pull_requests.json diff --git a/tests/cassettes/Repository_pull_requests.json b/tests/cassettes/Repository_pull_requests.json new file mode 100644 index 000000000..cd96a6fbe --- /dev/null +++ b/tests/cassettes/Repository_pull_requests.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY/iOBCG/wrKdWlMCN1ApNHMnnb3Nofey16QkzjE6iSObAdER/3f93Uc8sFogW6v1EKQdj1+Xa5yqtx4PPHCYOMvN74/90paMC/0DlxndRQsqrM399I6z/fdPxQ/FPTIZa1WazIZJU4lk17YeLk48BKM8VBQzDSr9XIbLOcePVJN5b6WOcZlWlcqJMQ+VAtLrRWTsSg1K/UiFgWpiTX+fvy2Au0gO4bBerG/3gbPL8l2l+5Wz+xlt/I324gxP9kFNE43MLiaq+LdPBaOyRS5EpzpIr+SaKW1JleDU5Hn4gTK9aLuTUR6S+PplsLLwxcpsGyI0BmDb7GkD+MorvTnRbVWDTZY6T1PDEdhwyRLPi2ss4MsEx8fDZGsEi2wjlQseaW5KD8vcGINmpAHWvJ3+jUarBUgRtrnpbRWsGZHxOrnza1ZQyrJjzQ+G9dIFjN+hLO/iLyyB1GfK5PWfyMojOu5ZnuaFCZNU5or9jH32uk1BrUP5sjKR6N/egwkrN9VTPjzrDNRznIeSSrPs1TIGUdOy5TGiNXZCcfMDOE6+4PrP+to9vvPv44BBGLcW6/kZua2zp8k41SOId3Zk5sIpCcAkPTGzk4cY98QfHb5FCPVaSQk1eLeoXFb4ATUkPFPE0ua0cJJeAsAKBPCzZMtACCuVM0eCu3bC285ilzyp6yLyB55j2TNbbQlQCtVOOdLxpw82EMacjmVkQ5lnLlhL4yG2G/tbtODk1RjD0yUi8iJgxclaSENURm17yG9d1VnqIYxgUqWOks1jB6qpeN+tzINpEfiJaix9U46LwzSdB7NaXmo6cGN2kOw6+ZVfaDvd4uY27kzUIA0FZzkUe1+yA0co9TWDsh3N5cOmAHaFiS3y5w7DhgVNq0LioLfqwtuEzvEJOz/B6yJ02u0+X2/jLkv1zAaMpzJ9tDv6C7e7U79i07SDHN07YJTSFwYpPmtojozJxemqqhkLqI7BGkiimJrsVg0GaNtWV0w6ZjBlgAUlXGGqtFFZ3NhoOopqG6r9dTITFC954ImTr7tIQDabXTRagnjGKvQpzoJbAFjYsFzprQo3c7YgTJml0LzlMePdCy3020Car4rXsZsTvN8jqjVPOaIY9TaZhdRcDI3D1kCloFrAtup5Awh7eR1ySyjIbbTjCVDI5LsqUYDsVr6q6dl8OQHr/4ufN6Gz8E/WEldJZMx66flFn+v/iZcrcLnpRlT1SobYdoh/vLVX4dB0GFwAnYhiG+4gsAnrj1+6e9HLYW5NQBbqWww/DGYhf9xP9KZxTli6SroH5/zeP1aum8KqZkoWIUyobtp6VcZVOcFPJ2g/UpErBbogYlZGX/H0N36JZgUBLGoS+yHv3uZeyeqUbvi1Tt+eCkk+qbPTE3V3qapF2pZm64ST4ZjYPTwxN943/HZpq2jb3BfVHApRXdfVCJJ0e9XrOzYgwzbOCovNDajEUb3ILtbRcJSWud6b4tnyE5Q9eeigu6S6RPavgvY0MYVx2XZ249/AVVXtNw9EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f6824d63d4d07e7c004af082600b136\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7B5F:5917E71:53E7C84B", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 08 Aug 2014 17:22:50 GMT", "date": "Sun, 10 Aug 2014 19:30:19 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407702619"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-10T19:30:20"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/pulls?sort=created&per_page=100&direction=desc"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"2766f6ed5e921c2b2f040affa74556fc\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:7B5F:5917EAD:53E7C84B", "cache-control": "public, max-age=60, s-maxage=60", "date": "Sun, 10 Aug 2014 19:30:20 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407702619"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/pulls?sort=created&per_page=100&direction=desc"}, "recorded_at": "2014-08-10T19:30:20"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file From b86a5b261c0793a75c261a549edcd1af3ff168b4 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 12 Aug 2014 21:36:21 -0500 Subject: [PATCH 358/972] Rename Repository#iter_refs --- HISTORY.rst | 1 + github3/repos/repo.py | 34 ++++++++++++++-------------- tests/cassettes/Repository_refs.json | 1 + tests/integration/test_repos_repo.py | 12 ++++++++++ tests/test_repos.py | 13 ----------- tests/unit/test_repos_repo.py | 22 ++++++++++++++++++ 6 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 tests/cassettes/Repository_refs.json diff --git a/HISTORY.rst b/HISTORY.rst index 2fe189efd..7a080bfe6 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -87,6 +87,7 @@ Old name New name ``Repository#iter_notifications`` ``Repository#notifications`` ``Repository#iter_pages_builds`` ``Repository#pages_builds`` ``Repository#iter_pulls`` ``Repository#pull_requests`` +``Repository#iter_refs`` ``Repository#refs`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 1c047eec4..878d10285 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,23 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_refs(self, subspace='', number=-1, etag=None): - r"""Iterate over references for this repository. - - :param str subspace: (optional), e.g. 'tags', 'stashes', 'notes' - :param int number: (optional), number of refs to return. Default: -1 - returns all available refs - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Reference `\ s - """ - if subspace: - args = ('git', 'refs', subspace) - else: - args = ('git', 'refs') - url = self._build_url(*args, base_url=self._api) - return self._iter(int(number), url, Reference, etag=etag) - def iter_releases(self, number=-1, etag=None): r"""Iterate over releases for this repository. @@ -1721,6 +1704,23 @@ def ref(self, ref): json = self._json(self._get(url), 200) return Reference(json, self) if json else None + def refs(self, subspace='', number=-1, etag=None): + r"""Iterate over references for this repository. + + :param str subspace: (optional), e.g. 'tags', 'stashes', 'notes' + :param int number: (optional), number of refs to return. Default: -1 + returns all available refs + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Reference `\ s + """ + if subspace: + args = ('git', 'refs', subspace) + else: + args = ('git', 'refs') + url = self._build_url(*args, base_url=self._api) + return self._iter(int(number), url, Reference, etag=etag) + def release(self, id): """Get a single release. diff --git a/tests/cassettes/Repository_refs.json b/tests/cassettes/Repository_refs.json new file mode 100644 index 000000000..abf26e8c2 --- /dev/null +++ b/tests/cassettes/Repository_refs.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YzW7rNhCFX8XQto5pSfG1LaC47art7i7STTcGJVEWEUkUSMqGI+TdeyjK+vFF7SQsEBi2wvl4OJyhZth6PPWicOuvt76/9CpaMi/yjlznTRyu6ou39LKmKA79PxQ/lvTEZaOCZzIbJc4Vk17UeoU48gqM6VBQzDTB83oXrpcePVFN5aGRBcblWtcqIsQ+VCtLbRSTiag0q/QqESVpiDX+fvo1AO0oe4bBeon/vAs339LdPtsHG/ZtH/jbXcyYn+5DmmRbGNzMVfN+HgvHZIrcCM51WdxItNI6k5vBmSgKcQbldlGPJiKDpfF0R+HV8YsUWLZE6JzBt1jSu3EUV/rzojqrFhus9IGnhqOwYZKlnxbW20GWiY/3lkhWiw7YxCqRvNZcVJ8XOLMGTcgjrfgb/RoN1goQI+3zUjorWLMTYvXz5tasJbXkJ5pcjGskSxg/wdlfRN7Yg6gvtUnrvxEUxvVcswNNS5OmGS0Ue1963fQag7oHS2TlR6N/fgykbNhVTPjjonNRLQoeSyovi0zIBUdOy4wmiNXFGcfMAuG6+IPrP5t48fuPv04hBGLc66DkbuZ2zp8l41yOIT3Yk7sIpCcAkPTKLk4cY98SfPb5lCDVaSwk1eLRoXFf4AzUkulPE0ua0dJJeAcAKBfCzZMdACCuVMM+FNr3F95xFLnmT9WUsT3yPpI199GWAK1U4ZyvGHPy4ABpyfVURjpUSe6GvTJaYr91u02PTlKNPTBxIWInDl6UpIO0ROXUvof0wVWdoRrGDCpZ5izVMAaolo773ck0kAGJl6DG1jvpvDJI23u0oNWxoUc36gDBrptX9ZG+PSxi7ufOSAHSVHCSx437ITdyjFJbOyDf3Vw6YkZoV5DcL3MeOGBS2HQuKEv+qC64T+wRs7D/H7AmTm/R5vfjMuaxXMNoyXgm20O/p7t4tz/1rzpJO87RtwtOIXFlkPaXmurcnFyYqqaSuYjuEaSNKYqt1WrV5ox2ZXXJpGMGWwJQVCY5qkYXne2VgaqnpLqr1jMjM0X1XgiaOvl2gABot9FFqyVMY6xGn+oksANMiSUvmNKicjtjR8qUXQnNM558pGO5n24zUPtd8SphS1oUS0St5glHHKPWNruIgpO5ecgSsAxcE9hOpWAIaSevS2YZLbGdZiIZGpH0QDUaiGDtB0/r8MkPX/x9tNlFm/AfrKSp09mY56f1Dn8v/jYKgmizNmPqRuUTTDfE91/WQRT4UbgxQ3AC9iGIb7iCwCeuPX7q7ycthbk1gKFS+Wj422gW/cf9SG+WFIilm6D/+Jyn29fSY1NIzUXJapQJ/U3LsMqwvqzg6RTtVyoStUIPTMzK+BuG7sP9ZlYQJKKpsB/+/tvSO1ON2hWv3unDayExNH1maqoONk29SMvGdJV4Mh4Dk4dn/sqHjs82bT19i/uikksp+vuiCkmKfr9mVc8eZdjGUXmRsZmMMLpH2f0qUpbRptAHWzxDdoqqvxA1dFdMn9H2XcGGNq04rsvevf8LhzaALD0TAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"4e996295d4c329b08a075d8ebe9be2a4\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6A43:B23A605:53EACDFE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 08 Aug 2014 17:22:50 GMT", "date": "Wed, 13 Aug 2014 02:31:26 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407900686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-13T02:31:27"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/git/refs?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"1c361eac0dfadc13bb02affbccead4ba\"", "access-control-allow-credentials": "true", "x-poll-interval": "300", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6A43:B23A63F:53EACDFE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 08 Aug 2014 17:22:50 GMT", "link": "; rel=\"next\", ; rel=\"last\"", "date": "Wed, 13 Aug 2014 02:31:26 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407900686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/git/refs?per_page=100"}, "recorded_at": "2014-08-13T02:31:27"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repositories/3710711/git/refs?per_page=100&page=2"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"3b92992dbae0dbe2ba105f1d7a7df020\"", "access-control-allow-credentials": "true", "x-poll-interval": "300", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6A43:B23A6A6:53EACDFE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 08 Aug 2014 17:22:50 GMT", "link": "; rel=\"next\", ; rel=\"last\", ; rel=\"first\", ; rel=\"prev\"", "date": "Wed, 13 Aug 2014 02:31:26 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407900686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repositories/3710711/git/refs?per_page=100&page=2"}, "recorded_at": "2014-08-13T02:31:27"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repositories/3710711/git/refs?per_page=100&page=3"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0668a3386d2e04c8208589834f771692\"", "access-control-allow-credentials": "true", "x-poll-interval": "300", "status": "200 OK", "x-ratelimit-remaining": "56", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:6A43:B23A6D2:53EACDFE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 08 Aug 2014 17:22:50 GMT", "link": "; rel=\"first\", ; rel=\"prev\"", "date": "Wed, 13 Aug 2014 02:31:27 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407900686"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repositories/3710711/git/refs?per_page=100&page=3"}, "recorded_at": "2014-08-13T02:31:27"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index e79ec27b4..85c55b7f7 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -369,6 +369,18 @@ def test_release(self): assert isinstance(release, github3.repos.release.Release) + def test_refs(self): + """Test the ability to retrieve the references from a repository.""" + cassette_name = self.cassette_name('refs') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + references = list(repository.refs()) + + assert len(references) > 0 + for ref in references: + assert isinstance(ref, github3.git.Reference) + def test_subscription(self): """Test the ability to subscribe to a repository's notifications.""" self.basic_login() diff --git a/tests/test_repos.py b/tests/test_repos.py index 1a50a6b76..bcb5c1f23 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,19 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_refs(self): - self.response('ref', _iter=True) - self.get(self.api + 'git/refs') - - r = next(self.repo.iter_refs()) - assert isinstance(r, github3.git.Reference) - self.mock_assertions() - - self.get(self.api + 'git/refs/subspace') - r = next(self.repo.iter_refs('subspace')) - assert isinstance(r, github3.git.Reference) - self.mock_assertions() - def test_iter_stargazers(self): self.response('user', _iter=True) self.get(self.api + 'stargazers') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index f358c9fd9..371d80bb4 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -513,6 +513,28 @@ def test_pull_requests_ignore_invalid_state(self): headers={} ) + def test_refs(self): + """Test the request for retrieving references.""" + i = self.instance.refs() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('git/refs'), + params={'per_page': 100}, + headers={} + ) + + def test_refs_with_a_subspace(self): + """Test the request for retrieivng refs in a subspace.""" + i = self.instance.refs('a-subspace') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('git/refs/a-subspace'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From 5c456ac9e4d7502f7606124a996eb1e75a2e85ac Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 13 Aug 2014 19:45:23 -0500 Subject: [PATCH 359/972] Rename Repository#iter_releases --- HISTORY.rst | 1 + github3/repos/repo.py | 30 +++++++++---------- ...releases.json => Repository_releases.json} | 0 tests/integration/test_repos_repo.py | 18 +++++------ tests/unit/test_repos_repo.py | 11 +++++++ 5 files changed, 36 insertions(+), 24 deletions(-) rename tests/cassettes/{Repository_iter_releases.json => Repository_releases.json} (100%) diff --git a/HISTORY.rst b/HISTORY.rst index 7a080bfe6..27e33154d 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -88,6 +88,7 @@ Old name New name ``Repository#iter_pages_builds`` ``Repository#pages_builds`` ``Repository#iter_pulls`` ``Repository#pull_requests`` ``Repository#iter_refs`` ``Repository#refs`` +``Repository#iter_releases`` ``Repository#releases`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 878d10285..7ef27f249 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,21 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_releases(self, number=-1, etag=None): - r"""Iterate over releases for this repository. - - :param int number: (optional), number of refs to return. Default: -1 - returns all available refs - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of - :class:`Release `\ s - """ - url = self._build_url('releases', base_url=self._api) - iterator = self._iter(int(number), url, Release, etag=etag) - iterator.headers.update(Release.CUSTOM_HEADERS) - return iterator - def iter_stargazers(self, number=-1, etag=None): r"""List users who have starred this repository. @@ -1733,6 +1718,21 @@ def release(self, id): json = self._json(self._get(url), 200) return Release(json, self) if json else None + def releases(self, number=-1, etag=None): + r"""Iterate over releases for this repository. + + :param int number: (optional), number of refs to return. Default: -1 + returns all available refs + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of + :class:`Release `\ s + """ + url = self._build_url('releases', base_url=self._api) + iterator = self._iter(int(number), url, Release, etag=etag) + iterator.headers.update(Release.CUSTOM_HEADERS) + return iterator + @requires_auth def remove_collaborator(self, username): """Remove collaborator ``username`` from the repository. diff --git a/tests/cassettes/Repository_iter_releases.json b/tests/cassettes/Repository_releases.json similarity index 100% rename from tests/cassettes/Repository_iter_releases.json rename to tests/cassettes/Repository_releases.json diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 85c55b7f7..cfe130f5f 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -350,15 +350,6 @@ def test_pull_requests_accepts_sort_and_direction(self): assert last_pr.updated_at < pr.updated_at last_pr = pr - def test_iter_releases(self): - """Test the ability to iterate over releases on a repository.""" - cassette_name = self.cassette_name('iter_releases') - with self.recorder.use_cassette(cassette_name): - repository = self.gh.repository('sigmavirus24', 'github3.py') - assert repository is not None - for release in repository.iter_releases(): - assert isinstance(release, github3.repos.release.Release) - def test_release(self): """Test the ability to retrieve a single release.""" cassette_name = self.cassette_name('release') @@ -369,6 +360,15 @@ def test_release(self): assert isinstance(release, github3.repos.release.Release) + def test_releases(self): + """Test the ability to iterate over releases on a repository.""" + cassette_name = self.cassette_name('releases') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + for release in repository.releases(): + assert isinstance(release, github3.repos.release.Release) + def test_refs(self): """Test the ability to retrieve the references from a repository.""" cassette_name = self.cassette_name('refs') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 371d80bb4..1f555405c 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -535,6 +535,17 @@ def test_refs_with_a_subspace(self): headers={} ) + def test_releases(self): + """Test the request for retrieving releases from a repository.""" + i = self.instance.releases() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('releases'), + params={'per_page': 100}, + headers={'Accept': 'application/vnd.github.manifold-preview'} + ) + class TestRepositoryRequiresAuth(UnitHelper): From 4833715934b53f82f6f19dea7b35f694f732e92d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 13 Aug 2014 20:13:53 -0500 Subject: [PATCH 360/972] Rename Repository#iter_stargazers --- HISTORY.rst | 4 ++++ github3/repos/repo.py | 26 +++++++++++----------- tests/cassettes/Repository_stargazers.json | 1 + tests/integration/test_repos_repo.py | 12 ++++++++++ tests/test_repos.py | 8 ------- tests/unit/test_repos_repo.py | 11 +++++++++ 6 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 tests/cassettes/Repository_stargazers.json diff --git a/HISTORY.rst b/HISTORY.rst index 27e33154d..69fc51df4 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -89,6 +89,7 @@ Old name New name ``Repository#iter_pulls`` ``Repository#pull_requests`` ``Repository#iter_refs`` ``Repository#refs`` ``Repository#iter_releases`` ``Repository#releases`` +``Repository#iter_stargazers`` ``Repository#stargazers`` ========================================== ============================================== @@ -228,6 +229,9 @@ Old name New attribute name - ``Team#add_member`` - ``Team#is_member`` +- ``Repository.stargazers`` is now ``Repository.stargazers_count`` (conforming + with the attribute name returned by the API). + 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 7ef27f249..8b5913cc0 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -136,7 +136,7 @@ def __init__(self, repo, session=None): # The number of stargazers #: Number of users who starred the repository - self.stargazers = repo.get('stargazers_count', 0) + self.stargazers_count = repo.get('stargazers_count', 0) # SSH url e.g. git@github.com/sigmavirus24/github3.py #: URL to clone the repository via SSH. @@ -1410,18 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_stargazers(self, number=-1, etag=None): - r"""List users who have starred this repository. - - :param int number: (optional), number of stargazers to return. - Default: -1 returns all subscribers available - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`User `\ s - """ - url = self._build_url('stargazers', base_url=self._api) - return self._iter(int(number), url, User, etag=etag) - def iter_subscribers(self, number=-1, etag=None): r"""Iterate over users subscribed to this repository. @@ -1748,6 +1736,18 @@ def remove_collaborator(self, username): base_url=self._api) return self._boolean(self._delete(url), 204, 404) + def stargazers(self, number=-1, etag=None): + r"""List users who have starred this repository. + + :param int number: (optional), number of stargazers to return. + Default: -1 returns all subscribers available + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`User `\ s + """ + url = self._build_url('stargazers', base_url=self._api) + return self._iter(int(number), url, User, etag=etag) + @requires_auth def subscribe(self): """Subscribe the user to this repository's notifications. diff --git a/tests/cassettes/Repository_stargazers.json b/tests/cassettes/Repository_stargazers.json new file mode 100644 index 000000000..1195302d0 --- /dev/null +++ b/tests/cassettes/Repository_stargazers.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/betamax"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA6WY346rNhDGXyXittk4Idn8QapOq75AVZ32ojeRAQPWAqa2SZpF++79bEMgUU+yC9JqN0s8P38ez9gzNB6PvWC12qwPu/Vm7pW0YF7ghUzTgv7rzb2kzvNj+1TxtKAnLmvlb0g/RJxLJr2g8XKR8hLWw3FAmBn8zXK/Xs49eqKaymMtc4zLtK5UQIh7qBYp11kd1orJSJSalXoRiYLUxBl/O/3sg5bKlmGwXrTa7Nev23h/SA7+K9se/NVuHzK2ig9rGiU7GNzNVfF2HgfHZIrcCc50kd9JdNKsyd3gROS5OINyv6hnE5GrpXGzpfAyHUmBZUOEzhh8iyV9GEdxpb8uylo1xPw58thwFDZMsvjLwlo7yDLx8dEQySphgXWoIskrzUX5dYE31qAJmdKSv9NxNFgrQIy0r0uxVrBmJ8Tq182dWUMqyU80uhjXSBYxfoKzRyLv7EHUl8ok9J8ICuN6rtmRxoVJ04Tmin3MPTu9xiD7YI6s/Gz0D86AmF23FLP9Ovvrtz9mvODabssM3/K0ZPFMlPlllgg5qy46E+WLZP/UDAG3gDY8fruKeJi01u83eThQYjBP9uLH9shJWEPMG7uMhxjjhuB3m0ERkpuGQlItnh0TD6TdUBoy/NeEjma0GC/ZWoOSCTHBe9YaFK5UzT4Vww/WayGKdFlS1kXoDrbP5MYDrjOHSqpsVLLxXrsSGtKduqGkZZRNYHaAhrhPdm9pOl6kMQYjzEU4HoL7j1hCQ1RG3fWij5N0GaQB3BAlS6aJNIArUcspu2sFGsKVhytNY6PHK+wApGm9mNMyrWk6AXklYI/NlZvS96fFyIPs6BHgmTJM8rCeeG71EKPR3f7I5Qlu7Bk90dYTj6uUR+seFCV25QVur/EKW/ub2J7KNPF4zzX/Py8+Hqy7AzSkP2Dd8d1+M9qj7fndTUCafoK2vJ/iXtsfKNL8VFGdmfMI81RUstFyW3vShBRl0WKxaDJGbQFcMDklQZ05OFRGGYq70QqbDoAipaDaVtSJERijws4Fjcf780oAze3baJXOfBhOFVrI8dKs9RBX8BwloygnnJk9YgguheYJjz7TSTxIqBtK803xMmJzmudzRKfmEUe8olkz24aakE1wjDPHAtCyu94hZwjd8Z6WzAEa4hq/SDL0BfGRapT0/nK1flnuXlbb78t14OPH/xtrqKv4ZszGjPEP35f7YLkN/K0ZU9UqG2C6IatDsD4E/soMwdHWBhw+4Y3AD9rtrsw3HTyslMp6q196m+D/XlS0NlGOyLkL7k/Odrq/XZ7YQWEmClbhem9fdmBl7WuThdRJvED3aZbB3zFgtd2tb27wSNQlPP96mHtnqlFT4sIcPOvufaB/t82UmY6qo8s/L9CyNs0cnvTJPXh45m/82m25nqmF4y1QwaUU7VuaEvmHLrtiZYvuROxcy6a8ABaD770A33SKnf6YJbTO9dFVtFBcUKVtQ1oyfUbL1TFBGtYHraLtx3/YfmXzpxIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f02da883c63df37ba10256a6669662b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0872:63DFD5F:53EC0C95", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 29 Jul 2014 08:06:26 GMT", "date": "Thu, 14 Aug 2014 01:10:45 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407982128"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/betamax"}, "recorded_at": "2014-08-14T01:10:46"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/betamax/stargazers?per_page=100"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a8d8e492d6966f0c23dee2eed64c678a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"d553fdd5dc93e9b9a93812043b7213ba\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0872:63DFD70:53EC0C95", "cache-control": "public, max-age=60, s-maxage=60", "date": "Thu, 14 Aug 2014 01:10:45 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1407982128"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/betamax/stargazers?per_page=100"}, "recorded_at": "2014-08-14T01:10:46"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index cfe130f5f..22f50aae8 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -381,6 +381,18 @@ def test_refs(self): for ref in references: assert isinstance(ref, github3.git.Reference) + def test_stargazers(self): + """Test the ability to retrieve the stargazers on a repository.""" + cassette_name = self.cassette_name('stargazers') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'betamax') + assert repository is not None + stargazers = list(repository.stargazers()) + + assert len(stargazers) > 0 + for user in stargazers: + assert isinstance(user, github3.users.User) + def test_subscription(self): """Test the ability to subscribe to a repository's notifications.""" self.basic_login() diff --git a/tests/test_repos.py b/tests/test_repos.py index bcb5c1f23..1fccb255e 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,14 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_stargazers(self): - self.response('user', _iter=True) - self.get(self.api + 'stargazers') - - u = next(self.repo.iter_stargazers()) - assert isinstance(u, github3.users.User) - self.mock_assertions() - def test_iter_subscribers(self): self.response('user', _iter=True) self.get(self.api + 'subscribers') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 1f555405c..eb6f0364d 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -546,6 +546,17 @@ def test_releases(self): headers={'Accept': 'application/vnd.github.manifold-preview'} ) + def test_stargazers(self): + """Test the request for retrieving stargazers of a repository.""" + i = self.instance.stargazers() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('stargazers'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From f1d1f78d0e1bf454d17fb669955df8b61ac27980 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Thu, 14 Aug 2014 22:35:21 -0500 Subject: [PATCH 361/972] Rename Repository#iter_subscribers --- HISTORY.rst | 1 + github3/repos/repo.py | 24 ++++++++++----------- tests/cassettes/Repository_subscribers.json | 1 + tests/integration/test_repos_repo.py | 12 +++++++++++ tests/test_repos.py | 8 ------- tests/unit/test_repos_repo.py | 11 ++++++++++ 6 files changed, 37 insertions(+), 20 deletions(-) create mode 100644 tests/cassettes/Repository_subscribers.json diff --git a/HISTORY.rst b/HISTORY.rst index 69fc51df4..e95768fe0 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -90,6 +90,7 @@ Old name New name ``Repository#iter_refs`` ``Repository#refs`` ``Repository#iter_releases`` ``Repository#releases`` ``Repository#iter_stargazers`` ``Repository#stargazers`` +``Repository#iter_subscribers`` ``Repository#subscribers`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 8b5913cc0..a816e718d 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,18 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_subscribers(self, number=-1, etag=None): - r"""Iterate over users subscribed to this repository. - - :param int number: (optional), number of subscribers to return. - Default: -1 returns all subscribers available - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`User ` - """ - url = self._build_url('subscribers', base_url=self._api) - return self._iter(int(number), url, User, etag=etag) - def iter_statuses(self, sha, number=-1, etag=None): r"""Iterate over the statuses for a specific SHA. @@ -1763,6 +1751,18 @@ def subscribe(self): 200) return Subscription(json, self) if json else None + def subscribers(self, number=-1, etag=None): + r"""Iterate over users subscribed to this repository. + + :param int number: (optional), number of subscribers to return. + Default: -1 returns all subscribers available + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`User ` + """ + url = self._build_url('subscribers', base_url=self._api) + return self._iter(int(number), url, User, etag=etag) + @requires_auth def subscription(self): """Return subscription for this Repository. diff --git a/tests/cassettes/Repository_subscribers.json b/tests/cassettes/Repository_subscribers.json new file mode 100644 index 000000000..e8998d55c --- /dev/null +++ b/tests/cassettes/Repository_subscribers.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/betamax"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA6WY346rNhDGXyXittk4Idn8QapOq75AVZ32ojeRAQPWAqa2SZpF++79bEMgUU+yC9JqN0s8P38ez9gzNB6PvWC12qwPu/Vm7pW0YF7ghUzTgv7rzb2kzvNj+1TxtKAnLmvlb0g/RJxLJr2g8XKR8hLWw3FAmBn8zXK/Xs49eqKaymMtc4zLtK5UQIh7qBYp11kd1orJSJSalXoRiYLUxBl/O/3sg5bKlmGwXrTa7Nev23h/SA7+K9se/NVuHzK2ig9rGiU7GNzNVfF2HgfHZIrcCc50kd9JdNKsyd3gROS5OINyv6hnE5GrpXGzpfAyHUmBZUOEzhh8iyV9GEdxpb8uylo1xPw58thwFDZMsvjLwlo7yDLx8dEQySphgXWoIskrzUX5dYE31qAJmdKSv9NxNFgrQIy0r0uxVrBmJ8Tq182dWUMqyU80uhjXSBYxfoKzRyLv7EHUl8ok9J8ICuN6rtmRxoVJ04Tmin3MPTu9xiD7YI6s/Gz0D86AmF23FLP9Ovvrtz9mvODabssM3/K0ZPFMlPlllgg5qy46E+WLZP/UDAG3gDY8fruKeJi01u83eThQYjBP9uLH9shJWEPMG7uMhxjjhuB3m0ERkpuGQlItnh0TD6TdUBoy/NeEjma0GC/ZWoOSCTHBe9YaFK5UzT4Vww/WayGKdFlS1kXoDrbP5MYDrjOHSqpsVLLxXrsSGtKduqGkZZRNYHaAhrhPdm9pOl6kMQYjzEU4HoL7j1hCQ1RG3fWij5N0GaQB3BAlS6aJNIArUcspu2sFGsKVhytNY6PHK+wApGm9mNMyrWk6AXklYI/NlZvS96fFyIPs6BHgmTJM8rCeeG71EKPR3f7I5Qlu7Bk90dYTj6uUR+seFCV25QVur/EKW/ub2J7KNPF4zzX/Py8+Hqy7AzSkP2Dd8d1+M9qj7fndTUCafoK2vJ/iXtsfKNL8VFGdmfMI81RUstFyW3vShBRl0WKxaDJGbQFcMDklQZ05OFRGGYq70QqbDoAipaDaVtSJERijws4Fjcf780oAze3baJXOfBhOFVrI8dKs9RBX8BwloygnnJk9YgguheYJjz7TSTxIqBtK803xMmJzmudzRKfmEUe8olkz24aakE1wjDPHAtCyu94hZwjd8Z6WzAEa4hq/SDL0BfGRapT0/nK1flnuXlbb78t14OPH/xtrqKv4ZszGjPEP35f7YLkN/K0ZU9UqG2C6IatDsD4E/soMwdHWBhw+4Y3AD9rtrsw3HTyslMp6q196m+D/XlS0NlGOyLkL7k/Odrq/XZ7YQWEmClbhem9fdmBl7WuThdRJvED3aZbB3zFgtd2tb27wSNQlPP96mHtnqlFT4sIcPOvufaB/t82UmY6qo8s/L9CyNs0cnvTJPXh45m/82m25nqmF4y1QwaUU7VuaEvmHLrtiZYvuROxcy6a8ABaD770A33SKnf6YJbTO9dFVtFBcUKVtQ1oyfUbL1TFBGtYHraLtx3/YfmXzpxIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "c046d59f93ede9ab52d5ac29f1ed70f7", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f02da883c63df37ba10256a6669662b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4A6E:104F5194:53ED7FDD", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 29 Jul 2014 08:06:26 GMT", "date": "Fri, 15 Aug 2014 03:34:53 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408077293"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/betamax"}, "recorded_at": "2014-08-15T03:34:53"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/betamax/subscribers?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63Y0W6bMBgF4HfhuirGYGxXqvYUu5qm6gebxGoCERiqLuq7z4Q0dliUxZirVpXP4YTmUyJ+HaNds1F19BJ1arOHQbV9h7PoKVIiesEZYil6imAADe1b3+7Mua3Wh+4ljqc/ds8bpbd90XeyLZtay1o/l80+7uMp/GN4xaZt0547xtqoTDKWklwwXnFMZM5xQlkhZSJ4CmVFTWB2rYM6X2cqNxfr4tngrd7vZhOnaafI7HDV7HbNh2mZv6j/XSi+JM3I6XdVbxa2mOQxbvRWmntrXtLXeKNUp/1HnVLHePzxpsTY05l/WCuF97Bzzsz6qM2iY9zKQ3Mq7IuubNVBq6b2H3iVNm1Nu4Fa/YFlbSbdmZJxmv+UU8qk5WDeq/7xKXaMD60aoPwcb00rS6kGc7MXVs7yplF/HqRx8tO8KcZbr7R8A7EfmVaw6+TXk2UrOyi1fO+gMCdHXTnjhCcL0U7hm2iRJDLBgpRZxbiUWUowrRgCQTIiSZGayz+A9mrufbJXR73A2uRyrv90hGB1yoKoOj3rQXVLXeRLmDpdvkidqD9RJ7wO0Ks1V7z9eHZQb+AsEyPGFrocozdVppCwlEnCSYZzluUZLhGAzJK8opQn8jGV3yvvg/w+5WXxFFrO0I2HCJx6gvBNFeu5O/eFkptqfLVNKX9oU24dY98bAni1UIHoW6jPxFhOs5wvRDaFbzLjkgDgrMhFyXGFSIXLohIICkQ5yDR/jJm79j4196QXt0twObl5RQg72xVEz9asx8/pDCVoq3wZ2qQ/RZtdh6O7JYBkX2ul4f30zXX8PspSSmi6lOQpfJNkAoLRokApSrH5BJSM5pBkVEApCKGQPEbSXXufpHvSi+QluJzkvCKEpO0KImlr1iPpdIaStFW+JG3Sn6TNrkPS3RJA8l0Oqk6Qfa6TIL70QxKP2Zsgi7QwT3EgAfPRiHgBGGHOqMDjQ52C4uoxkO7W+yDdk14gL8HlIOcVISBtVxBIW7MeSKczFKSt8gVpk/4gbXYdkO4WX5C//wIj/RQObRUAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"21a6e1911b1320d7e6e970a857e62b23\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:4A6E:104F51CE:53ED7FDD", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 15 Aug 2014 03:34:53 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408077293"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/betamax/subscribers?per_page=100"}, "recorded_at": "2014-08-15T03:34:53"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 22f50aae8..f66b7a61d 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -393,6 +393,18 @@ def test_stargazers(self): for user in stargazers: assert isinstance(user, github3.users.User) + def test_subscribers(self): + """Test the ability to retrieve a repository's subscribers.""" + cassette_name = self.cassette_name('subscribers') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'betamax') + assert repository is not None + subscribers = list(repository.subscribers()) + + assert len(subscribers) > 0 + for user in subscribers: + assert isinstance(user, github3.users.User) + def test_subscription(self): """Test the ability to subscribe to a repository's notifications.""" self.basic_login() diff --git a/tests/test_repos.py b/tests/test_repos.py index 1fccb255e..60f5265ca 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,14 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_subscribers(self): - self.response('user', _iter=True) - self.get(self.api + 'subscribers') - - u = next(self.repo.iter_subscribers()) - assert isinstance(u, github3.users.User) - self.mock_assertions() - def test_iter_statuses(self): self.response('status', _iter=True) self.get(self.api + 'statuses/fakesha') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index eb6f0364d..2e4128454 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -557,6 +557,17 @@ def test_stargazers(self): headers={} ) + def test_subscribers(self): + """Test the request for retrieving subscribers to a repository.""" + i = self.instance.subscribers() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('subscribers'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From d4a4ac048a1f9220cae5664a6eaedec64629addf Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 15 Aug 2014 08:32:54 -0500 Subject: [PATCH 362/972] Rename Repository#iter_statuses --- HISTORY.rst | 1 + github3/repos/repo.py | 30 ++++++++++++------------ tests/cassettes/Repository_statuses.json | 1 + tests/integration/test_repos_repo.py | 14 +++++++++++ tests/test_repos.py | 12 ---------- tests/unit/test_repos_repo.py | 18 ++++++++++++++ 6 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 tests/cassettes/Repository_statuses.json diff --git a/HISTORY.rst b/HISTORY.rst index e95768fe0..4f6159abc 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -91,6 +91,7 @@ Old name New name ``Repository#iter_releases`` ``Repository#releases`` ``Repository#iter_stargazers`` ``Repository#stargazers`` ``Repository#iter_subscribers`` ``Repository#subscribers`` +``Repository#iter_statuses`` ``Repository#statuses`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index a816e718d..1acc94dd2 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,21 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_statuses(self, sha, number=-1, etag=None): - r"""Iterate over the statuses for a specific SHA. - - :param str sha: SHA of the commit to list the statuses of - :param int number: (optional), return up to number statuses. Default: - -1 returns all available statuses. - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Status ` - """ - url = '' - if sha: - url = self._build_url('statuses', sha, base_url=self._api) - return self._iter(int(number), url, Status, etag=etag) - def iter_tags(self, number=-1, etag=None): r"""Iterate over tags on this repository. @@ -1736,6 +1721,21 @@ def stargazers(self, number=-1, etag=None): url = self._build_url('stargazers', base_url=self._api) return self._iter(int(number), url, User, etag=etag) + def statuses(self, sha, number=-1, etag=None): + r"""Iterate over the statuses for a specific SHA. + + :param str sha: SHA of the commit to list the statuses of + :param int number: (optional), return up to number statuses. Default: + -1 returns all available statuses. + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Status ` + """ + url = '' + if sha: + url = self._build_url('statuses', sha, base_url=self._api) + return self._iter(int(number), url, Status, etag=etag) + @requires_auth def subscribe(self): """Subscribe the user to this repository's notifications. diff --git a/tests/cassettes/Repository_statuses.json b/tests/cassettes/Repository_statuses.json new file mode 100644 index 000000000..71f8c9f46 --- /dev/null +++ b/tests/cassettes/Repository_statuses.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY/iOBCG/wrKdWlMSNNApNHMnnb3Nofey16QkzjE6iSObAdER/3f93Uc8sFogW6v1EKQdj1+Xa5yqtx4PPHCYOMvN74/90paMC/0DlxndRQsqrM399I6z/fdPxQ/FPTIZa1Wz2QySpxKJr2w8XJx4CUY46GgmGlWz8ttsJx79Eg1lfta5hiXaV2pkBD7UC0stVZMxqLUrNSLWBSkJtb4+/HbCrSD7BgG68X+8zZYvyTbXbpbrdnLbuVvthFjfrILaJxuYHA1V8W7eSwckylyJTjTRX4l0UprTa4GpyLPxQmU60Xdm4j0lsbTLYWXhy9SYNkQoTMG32JJH8ZRXOnPi2qtGmyw0nueGI7ChkmWfFpYZwdZJj4+GiJZJVpgHalY8kpzUX5e4MQaNCEPtOTv9Gs0WCtAjLTPS2mtYM2OiNXPm1uzhlSSH2l8Nq6RLGb8CGd/EXllD6I+Vyat/0ZQGNdzzfY0KUyapjRX7GPutdNrDGofzJGVj0b/9BhIWL+rmPDnWWeinOU8klSeZ6mQM46climNEauzE46ZGcJ19gfXf9bR7Peffx0DCMS4t17JzcxtnT9JxqkcQ7qzJzcRSE8AIOmNnZ04xr4h+OzyKUaq00hIqsW9Q+O2wAmoIeOfJpY0o4WT8BYAUCaEmydbAEBcqZo9FNq3F95yFLnkT1kXkT3yHsma22hLgFaqcM6XjDl5sIc05HIqIx3KOHPDXhgNsd/a3aYHJ6nGHpgoF5ETBy9K0kIaojJq30N676rOUA1jApUsdZZqGD1US8f9bmUaSI/ES1Bj6510Xhik6Tya0/JQ04MbtYdg182r+kDf7xYxt3NnoABpKjjJo9r9kBs4RqmtHZDvbi4dMAO0LUhulzl3HDAqbFoXFAW/VxfcJnaISdj/D1gTp9do8/t+GXNfrmE0ZDiT7aHf0V282536F52kGebo2gWnkLgwSPNbRXVmTi5MVVHJXER3CNJEFMXWYrFoMkbbsrpg0jGDLQEoKuMMVaOLzubCQNVTUN1W66mRmaB6zwVNnHzbQwC02+ii1RLGMVahT3US2ALGxILnTGlRup2xA2XMLoXmKY8f6Vhup9sE1HxXvIzZnOb5HFGrecwRx6i1zS6i4GRuHrIELAPXBLZTyRlC2snrkllGQ2ynGUuGRiTZU40GYrX0V0/L4MkPXv1duN6G6+AfrKSuksmY56flFn+v/iZcrcL10oypapWNMO0Qf/26DMJgHa5aDE7ALgTxDVcQ+MS1xy/9/ailMLcGMFQqGwx/DGbhf9yPdGZxjli6CvrH5zxev5bum0JqJgpWoUzoblr6VQbVeQFPJ2i/EhGrBXpgYlbG3zF0F+zWk4IgFnWJ/fB3L3PvRDVqV7x6xw8vhUTf9JmpqdrbNPVCLWvTVeLJcAyMHp74G+87Ptu0dfQN7osKLqXo7otKJCn6/YqVHXuQYRtH5YXGZjTC6B5kd6tIWErrXO9t8QzZCar+XFTQXTJ9Qtt3ARvauOK4LHv78S+H46tiPRMAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "88d924ed861736d2749ce1a55766cb53", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"1a9c32db89ead2eaffaa8583e11bbffc\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0875:1129C3F8:53EE08E5", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 08 Aug 2014 17:22:50 GMT", "date": "Fri, 15 Aug 2014 13:19:34 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408112374"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-15T13:19:34"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/statuses/0cea3860f91717272a5edb3961e9723b70769084?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1WTY/bIBD9K5HPScDG31LVQ0+9p5dWVYSBOEiOsQB7m1r57x3sTZRkt428l375ZsG8x7xh5pkvvdfqysu9vbWNyRGijVyX0u7bYs3UAWnRKIOMLA+0k7o1QYjGXbJujshYalsjDMJMUJLGeJf5iZ8ESUAjwQuSxb7IkoAUCU7iDKeht/Qk9/LMh60kzJaeYxBwvGkZE8bAPheGadlYqWpY3+zFYqPhbLP48HFRtLLii4YaIziEWqpLYbe3AuwQvWJyrXT508wHJoNIEOMwxS4vpmorvlk4033JulWtWUlYKzV1yaALsQvWAvLmW+riA+yHK5yu/GiDSU6ynKSfIaZt+MOYgUdpL++9SpXSKb6u9XO5ghCnBC892lGQfKd3XDTPlwa3oQcltR3ur0Uj+H33LgA20DJyuFvwmB+mJIp5mu2yIBJxFvhJWgjh84xQtkuciF81hzvstjkAsbeH6i7Fq366U7dTVaWegOVe1G0XvjwIXZBw5Pgt6/KNLIDskbJ7AbUFSSdXKGns9KQGVA8TYuxWcscD/a01NMrEOrrJcjhI66mGjPphEAfCtrjMx/QEb9DABiNCa/l9aPDpbIB2Ezt4xGSFAwrQooNenQ4fYT1qtOwoO7rSaMGE7KDYb6S8wwOjPTbOnD5BU7jSSyu2lB/cmO5oZcTptPx99unH4Ahn+2xEzaGLIcnH9glWKutFo1WpR8f9M200zv3wkY2eY2YbnW0U/nUvfkezjd485l4p0H9vozi6eoX+gzYa5YQ8stFzzGyjs43ONvr3vka//gCaRwUwzg8AAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"215b076ae6a41559d68521911ec09cf0\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0875:1129C44C:53EE08E6", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 15 Aug 2014 13:19:34 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408112374"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/statuses/0cea3860f91717272a5edb3961e9723b70769084?per_page=100"}, "recorded_at": "2014-08-15T13:19:34"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index f66b7a61d..c95325a7f 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -393,6 +393,20 @@ def test_stargazers(self): for user in stargazers: assert isinstance(user, github3.users.User) + def test_statuses(self): + """Test the ability to retrieve a commit's statuses.""" + cassette_name = self.cassette_name('statuses') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'github3.py') + assert repository is not None + statuses = list(repository.statuses( + '0cea3860f91717272a5edb3961e9723b70769084' + )) + + assert len(statuses) > 0 + for status in statuses: + assert isinstance(status, github3.repos.status.Status) + def test_subscribers(self): """Test the ability to retrieve a repository's subscribers.""" cassette_name = self.cassette_name('subscribers') diff --git a/tests/test_repos.py b/tests/test_repos.py index 60f5265ca..db315d4df 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,18 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_statuses(self): - self.response('status', _iter=True) - self.get(self.api + 'statuses/fakesha') - - with self.assertRaises(StopIteration): - next(self.repo.iter_statuses(None)) - self.not_called() - - s = next(self.repo.iter_statuses('fakesha')) - assert isinstance(s, repos.status.Status) - self.mock_assertions() - def test_iter_tags(self): self.response('tag', _iter=True) self.get(self.api + 'tags') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index 2e4128454..c225989c4 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -557,6 +557,24 @@ def test_stargazers(self): headers={} ) + def test_statuses(self): + """Test the request for retrieiving statuses of a commit.""" + i = self.instance.statuses('fake-sha') + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('statuses/fake-sha'), + params={'per_page': 100}, + headers={} + ) + + def test_statuses_requires_a_sha(self): + """Test the request is made only if given a SHA.""" + i = self.instance.statuses('') + self.get_next(i) + + assert self.session.get.called is False + def test_subscribers(self): """Test the request for retrieving subscribers to a repository.""" i = self.instance.subscribers() From c0d04a806be1e34f287ee11d0ed8767efb091841 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 15 Aug 2014 20:37:38 -0500 Subject: [PATCH 363/972] Rename Repository#iter_tags --- HISTORY.rst | 1 + github3/repos/repo.py | 24 ++++++++++++------------ tests/integration/test_repos_repo.py | 12 ++++++++++++ tests/test_repos.py | 11 ----------- tests/unit/test_repos_repo.py | 11 +++++++++++ 5 files changed, 36 insertions(+), 23 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 4f6159abc..02a339eb2 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -92,6 +92,7 @@ Old name New name ``Repository#iter_stargazers`` ``Repository#stargazers`` ``Repository#iter_subscribers`` ``Repository#subscribers`` ``Repository#iter_statuses`` ``Repository#statuses`` +``Repository#iter_tags`` ``Repository#tags`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index 1acc94dd2..f892c214d 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,18 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - def iter_tags(self, number=-1, etag=None): - r"""Iterate over tags on this repository. - - :param int number: (optional), return up to at most number tags. - Default: -1 returns all available tags. - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`RepoTag `\ s - """ - url = self._build_url('tags', base_url=self._api) - return self._iter(int(number), url, RepoTag, etag=etag) - @requires_auth def iter_teams(self, number=-1, etag=None): r"""Iterate over teams with access to this repository. @@ -1787,6 +1775,18 @@ def tag(self, sha): json = self._json(self._get(url), 200) return Tag(json) if json else None + def tags(self, number=-1, etag=None): + r"""Iterate over tags on this repository. + + :param int number: (optional), return up to at most number tags. + Default: -1 returns all available tags. + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`RepoTag `\ s + """ + url = self._build_url('tags', base_url=self._api) + return self._iter(int(number), url, RepoTag, etag=etag) + def tree(self, sha): """Get a tree. diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index c95325a7f..44308fb26 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -428,3 +428,15 @@ def test_subscription(self): assert repository is not None subscription = repository.subscribe() assert subscription.subscribed is True + + def test_tags(self): + """Test the ability to retrieve a repository's tags.""" + cassette_name = self.cassette_name('tags') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('sigmavirus24', 'betamax') + assert repository is not None + tags = list(repository.tags()) + + assert len(tags) > 0 + for tag in tags: + assert isinstance(tag, github3.repos.tag.RepoTag) diff --git a/tests/test_repos.py b/tests/test_repos.py index db315d4df..3e765401c 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,17 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_tags(self): - self.response('tag', _iter=True) - self.get(self.api + 'tags') - - t = next(self.repo.iter_tags()) - assert isinstance(t, repos.tag.RepoTag) - self.mock_assertions() - - assert repr(t).startswith(' '' - def test_iter_teams(self): self.response('team', _iter=True) self.get(self.api + 'teams') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index c225989c4..b881c2d75 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -586,6 +586,17 @@ def test_subscribers(self): headers={} ) + def test_tags(self): + """Test the request for retrieving tags in a repository.""" + i = self.instance.tags() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('tags'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): From bd8a63232f2f2ecc522a941512e4d5fca75d2e4f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 15 Aug 2014 21:04:51 -0500 Subject: [PATCH 364/972] Add a docstring for Repository#key test --- tests/integration/test_repos_repo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index 44308fb26..bf0bbf6cd 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -233,6 +233,7 @@ def test_issues_accepts_state_all(self): assert issue.state in ('open', 'closed') def test_key(self): + """Test the retrieval of a single key.""" self.basic_login() cassette_name = self.cassette_name('key') with self.recorder.use_cassette(cassette_name): From c8ea69c440b45fca11254bf78b0039f52ff74557 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 15 Aug 2014 21:24:34 -0500 Subject: [PATCH 365/972] Add missing cassette --- tests/cassettes/Repository_tags.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/cassettes/Repository_tags.json diff --git a/tests/cassettes/Repository_tags.json b/tests/cassettes/Repository_tags.json new file mode 100644 index 000000000..8d6db67d2 --- /dev/null +++ b/tests/cassettes/Repository_tags.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/betamax"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA6WY346rNhDGXyXittk4Idn8QapOq75AVZ32ojeRAQPWAqa2SZpF++79bEMgUU+yC9JqN0s8P38ez9gzNB6PvWC12qwPu/Vm7pW0YF7ghUzTgv7rzb2kzvNj+1TxtKAnLmvlb0g/RJxLJr2g8XKR8hLWw3FAmBn8zXK/Xs49eqKaymMtc4zLtK5UQIh7qBYp11kd1orJSJSalXoRiYLUxBl/O/3sg5bKlmGwXrTa7Nev23h/SA7+K9se/NVuHzK2ig9rGiU7GNzNVfF2HgfHZIrcCc50kd9JdNKsyd3gROS5OINyv6hnE5GrpXGzpfAyHUmBZUOEzhh8iyV9GEdxpb8uylo1xPw58thwFDZMsvjLwlo7yDLx8dEQySphgXWoIskrzUX5dYE31qAJmdKSv9NxNFgrQIy0r0uxVrBmJ8Tq182dWUMqyU80uhjXSBYxfoKzRyLv7EHUl8ok9J8ICuN6rtmRxoVJ04Tmin3MPTu9xiD7YI6s/Gz0D86AmF23FLP9Ovvrtz9mvODabssM3/K0ZPFMlPlllgg5qy46E+WLZP/UDAG3gDY8fruKeJi01u83eThQYjBP9uLH9shJWEPMG7uMhxjjhuB3m0ERkpuGQlItnh0TD6TdUBoy/NeEjma0GC/ZWoOSCTHBe9YaFK5UzT4Vww/WayGKdFlS1kXoDrbP5MYDrjOHSqpsVLLxXrsSGtKduqGkZZRNYHaAhrhPdm9pOl6kMQYjzEU4HoL7j1hCQ1RG3fWij5N0GaQB3BAlS6aJNIArUcspu2sFGsKVhytNY6PHK+wApGm9mNMyrWk6AXklYI/NlZvS96fFyIPs6BHgmTJM8rCeeG71EKPR3f7I5Qlu7Bk90dYTj6uUR+seFCV25QVur/EKW/ub2J7KNPF4zzX/Py8+Hqy7AzSkP2Dd8d1+M9qj7fndTUCafoK2vJ/iXtsfKNL8VFGdmfMI81RUstFyW3vShBRl0WKxaDJGbQFcMDklQZ05OFRGGYq70QqbDoAipaDaVtSJERijws4Fjcf780oAze3baJXOfBhOFVrI8dKs9RBX8BwloygnnJk9YgguheYJjz7TSTxIqBtK803xMmJzmudzRKfmEUe8olkz24aakE1wjDPHAtCyu94hZwjd8Z6WzAEa4hq/SDL0BfGRapT0/nK1flnuXlbb78t14OPH/xtrqKv4ZszGjPEP35f7YLkN/K0ZU9UqG2C6IatDsD4E/soMwdHWBhw+4Y3AD9rtrsw3HTyslMp6q196m+D/XlS0NlGOyLkL7k/Odrq/XZ7YQWEmClbhem9fdmBl7WuThdRJvED3aZbB3zFgtd2tb27wSNQlPP96mHtnqlFT4sIcPOvufaB/t82UmY6qo8s/L9CyNs0cnvTJPXh45m/82m25nqmF4y1QwaUU7VuaEvmHLrtiZYvuROxcy6a8ABaD770A33SKnf6YJbTO9dFVtFBcUKVtQ1oyfUbL1TFBGtYHraLtx3/YfmXzpxIAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0f02da883c63df37ba10256a6669662b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0874:FDD91AB:53EEB522", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 29 Jul 2014 08:06:26 GMT", "date": "Sat, 16 Aug 2014 01:34:26 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408156466"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/betamax"}, "recorded_at": "2014-08-16T01:34:27"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/betamax/tags?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63X3W7bMAwF4HfJdWFL1B/VVxmGgaSoNkCzBklaDCvy7pOadludXRirLhNA59gfCNr+8rL5Tjvd3G6ezWSnuLnZ/NzumR4evj0dHtrf96fT/ng7z7TfTnfb0/0TT/K4mw+6fzzOx+3djp63h6cj+Jn1RDv6Mb+dn38HnujwqcC3838C2wXstqfN7cvmeE/tGkPOVTOXHJWTiBZXULKzUSqQlkglhCTQb+5/b+pSeZxXV53PNx9pw2jaHjiUtgcuaclXyg21Go+WvYTAmiWBxVJNNTZhLlBTGUC7uuqK1o+m7YFDaXvgkrZgQBsLmIhUK4eCqdYQQVxOwlZ8RqQGPIB2ddUVrRtN2wOH0vbAJa2oh6IZK8dEHoNwtupZY3TWZhYBglKYBtCurrqihdG0PXAobQ9c0iZG5JAi+1CdySqsSl7AqoLNlq0jdgB94D+7a1dXXdHa0bQ9cChtD1zSGkVLxaJLJtnggpJAthIUc8pZJBuQkLEf/Szt6qol7WDYwaz/QAXvTajegbK1vrafAXJF5TapKSTvfURgGrEKVlf9jWomP5mBqu95o6b1PW85rKxYEmGNpAAmRZ+dNuNaE5KpKN437VL6dv7ssK6u+ujqppEb1kyXvHGul7ylaxvOYJkZyAUGhZS8ETUA1ZuSnGlLQU0cM69rq5auI9drdx25Xd/zlq6pmkIA4GxyIbHx0ka3vccyZiJv2yMteAAZsVxXVy1dx+4B97pXRs5rz1u65hSofW/J6yMqMQhhKQLqyUGoERHbl5nyiPeB1VUfXWHwfr3kjXO95C1dKxgVjMUpoTo2jZSkeDHRpVQ4gZZAijxgv66uOp+//gJf2sFcMBAAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"88ce86c6e5a576fc2f90b556d467243a\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0874:FDD91D1:53EEB522", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Tue, 29 Jul 2014 08:06:26 GMT", "date": "Sat, 16 Aug 2014 01:34:26 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408156466"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/betamax/tags?per_page=100"}, "recorded_at": "2014-08-16T01:34:27"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file From d6e3d154f5b7de230b7e1ff6db1088b5a82ec8a5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 15 Aug 2014 21:24:53 -0500 Subject: [PATCH 366/972] Rename Repository#iter_teams --- HISTORY.rst | 1 + github3/repos/repo.py | 28 +++++++++++++-------------- tests/cassettes/Repository_teams.json | 1 + tests/integration/test_repos_repo.py | 13 +++++++++++++ tests/test_repos.py | 12 ------------ tests/unit/test_repos_repo.py | 16 +++++++++++++++ 6 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 tests/cassettes/Repository_teams.json diff --git a/HISTORY.rst b/HISTORY.rst index 02a339eb2..3eac827ee 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -93,6 +93,7 @@ Old name New name ``Repository#iter_subscribers`` ``Repository#subscribers`` ``Repository#iter_statuses`` ``Repository#statuses`` ``Repository#iter_tags`` ``Repository#tags`` +``Repository#iter_teams`` ``Repository#teams`` ========================================== ============================================== diff --git a/github3/repos/repo.py b/github3/repos/repo.py index f892c214d..75be9abeb 100644 --- a/github3/repos/repo.py +++ b/github3/repos/repo.py @@ -1410,20 +1410,6 @@ def latest_pages_build(self): json = self._json(self._get(url), 200) return PagesBuild(json) if json else None - @requires_auth - def iter_teams(self, number=-1, etag=None): - r"""Iterate over teams with access to this repository. - - :param int number: (optional), return up to number Teams. Default: -1 - returns all Teams. - :param str etag: (optional), ETag from a previous request to the same - endpoint - :returns: generator of :class:`Team `\ s - """ - from ..orgs import Team - url = self._build_url('teams', base_url=self._api) - return self._iter(int(number), url, Team, etag=etag) - @requires_auth def mark_notifications(self, last_read=''): """Mark all notifications in this repository as read. @@ -1787,6 +1773,20 @@ def tags(self, number=-1, etag=None): url = self._build_url('tags', base_url=self._api) return self._iter(int(number), url, RepoTag, etag=etag) + @requires_auth + def teams(self, number=-1, etag=None): + r"""Iterate over teams with access to this repository. + + :param int number: (optional), return up to number Teams. Default: -1 + returns all Teams. + :param str etag: (optional), ETag from a previous request to the same + endpoint + :returns: generator of :class:`Team `\ s + """ + from github3.orgs import Team + url = self._build_url('teams', base_url=self._api) + return self._iter(int(number), url, Team, etag=etag) + def tree(self, sha): """Get a tree. diff --git a/tests/cassettes/Repository_teams.json b/tests/cassettes/Repository_teams.json new file mode 100644 index 000000000..24ed3c2e2 --- /dev/null +++ b/tests/cassettes/Repository_teams.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/github3py/github3.py"}, "response": {"body": {"string": "", "base64_string": "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", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "6d7de9e645814cac34ea2a8d72ba3141", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"0ff80bc7bd4af0965a8b62f11b62fb45\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4943", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0875:12769BC7:53EEC084", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Fri, 25 Apr 2014 01:02:57 GMT", "date": "Sat, 16 Aug 2014 02:23:01 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408158007"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/github3py/github3.py"}, "recorded_at": "2014-08-16T02:23:01"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic "}, "method": "GET", "uri": "https://api.github.com/repos/github3py/github3.py/teams?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA5WOMQ7CMAwA/+K5asLYrDwDIZQUq7VUJ1HsTFX/jgVd2GCz5buTbzvkyAgBriVro9S1NIEB6AnhMnnvpwFk64sR8zdRsTGJUMl2q11Ws3rbbFlVqwTnYqVxIV17GufCTjGyuE/UWEZO2OTxs+NOYz+HwyINaxGynwn/Kb01OO4vnvRpt/8AAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "x-served-by": "d818ddef80f4c7d10683dd483558952a", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"34d0bb2f7c4412b29a2657f31cd458e5\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "4942", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0875:12769C19:53EEC085", "cache-control": "private, max-age=60, s-maxage=60", "date": "Sat, 16 Aug 2014 02:23:01 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "5000", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408158007"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/github3py/github3.py/teams?per_page=100"}, "recorded_at": "2014-08-16T02:23:01"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_repos_repo.py b/tests/integration/test_repos_repo.py index bf0bbf6cd..93d5580f9 100644 --- a/tests/integration/test_repos_repo.py +++ b/tests/integration/test_repos_repo.py @@ -441,3 +441,16 @@ def test_tags(self): assert len(tags) > 0 for tag in tags: assert isinstance(tag, github3.repos.tag.RepoTag) + + def test_teams(self): + """Test the ability to retrieve teams assigned to a repo.""" + self.basic_login() + cassette_name = self.cassette_name('teams') + with self.recorder.use_cassette(cassette_name): + repository = self.gh.repository('github3py', 'github3.py') + assert repository is not None + teams = list(repository.teams()) + + assert len(teams) > 0 + for team in teams: + assert isinstance(team, github3.orgs.Team) diff --git a/tests/test_repos.py b/tests/test_repos.py index 3e765401c..0d9cb4c82 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -537,18 +537,6 @@ def test_label(self): assert isinstance(self.repo.label('name'), github3.issues.label.Label) self.mock_assertions() - def test_iter_teams(self): - self.response('team', _iter=True) - self.get(self.api + 'teams') - - self.assertRaises(github3.GitHubError, self.repo.iter_teams) - self.not_called() - - self.login() - t = next(self.repo.iter_teams()) - assert isinstance(t, github3.orgs.Team) - self.mock_assertions() - def test_mark_notifications(self): self.response('', 205) self.put(self.api + 'notifications') diff --git a/tests/unit/test_repos_repo.py b/tests/unit/test_repos_repo.py index b881c2d75..4b602504b 100644 --- a/tests/unit/test_repos_repo.py +++ b/tests/unit/test_repos_repo.py @@ -597,6 +597,17 @@ def test_tags(self): headers={} ) + def test_teams(self): + """Test the request for retrieving teams on a repository.""" + i = self.instance.teams() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('teams'), + params={'per_page': 100}, + headers={} + ) + class TestRepositoryRequiresAuth(UnitHelper): @@ -633,3 +644,8 @@ def test_pages_builds(self): """Show that a user must be authenticated to list their builds.""" with pytest.raises(GitHubError): self.instance.pages_builds() + + def test_teams(self): + """Show that a user must be authenticated to list teams on a repo.""" + with pytest.raises(GitHubError): + self.instance.teams() From 50bc6891ef97763f71eea3d3bf3fcbe5726e2470 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 14:37:27 -0500 Subject: [PATCH 367/972] Use helper function --- HISTORY.rst | 16 ++++++++++++++++ github3/issues/issue.py | 2 +- tests/unit/test_pulls.py | 14 +++----------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 3eac827ee..4c08065f5 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -236,6 +236,22 @@ Old name New attribute name - ``Repository.stargazers`` is now ``Repository.stargazers_count`` (conforming with the attribute name returned by the API). + +- The ``Issue`` API has changed in order to provide a more consistent attribute + API. ``Issue.comments`` is now ``Issue.comments_count`` and returns the + number of comments on an issue. + +- The ``Issue.labels`` attribute has also been renamed. It is now available from + ``Issue.original_labels``. This will provide the user with the list of + ``Label`` objects that was returned by the API. To retrieve an updated list + of labels, the user can now use ``Issue#labels``, e.g. + + :: + + i = github3.issue('sigmavirus24', 'github3.py', 30) + labels = list(i.labels()) + + 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ diff --git a/github3/issues/issue.py b/github3/issues/issue.py index 92c53b04d..422419ed8 100644 --- a/github3/issues/issue.py +++ b/github3/issues/issue.py @@ -51,7 +51,7 @@ def __init__(self, issue, session=None): self.closed_at = self._strptime(issue.get('closed_at')) #: Number of comments on this issue. - self.comments = issue.get('comments') + self.comments_count = issue.get('comments') #: Comments url (not a template) self.comments_url = issue.get('comments_url') #: datetime object representing when the issue was created. diff --git a/tests/unit/test_pulls.py b/tests/unit/test_pulls.py index 19d95fb9e..5840d8343 100644 --- a/tests/unit/test_pulls.py +++ b/tests/unit/test_pulls.py @@ -1,21 +1,13 @@ """Unit tests for the github3.pulls module.""" -import json -import os import pytest -from .helper import UnitHelper, UnitIteratorHelper, create_url_helper +from .helper import (UnitHelper, UnitIteratorHelper, create_url_helper, + create_example_data_helper) from github3 import GitHubError from github3.pulls import PullRequest - -def get_pr_example_data(): - """Load the example data for the PullRequest object.""" - directory = os.path.dirname(__file__) - example = os.path.join(directory, 'pull_request_example') - with open(example) as fd: - data = json.load(fd) - return data +get_pr_example_data = create_example_data_helper('pull_request_example') url_for = create_url_helper( From 804ff5058a7ee551217eebb8f2c358e5584645a3 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 15:04:52 -0500 Subject: [PATCH 368/972] Rename Issue#iter_comments --- HISTORY.rst | 1 + github3/issues/issue.py | 20 ++--- tests/cassettes/Issue_comments.json | 1 + tests/integration/test_issue.py | 16 ++++ tests/test_issues.py | 7 -- tests/unit/issue_example_data | 113 ++++++++++++++++++++++++++++ tests/unit/test_issues_issue.py | 30 ++++++++ 7 files changed, 171 insertions(+), 17 deletions(-) create mode 100644 tests/cassettes/Issue_comments.json create mode 100644 tests/unit/issue_example_data create mode 100644 tests/unit/test_issues_issue.py diff --git a/HISTORY.rst b/HISTORY.rst index 4c08065f5..4ff9a13aa 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -55,6 +55,7 @@ Old name New name ``GitHub#iter_repos`` ``GitHub#reposistories`` ``GitHub#iter_user_repos`` ``GitHub#repositories_by`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` +``Issue#iter_comments`` ``Issue#comments`` ``Organization#iter_members`` ``Organization#members`` ``Organization#iter_public_members`` ``Organization#public_members`` ``Organization#iter_repos`` ``Organization#repositories`` diff --git a/github3/issues/issue.py b/github3/issues/issue.py index 422419ed8..631e15a40 100644 --- a/github3/issues/issue.py +++ b/github3/issues/issue.py @@ -157,6 +157,16 @@ def comment(self, id_num): json = self._json(self._get(url), 200) return IssueComment(json) if json else None + def comments(self, number=-1): + r"""Iterate over the comments on this issue. + + :param int number: (optional), number of comments to iterate over + :returns: iterator of + :class:`IssueComment `\ s + """ + url = self._build_url('comments', base_url=self._api) + return self._iter(int(number), url, IssueComment) + @requires_auth def create_comment(self, body): """Create a comment on this issue. @@ -211,16 +221,6 @@ def is_closed(self): return True return False - def iter_comments(self, number=-1): - """Iterate over the comments on this issue. - - :param int number: (optional), number of comments to iterate over - :returns: iterator of - :class:`IssueComment `\ s - """ - url = self._build_url('comments', base_url=self._api) - return self._iter(int(number), url, IssueComment) - def iter_events(self, number=-1): """Iterate over events associated with this issue only. diff --git a/tests/cassettes/Issue_comments.json b/tests/cassettes/Issue_comments.json new file mode 100644 index 000000000..f25876fd0 --- /dev/null +++ b/tests/cassettes/Issue_comments.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA62YTY/iOBCG/wrKdWlMSNNApNHMnnb3Nofey16QkzjE6iSObAdER/3f93Uc8sFogW6v1EKQdj1+Xa5yqtx4PPHCYOMvN74/90paMC/0DlxndRQsqrM399I6z/fdPxQ/FPTIZa1Wz2QySpxKJr2w8XJx4CUY46GgmGlWz8ttsJx79Eg1lfta5hiXaV2pkBD7UC0stVZMxqLUrNSLWBSkJtb4+/HbCrSD7BgG68X+8zZYvyTbXbpbrdnLbuVvthFjfrILaJxuYHA1V8W7eSwckylyJTjTRX4l0UprTa4GpyLPxQmU60Xdm4j0lsbTLYWXhy9SYNkQoTMG32JJH8ZRXOnPi2qtGmyw0nueGI7ChkmWfFpYZwdZJj4+GiJZJVpgHalY8kpzUX5e4MQaNCEPtOTv9Gs0WCtAjLTPS2mtYM2OiNXPm1uzhlSSH2l8Nq6RLGb8CGd/EXllD6I+Vyat/0ZQGNdzzfY0KUyapjRX7GPutdNrDGofzJGVj0b/9BhIWL+rmPDnWWeinOU8klSeZ6mQM46climNEauzE46ZGcJ19gfXf9bR7Peffx0DCMS4t17JzcxtnT9JxqkcQ7qzJzcRSE8AIOmNnZ04xr4h+OzyKUaq00hIqsW9Q+O2wAmoIeOfJpY0o4WT8BYAUCaEmydbAEBcqZo9FNq3F95yFLnkT1kXkT3yHsma22hLgFaqcM6XjDl5sIc05HIqIx3KOHPDXhgNsd/a3aYHJ6nGHpgoF5ETBy9K0kIaojJq30N676rOUA1jApUsdZZqGD1US8f9bmUaSI/ES1Bj6510Xhik6Tya0/JQ04MbtYdg182r+kDf7xYxt3NnoABpKjjJo9r9kBs4RqmtHZDvbi4dMAO0LUhulzl3HDAqbFoXFAW/VxfcJnaISdj/D1gTp9do8/t+GXNfrmE0ZDiT7aHf0V282536F52kGebo2gWnkLgwSPNbRXVmTi5MVVHJXER3CNJEFMXWYrFoMkbbsrpg0jGDLQEoKuMMVaOLzubCQNVTUN1W66mRmaB6zwVNnHzbQwC02+ii1RLGMVahT3US2ALGxILnTGlRup2xA2XMLoXmKY8f6Vhup9sE1HxXvIzZnOb5HFGrecwRx6i1zS6i4GRuHrIELAPXBLZTyRlC2snrkllGQ2ynGUuGRiTZU40GYrX0V0/L4MkPXv1duN6G6+AfrKSuksmY56flFn+v/iZcrcL10oypapWNMO0Q/+V1ucI1RLh+MUNwAnYhiG+4gsAnrj1+6e9HLYW5NYChUtlg+GMwC//jfqQzi3PE0lXQPz7n8fq1dN8UUjNRsAplQnfT0q8yqM4LeDpB+5WIWC3QAxOzMv6Oobtgt54UBLGoS+yHv3uZeyeqUbvi1Tt+eCkk+qbPTE3V3qapF2pZm64ST4ZjYPTwxN943/HZpq2jb3BfVHApRXdfVCJJ0e9XrOzYgwzbOCovNDajEUb3ILtbRcJSWud6b4tnyE5Q9eeigu6S6RPavgvY0MYVx2XZ249/AfzD9aY9EwAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "62a1303ae95931e56e387e87d354bb24", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ee1469828784a316b923eb33d476b2a1\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0875:142040AE:53EFB2DE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Fri, 08 Aug 2014 17:22:50 GMT", "date": "Sat, 16 Aug 2014 19:37:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408221422"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py"}, "recorded_at": "2014-08-16T19:37:02"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/issues/187"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA71WXa8aNxD9K5YfE4K9y9eyIlSt2oe89SFVpZaKeNcDWPXaK9sLIYj/3vEukMtNdO/lBlUIiTWec+Ycz4z3QBunaU43IdQ+Z0zUqr9WYdMU/dJWzEFtPfNqXYmtco1Ph6z7d9Cv90x534BnSTahPapFAdov7wLHOrADM6KCI4JjLhWYcC/4Mxwiw/aOuB0Yom5CpR9Z8cDVF/mpJM3TUconaZr1qGmqAhzN0eseDSpowEP71ZZNtIWEnSUrUQbriGjCBhNofNx9oNqulcGtDynx7xZ8yLMB71GxFUG4xwfXLvpTLUS00pqAXG1ZNKwL/mn7PkW0tTthRFhaJsNsMBrLbLqapiMYT9NkkhUAiZwORLmKtfJkkUSy65q7yVDcvLJa2x2iPBZ1XdzfErFL5AVFmfUrUTDywGzYAHqLkmIZr5V/roa/k1QbdcDG82GpZMTxeDYO5M2JneIwrZ3BjA5tf7eATeFLp+qgrLndtatoRLNuLYz6Il6HhtEeQdrRc7PCNgqjX9LW37G6Czuw2qmtKPfRGgclqC2a/UrIR/GIGPZ17N4/Youi9SrAUsgqtulKaA/H8yyl+d+Hp1vl6fHcDVH2S7NGmjhJkbR7KK22OB4oJIlME3rs3YPnN+H3X4lOT2cmnkLCy3sxmY0wJcTR94DwavGiUAJ+7sT7u1Du7Q5vx7cfhPnKHJdJXCbd8kUzn2ac0+M/bcOGaL+tIQZqW/6LWXXnjRPY43g2gBtMo3WPVkqDD9ZcFi73VT7Au9ABgsmlCAiY8mT4jifvePaR85yP8tHoLyRoavntniT5mCb5MMtHSdxTautPMB1tYeV+GW8uxJ3V85kgGwer94vLy0FAkQFcewUUTgmzLBsXlGFRXuPZMOXj8WiQTNIJn3I+GYwXdH5+s7g9eMbEnFRCAqmAoGitvgD5QAw2oiPydPeBJCqQGVRzEYjQesbwZ3/G6vnCLAzK+Fl7G7egv9KTYEkBREgsivgbpzOZlVbC/Pxa016YM9aukVVjyjjE+uRPaAGIICvYkbW1ksBnUdV4UBHnnE0kipXQJoAet5YG+ByP6vVGvNCEzoB+1P2s6Cu5P6DzpPH/kPem0/emv3AoEb/Pivx0pfLTj8k8tUux77r0+B+ALh1POgsAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"9c8f535a8bdb69177f2992aa89cc39b4\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0875:142040FF:53EFB2DE", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Sat, 16 Aug 2014 02:27:44 GMT", "date": "Sat, 16 Aug 2014 19:37:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408221422"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/issues/187"}, "recorded_at": "2014-08-16T19:37:02"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/issues/187/comments?per_page=100"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1YXY/iNhT9K276sH0AkgAZkoil6qp92KrbjqqtKrVUyCQOWJPEqe3AUjT/vceBnSUZCsPHqPMwD0jIuef43uOYc7l/rq1SplZozbUuVGjbtOCdGdfzctqJRGZLVghlKz7L6ILLUnX79uZpr1OsbK5UyZSNwIzlWtk9dxAETs+1WuDL0kmdeof2CKHrD76uuLfM7R3iar3BfE7S2ANp8tgKP5O3rFIxaYVrKxUznkMUpmik2Z2i023ojR94gduy6IJqKptZVItqK5/hikSuIUylZGlvwN8u3nbBNpNbDpOB5TCPud3Yi/qJHzDW73ndQeI7NPb6HvOmPQAOHpPZTNm1dA8fQC00EWkqlmBoFlR/F5qb2A84pLf5zvPZWRzArW2h5wyaopR7IxBX+tSEKswab6jSEx4bFoUTkSw+MaktCiktc2Szrq5BRVdOVSR5obnIT02uhgWXkDOa83/oOVzAKlBUt/PE2ioMsGxhruyJ4A1obReSL2i0MpJIFjG+gMRnETbQ4NOrguFG/GauIgTnmk1onJnrmNBUsfuWFUlGNTakGnFdx+23Hbft+B8dN+z7Ydf/A7iyiI/GTEW8mphrApphMfpZaEa0IIqlSUiGLBt9L/I3mmRMzhhZ4jdRlJrEIirNj111bEMbUSRsF2RoF6NxPs7B8w5R70GkaZquiEHN5mZlTmOiRMbIrz/c/mTz2xUe5QScBQCJFBnRTGncBGC4Iss5ywnXZEkV4VmRMrMri/GQYlGUaQzGBRIT8g7LS5amJBGS0JywT9QAOlVWEKMqVLNPRq96lUcrrIozhb2cqrYFPaplcrSYyaYaiXrweTkVEeu+dX0fdgMHUh22gbN8eEP8TD4M8sc+vJsmajKW2e07fg+hZznxBrzXiSO37/e8m9gPkqDrsZug6w78KWNuHPRolJie4QlO3Ej46YcA+pPcuHaAZ/vxHpZLHLnxVl3gyTWm67lynXbX06H/yb5cYzvVmWvg0725Br+OOzcyqrk75LnInz1YtHfEnx9iav4c8wWJUqrU27HFMsrT9t8lDDtuQ7N0NbZGv+TkY8la5EcYoDNoEdMYEFil4226gtsPBE2C47TIO7SEK/JBSMkVHHgpwROOc1K3xifaydBGZrD+4eMEE0lnxrSR3HdVH6BoDv/mGVOVxXcOYBvFkSuaFSq9rK04kPZOye/foCHR9I5ht682kEYr8j+d2DjffxrQ5SWpPM5rCn7pei6VDa3P6Lx3nZi2yXz+Q8Dt09E1daz2HF34xj4kXpf0Obqufs+0CE83/D3jlP3Tjw3xM3VdIH/cdb1OP3YnYa/Tj9fpRzUyebnTD28QOr1j3dXnmMb043eURqY0ukNrIs3IgmRmeIG/AaqD4UVcjUKqgQPNMbnAeoeE3+ybMJzH9MXfzsPjP/Rf/wJiGPWszRYAAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "3061975e1f37121b3751604ad153c687", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"ce2781d7530ec339ede9dce49e349d6b\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "48A0C4D3:0875:14204127:53EFB2DE", "cache-control": "public, max-age=60, s-maxage=60", "date": "Sat, 16 Aug 2014 19:37:02 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408221422"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/issues/187/comments?per_page=100"}, "recorded_at": "2014-08-16T19:37:02"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_issue.py b/tests/integration/test_issue.py index cf88c8ff8..ebc522166 100644 --- a/tests/integration/test_issue.py +++ b/tests/integration/test_issue.py @@ -1,9 +1,25 @@ +"""Integration tests for Issues.""" import github3 from .helper import IntegrationHelper class TestIssue(IntegrationHelper): + + """Integration tests for methods on the Issue class.""" + + def test_comments(self): + """Test the ability to retrieve comments on an issue.""" + cassette_name = self.cassette_name('comments') + with self.recorder.use_cassette(cassette_name): + issue = self.gh.issue('sigmavirus24', 'github3.py', 187) + assert issue is not None + comments = list(issue.comments()) + + assert len(comments) > 0 + for comment in comments: + assert isinstance(comment, github3.issues.comment.IssueComment) + def test_iter_events(self): """Test the ability to iterate over issue events.""" self.token_login() diff --git a/tests/test_issues.py b/tests/test_issues.py index f5daeb1bd..f38135023 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -241,13 +241,6 @@ def test_is_closed(self): self.i.state = 'open' assert self.i.is_closed() is False - def test_iter_comments(self): - self.response('issue_comment', _iter=True) - self.get(self.api + '/comments') - - assert isinstance((next(self.i.iter_comments())), IssueComment) - self.mock_assertions() - def test_iter_events(self): self.response('issue_event', _iter=True) self.get(self.api + '/events') diff --git a/tests/unit/issue_example_data b/tests/unit/issue_example_data new file mode 100644 index 000000000..c203391c3 --- /dev/null +++ b/tests/unit/issue_example_data @@ -0,0 +1,113 @@ +{ + "url": "https://api.github.com/repos/octocat/Hello-World/issues/1347", + "html_url": "https://github.com/octocat/Hello-World/issues/1347", + "number": 1347, + "state": "open", + "title": "Found a bug", + "body": "I'm having a problem with this.", + "user": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "url": "https://api.github.com/repos/octocat/Hello-World/labels/bug", + "name": "bug", + "color": "f29513" + } + ], + "assignee": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "milestone": { + "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", + "number": 1, + "state": "open", + "title": "v1.0", + "description": "", + "creator": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 4, + "closed_issues": 8, + "created_at": "2011-04-10T20:09:31Z", + "updated_at": "2014-03-03T18:58:10Z", + "due_on": null + }, + "comments": 0, + "pull_request": { + "url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347", + "html_url": "https://github.com/octocat/Hello-World/pull/1347", + "diff_url": "https://github.com/octocat/Hello-World/pull/1347.diff", + "patch_url": "https://github.com/octocat/Hello-World/pull/1347.patch" + }, + "closed_at": null, + "created_at": "2011-04-22T13:33:48Z", + "updated_at": "2011-04-22T13:33:48Z", + "closed_by": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/tests/unit/test_issues_issue.py b/tests/unit/test_issues_issue.py new file mode 100644 index 000000000..f6a172823 --- /dev/null +++ b/tests/unit/test_issues_issue.py @@ -0,0 +1,30 @@ +"""Unit tests for the Issue class.""" +import github3 + +from .helper import (UnitIteratorHelper, create_url_helper, + create_example_data_helper) + +url_for = create_url_helper( + 'https://api.github.com/repos/octocat/Hello-World/issues/1347' +) + +get_issue_example_data = create_example_data_helper('issue_example_data') + + +class TestIssueIterators(UnitIteratorHelper): + + """Test Issue methods that return iterators.""" + + described_class = github3.issues.Issue + example_data = get_issue_example_data() + + def test_comments(self): + """Test the request to retrieve an issue's comments.""" + i = self.instance.comments() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('comments'), + params={'per_page': 100}, + headers={} + ) From dd2b5ea3b0bd62c95e70bb00a9dedd9da831e2e5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 15:06:46 -0500 Subject: [PATCH 369/972] Break latest version's history into separate file --- HISTORY.rst | 250 +-------------------------------------- LATEST_VERSION_NOTES.rst | 250 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+), 249 deletions(-) create mode 100644 LATEST_VERSION_NOTES.rst diff --git a/HISTORY.rst b/HISTORY.rst index 4ff9a13aa..1b43fa51c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,255 +3,7 @@ History/Changelog ----------------- -1.0.0: 2014-xx-xx -~~~~~~~~~~~~~~~~~ - -1.0.0 is a huge release. It includes a great deal of changes to ``github3.py``. -It is suggested you read the following release notes *very* carefully. - -Breaking Changes -```````````````` - -- ``Organization#add_member`` has been changed. The second parameter has been - changed to ``team_id`` and now expects an integer. - -- ``Organization#add_repository`` has been changed. The second parameter has been - changed to ``team_id`` and now expects an integer. - -- All methods and functions starting with ``iter_`` have been renamed. - -========================================== ============================================== -Old name New name -========================================== ============================================== -``github3.iter_all_repos`` ``github3.all_repositories`` -``github3.iter_all_users`` ``github3.all_users`` -``github3.iter_events`` ``github3.all_events`` -``github3.iter_followers`` ``github3.followers_of`` -``github3.iter_following`` ``github3.followed_by`` -``github3.iter_repo_issues`` ``github3.repository_issues`` -``github3.iter_orgs`` ``github3.organizations_with`` -``github3.iter_user_repos`` ``github3.repositories_by`` -``github3.iter_starred`` ``github3.starred_by`` -``github3.iter_subscriptions`` ``github3.subscriptions_for`` -``Gist#iter_comments`` ``Gist#comments`` -``Gist#iter_commits`` ``Gist#commits`` -``Gist#iter_files`` ``Gist#files`` -``Gist#iter_forks`` ``Gist#forks`` -``GitHub#iter_all_repos`` ``GitHub#all_repositories`` -``GitHub#iter_all_users`` ``GitHub#all_users`` -``GitHub#iter_authorizations`` ``GitHub#authorizations`` -``GitHub#iter_emails`` ``GitHub#emails`` -``GitHub#iter_events`` ``GitHub#events`` -``GitHub#iter_followers`` ``GitHub#{followers,followers_of}`` -``GitHub#iter_following`` ``GitHub#{following,followed_by}`` -``GitHub#iter_gists`` ``GitHub#{gists,gists_by,public_gists}`` -``GitHub#iter_notifications`` ``GitHub#notifications`` -``GitHub#iter_org_issues`` ``GitHub#organization_issues`` -``GitHub#iter_issues`` ``GitHub#issues`` -``GitHub#iter_user_issues`` ``GitHub#user_issues`` -``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` -``GitHub#iter_keys`` ``GitHub#keys`` -``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` -``GitHub#iter_repos`` ``GitHub#reposistories`` -``GitHub#iter_user_repos`` ``GitHub#repositories_by`` -``GitHub#iter_user_teams`` ``GitHub#user_teams`` -``Issue#iter_comments`` ``Issue#comments`` -``Organization#iter_members`` ``Organization#members`` -``Organization#iter_public_members`` ``Organization#public_members`` -``Organization#iter_repos`` ``Organization#repositories`` -``Organization#iter_teams`` ``Organization#teams`` -``PullRequest#iter_comments`` ``PullRequest#review_comments`` -``PullRequest#iter_commits`` ``PullRequest#commits`` -``PullRequest#iter_files`` ``PullRequest#files`` -``PullRequest#iter_issue_comments`` ``PullRequest#issue_comments`` -``Team#iter_members`` ``Team#members`` -``Team#iter_repos`` ``Team#repositories`` -``Repository#iter_assignees`` ``Repository#assignees`` -``Repository#iter_branches`` ``Repository#branches`` -``Repository#iter_code_frequency`` ``Repository#code_frequency`` -``Repository#iter_collaborators`` ``Repository#collaborators`` -``Repository#iter_comments`` ``Repository#comments`` -``Repository#iter_comments_on_commit`` ``Repository#comments_on_commit`` -``Repository#iter_commit_activity`` ``Repository#commit_activity`` -``Repository#iter_commits`` ``Repository#commits`` -``Repository#iter_contributor_statistics`` ``Repository#contributor_statistics`` -``Repository#iter_contributors`` ``Repository#contributors`` -``Repository#iter_forks`` ``Repository#forks`` -``Repository#iter_hooks`` ``Repository#hooks`` -``Repository#iter_issues`` ``Repository#issues`` -``Repository#iter_issue_events`` ``Repository#issue_events`` -``Repository#iter_keys`` ``Repository#keys`` -``Repository#iter_labels`` ``Repository#labels`` -``Repository#iter_languages`` ``Repository#languages`` -``Repository#iter_milestones`` ``Repository#milestones`` -``Repository#iter_network_events`` ``Repository#network_events`` -``Repository#iter_notifications`` ``Repository#notifications`` -``Repository#iter_pages_builds`` ``Repository#pages_builds`` -``Repository#iter_pulls`` ``Repository#pull_requests`` -``Repository#iter_refs`` ``Repository#refs`` -``Repository#iter_releases`` ``Repository#releases`` -``Repository#iter_stargazers`` ``Repository#stargazers`` -``Repository#iter_subscribers`` ``Repository#subscribers`` -``Repository#iter_statuses`` ``Repository#statuses`` -``Repository#iter_tags`` ``Repository#tags`` -``Repository#iter_teams`` ``Repository#teams`` - -========================================== ============================================== - -- ``github3.login`` has been simplified and split into two functions: - - - ``github3.login`` serves the majority use case and only provides an - authenticated ``GitHub`` object. - - - ``github3.enterprise_login`` allows GitHub Enterprise users to log into - their service. - -- ``GitHub#iter_followers`` was split into two functions: - - - ``GitHub#followers_of`` which iterates over all of the followers of a user - whose username you provide - - - ``GitHub#followers`` which iterates over all of the followers of the - authenticated user - -- ``GitHub#iter_following`` was split into two functions: - - - ``GitHub#followed_by`` which iterates over all of the users followed by - the username you provide - - - ``GitHub#following`` which iterates over all of the users followed by the - authenticated user - -- ``GitHub#iter_gists`` was split into three functions: - - - ``GitHub#public_gists`` which iterates over all of the public gists on - GitHub - - - ``GitHub#gists_for`` which iterates over all the public gists of a - specific user - - - ``GitHub#gists`` which iterates over the authenticated users gists - -- ``GitHub#iter_orgs`` was split into two functions: - - - ``GitHub#organizations`` which iterates over the authenticated user's - organization memberships - - - ``GitHub#organizations_with`` which iterates over the given user's - organization memberships - -- ``GitHub#iter_subscriptions`` was split into two functions: - - - ``GitHub#subscriptions_for`` which iterates over an arbitrary user's - subscriptions - - - ``GitHub#subscriptions`` which iterates over the authenticated user's - subscriptions - -- ``GitHub#iter_starred`` was split into two functions: - - - ``GitHub#starred_by`` which iterates over an arbitrary user's stars - - - ``GitHub#starred`` which iterates over the authenticated user's stars - -- Remove legacy watching API: - - - ``GitHub#subscribe`` - - - ``GitHub#unsubscribe`` - - - ``GitHub#is_subscribed`` - -- ``Repository#set_subscription`` was split into two simpler functions - - - ``Repository#subscribe`` subscribes the authenticated user to the - repository's notifications - - - ``Repository#ignore`` ignores notifications from the repository for the - authenticated user - -- ``Organization#add_repo`` and ``Team#add_repo`` have been renamed to - ``Organization#add_repository`` and ``Team#add_repository`` respectively. - -- ``Organization#create_repo`` has been renamed to - ``Organization#create_repository``. It no longer accepts ``has_downloads``. - It now accepts ``license_template``. - -- ``Organization#remove_repo`` has been renamed to - ``Organization#remove_repository``. It now accepts ``team_id`` instead of - ``team``. - -- ``github3.ratelimit_remaining`` was removed - -- ``GitHub`` instances can no longer be used as context managers - -- The pull request API has changed. - - - The ``links`` attribute now contains the raw ``_links`` attribute from the - API. - - - The ``merge_commit_sha`` attribute has been removed since it was deprecated - in the GitHub API. - - - To present a more consistent universal API, certain attributes have been - renamed. - -=============================== ========================== -Old name New attribute name -=============================== ========================== -``PullFile.additions`` ``additions_count`` -``PullFile.deletions`` ``deletions_count`` -``PullFile.changes`` ``changes_count`` -``PullRequest.additions`` ``additions_count`` -``PullRequest.comments`` ``comments_count`` -``PullRequest.commits`` ``commits_count`` -``PullRequest.deletions`` ``deletions_count`` -``PullRequest.review_comments`` ``review_comments_count`` -=============================== ========================== - -- The Gist API has changed. - - - The ``forks`` and ``files`` attributes that used to keep count of the - number of ``forks`` and ``files`` have been **removed**. - - - The ``comments`` attribute which provided the number of comments on a - gist, has been **renamed** to ``comments_count``. - - - The ``is_public`` method has been removed since it just returned the - ``Gist.public`` attribute. - -- Most instances of ``login`` as a parameter have been changed to ``username`` - for clarity and consistency. This affects the following methods: - - - ``Organization#add_member`` - - ``Organization#is_member`` - - ``Organization#is_public_member`` - - ``Organization#remove_member`` - - ``Repository#add_collaborator`` - - ``Repository#is_assignee`` - - ``Repository#is_collaborator`` - - ``Repository#remove_collaborator`` - - ``Team#add_member`` - - ``Team#is_member`` - -- ``Repository.stargazers`` is now ``Repository.stargazers_count`` (conforming - with the attribute name returned by the API). - - -- The ``Issue`` API has changed in order to provide a more consistent attribute - API. ``Issue.comments`` is now ``Issue.comments_count`` and returns the - number of comments on an issue. - -- The ``Issue.labels`` attribute has also been renamed. It is now available from - ``Issue.original_labels``. This will provide the user with the list of - ``Label`` objects that was returned by the API. To retrieve an updated list - of labels, the user can now use ``Issue#labels``, e.g. - - :: - - i = github3.issue('sigmavirus24', 'github3.py', 30) - labels = list(i.labels()) - +.. include:: LATEST_VERSION_NOTES.rst 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ diff --git a/LATEST_VERSION_NOTES.rst b/LATEST_VERSION_NOTES.rst new file mode 100644 index 000000000..ca5b54c2b --- /dev/null +++ b/LATEST_VERSION_NOTES.rst @@ -0,0 +1,250 @@ +.. vim: set tw=100 + +1.0.0: 2014-xx-xx +~~~~~~~~~~~~~~~~~ + +1.0.0 is a huge release. It includes a great deal of changes to ``github3.py``. +It is suggested you read the following release notes *very* carefully. + +Breaking Changes +```````````````` + +- ``Organization#add_member`` has been changed. The second parameter has been + changed to ``team_id`` and now expects an integer. + +- ``Organization#add_repository`` has been changed. The second parameter has been + changed to ``team_id`` and now expects an integer. + +- All methods and functions starting with ``iter_`` have been renamed. + +========================================== ============================================== +Old name New name +========================================== ============================================== +``github3.iter_all_repos`` ``github3.all_repositories`` +``github3.iter_all_users`` ``github3.all_users`` +``github3.iter_events`` ``github3.all_events`` +``github3.iter_followers`` ``github3.followers_of`` +``github3.iter_following`` ``github3.followed_by`` +``github3.iter_repo_issues`` ``github3.repository_issues`` +``github3.iter_orgs`` ``github3.organizations_with`` +``github3.iter_user_repos`` ``github3.repositories_by`` +``github3.iter_starred`` ``github3.starred_by`` +``github3.iter_subscriptions`` ``github3.subscriptions_for`` +``Gist#iter_comments`` ``Gist#comments`` +``Gist#iter_commits`` ``Gist#commits`` +``Gist#iter_files`` ``Gist#files`` +``Gist#iter_forks`` ``Gist#forks`` +``GitHub#iter_all_repos`` ``GitHub#all_repositories`` +``GitHub#iter_all_users`` ``GitHub#all_users`` +``GitHub#iter_authorizations`` ``GitHub#authorizations`` +``GitHub#iter_emails`` ``GitHub#emails`` +``GitHub#iter_events`` ``GitHub#events`` +``GitHub#iter_followers`` ``GitHub#{followers,followers_of}`` +``GitHub#iter_following`` ``GitHub#{following,followed_by}`` +``GitHub#iter_gists`` ``GitHub#{gists,gists_by,public_gists}`` +``GitHub#iter_notifications`` ``GitHub#notifications`` +``GitHub#iter_org_issues`` ``GitHub#organization_issues`` +``GitHub#iter_issues`` ``GitHub#issues`` +``GitHub#iter_user_issues`` ``GitHub#user_issues`` +``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` +``GitHub#iter_keys`` ``GitHub#keys`` +``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` +``GitHub#iter_repos`` ``GitHub#reposistories`` +``GitHub#iter_user_repos`` ``GitHub#repositories_by`` +``GitHub#iter_user_teams`` ``GitHub#user_teams`` +``Issue#iter_comments`` ``Issue#comments`` +``Organization#iter_members`` ``Organization#members`` +``Organization#iter_public_members`` ``Organization#public_members`` +``Organization#iter_repos`` ``Organization#repositories`` +``Organization#iter_teams`` ``Organization#teams`` +``PullRequest#iter_comments`` ``PullRequest#review_comments`` +``PullRequest#iter_commits`` ``PullRequest#commits`` +``PullRequest#iter_files`` ``PullRequest#files`` +``PullRequest#iter_issue_comments`` ``PullRequest#issue_comments`` +``Team#iter_members`` ``Team#members`` +``Team#iter_repos`` ``Team#repositories`` +``Repository#iter_assignees`` ``Repository#assignees`` +``Repository#iter_branches`` ``Repository#branches`` +``Repository#iter_code_frequency`` ``Repository#code_frequency`` +``Repository#iter_collaborators`` ``Repository#collaborators`` +``Repository#iter_comments`` ``Repository#comments`` +``Repository#iter_comments_on_commit`` ``Repository#comments_on_commit`` +``Repository#iter_commit_activity`` ``Repository#commit_activity`` +``Repository#iter_commits`` ``Repository#commits`` +``Repository#iter_contributor_statistics`` ``Repository#contributor_statistics`` +``Repository#iter_contributors`` ``Repository#contributors`` +``Repository#iter_forks`` ``Repository#forks`` +``Repository#iter_hooks`` ``Repository#hooks`` +``Repository#iter_issues`` ``Repository#issues`` +``Repository#iter_issue_events`` ``Repository#issue_events`` +``Repository#iter_keys`` ``Repository#keys`` +``Repository#iter_labels`` ``Repository#labels`` +``Repository#iter_languages`` ``Repository#languages`` +``Repository#iter_milestones`` ``Repository#milestones`` +``Repository#iter_network_events`` ``Repository#network_events`` +``Repository#iter_notifications`` ``Repository#notifications`` +``Repository#iter_pages_builds`` ``Repository#pages_builds`` +``Repository#iter_pulls`` ``Repository#pull_requests`` +``Repository#iter_refs`` ``Repository#refs`` +``Repository#iter_releases`` ``Repository#releases`` +``Repository#iter_stargazers`` ``Repository#stargazers`` +``Repository#iter_subscribers`` ``Repository#subscribers`` +``Repository#iter_statuses`` ``Repository#statuses`` +``Repository#iter_tags`` ``Repository#tags`` +``Repository#iter_teams`` ``Repository#teams`` + +========================================== ============================================== + +- ``github3.login`` has been simplified and split into two functions: + + - ``github3.login`` serves the majority use case and only provides an + authenticated ``GitHub`` object. + + - ``github3.enterprise_login`` allows GitHub Enterprise users to log into + their service. + +- ``GitHub#iter_followers`` was split into two functions: + + - ``GitHub#followers_of`` which iterates over all of the followers of a user + whose username you provide + + - ``GitHub#followers`` which iterates over all of the followers of the + authenticated user + +- ``GitHub#iter_following`` was split into two functions: + + - ``GitHub#followed_by`` which iterates over all of the users followed by + the username you provide + + - ``GitHub#following`` which iterates over all of the users followed by the + authenticated user + +- ``GitHub#iter_gists`` was split into three functions: + + - ``GitHub#public_gists`` which iterates over all of the public gists on + GitHub + + - ``GitHub#gists_for`` which iterates over all the public gists of a + specific user + + - ``GitHub#gists`` which iterates over the authenticated users gists + +- ``GitHub#iter_orgs`` was split into two functions: + + - ``GitHub#organizations`` which iterates over the authenticated user's + organization memberships + + - ``GitHub#organizations_with`` which iterates over the given user's + organization memberships + +- ``GitHub#iter_subscriptions`` was split into two functions: + + - ``GitHub#subscriptions_for`` which iterates over an arbitrary user's + subscriptions + + - ``GitHub#subscriptions`` which iterates over the authenticated user's + subscriptions + +- ``GitHub#iter_starred`` was split into two functions: + + - ``GitHub#starred_by`` which iterates over an arbitrary user's stars + + - ``GitHub#starred`` which iterates over the authenticated user's stars + +- Remove legacy watching API: + + - ``GitHub#subscribe`` + + - ``GitHub#unsubscribe`` + + - ``GitHub#is_subscribed`` + +- ``Repository#set_subscription`` was split into two simpler functions + + - ``Repository#subscribe`` subscribes the authenticated user to the + repository's notifications + + - ``Repository#ignore`` ignores notifications from the repository for the + authenticated user + +- ``Organization#add_repo`` and ``Team#add_repo`` have been renamed to + ``Organization#add_repository`` and ``Team#add_repository`` respectively. + +- ``Organization#create_repo`` has been renamed to + ``Organization#create_repository``. It no longer accepts ``has_downloads``. + It now accepts ``license_template``. + +- ``Organization#remove_repo`` has been renamed to + ``Organization#remove_repository``. It now accepts ``team_id`` instead of + ``team``. + +- ``github3.ratelimit_remaining`` was removed + +- ``GitHub`` instances can no longer be used as context managers + +- The pull request API has changed. + + - The ``links`` attribute now contains the raw ``_links`` attribute from the + API. + + - The ``merge_commit_sha`` attribute has been removed since it was deprecated + in the GitHub API. + + - To present a more consistent universal API, certain attributes have been + renamed. + +=============================== ========================== +Old name New attribute name +=============================== ========================== +``PullFile.additions`` ``additions_count`` +``PullFile.deletions`` ``deletions_count`` +``PullFile.changes`` ``changes_count`` +``PullRequest.additions`` ``additions_count`` +``PullRequest.comments`` ``comments_count`` +``PullRequest.commits`` ``commits_count`` +``PullRequest.deletions`` ``deletions_count`` +``PullRequest.review_comments`` ``review_comments_count`` +=============================== ========================== + +- The Gist API has changed. + + - The ``forks`` and ``files`` attributes that used to keep count of the + number of ``forks`` and ``files`` have been **removed**. + + - The ``comments`` attribute which provided the number of comments on a + gist, has been **renamed** to ``comments_count``. + + - The ``is_public`` method has been removed since it just returned the + ``Gist.public`` attribute. + +- Most instances of ``login`` as a parameter have been changed to ``username`` + for clarity and consistency. This affects the following methods: + + - ``Organization#add_member`` + - ``Organization#is_member`` + - ``Organization#is_public_member`` + - ``Organization#remove_member`` + - ``Repository#add_collaborator`` + - ``Repository#is_assignee`` + - ``Repository#is_collaborator`` + - ``Repository#remove_collaborator`` + - ``Team#add_member`` + - ``Team#is_member`` + +- ``Repository.stargazers`` is now ``Repository.stargazers_count`` (conforming + with the attribute name returned by the API). + + +- The ``Issue`` API has changed in order to provide a more consistent attribute + API. ``Issue.comments`` is now ``Issue.comments_count`` and returns the + number of comments on an issue. + +- The ``Issue.labels`` attribute has also been renamed. It is now available from + ``Issue.original_labels``. This will provide the user with the list of + ``Label`` objects that was returned by the API. To retrieve an updated list + of labels, the user can now use ``Issue#labels``, e.g. + + :: + + i = github3.issue('sigmavirus24', 'github3.py', 30) + labels = list(i.labels()) From b573464528e4fbb07beeaa1376e0a25082e6f96d Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 15:09:31 -0500 Subject: [PATCH 370/972] Use latest version notes in place of the entire history --- MANIFEST.in | 1 + docs/index.rst | 5 ++++- setup.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 151251949..e347eaa1a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,7 @@ include README.rst include LICENSE include HISTORY.rst +include LATEST_VERSION_NOTES.rst include AUTHORS.rst include CONTRIBUTING.rst include tox.ini diff --git a/docs/index.rst b/docs/index.rst index cfb3f5f5e..c45936117 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -173,7 +173,10 @@ Contact .. _sigmavirus24: https://twitter.com/sigmavirus24 -.. include:: ../HISTORY.rst +Latest Version's Changes +------------------------ + +.. include:: ../LATEST_VERSION_NOTES.rst Testimonials ------------ diff --git a/setup.py b/setup.py index a6d7d7f02..806050fbe 100755 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ def run_tests(self): description=("Python wrapper for the GitHub API" "(http://developer.github.com/v3)"), long_description="\n\n".join([open("README.rst").read(), - open("HISTORY.rst").read()]), + open("LATEST_VERSION_NOTES.rst").read()]), license=open('LICENSE').read(), author="Ian Cordasco", author_email="graffatcolmingov@gmail.com", From 629ce6ffc5de962714a15f73dadfb502009c8bd8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 15:26:19 -0500 Subject: [PATCH 371/972] Add full history to docs --- docs/index.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index c45936117..7f6818c12 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -178,6 +178,12 @@ Latest Version's Changes .. include:: ../LATEST_VERSION_NOTES.rst +The full history of the project is available as well. + +.. toctree:: + + project_changelog + Testimonials ------------ From 93b1e46b4e3f202b153371fbd4f99871f3cceeea Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 15:28:01 -0500 Subject: [PATCH 372/972] Add missing file for docs --- docs/project_changelog.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/project_changelog.rst diff --git a/docs/project_changelog.rst b/docs/project_changelog.rst new file mode 100644 index 000000000..250649964 --- /dev/null +++ b/docs/project_changelog.rst @@ -0,0 +1 @@ +.. include:: ../HISTORY.rst From c1fc0bbe6bf5d804461c2c8e077120f7e8006635 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 15:32:05 -0500 Subject: [PATCH 373/972] Use absolute path for ReadTheDocs --- HISTORY.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 1b43fa51c..1249c4387 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,7 +3,7 @@ History/Changelog ----------------- -.. include:: LATEST_VERSION_NOTES.rst +.. include:: ./LATEST_VERSION_NOTES.rst 0.9.0: 2014-05-04 ~~~~~~~~~~~~~~~~~ From 7c7c5c344e9f41c3704071d346843e0ec6961548 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 18:20:10 -0500 Subject: [PATCH 374/972] Rename Issue#iter_events --- LATEST_VERSION_NOTES.rst | 1 + github3/issues/issue.py | 20 +++++++++---------- ...sue_iter_events.json => Issue_events.json} | 0 tests/integration/test_issue.py | 6 +++--- tests/test_issues.py | 9 --------- tests/unit/test_issues_issue.py | 11 ++++++++++ 6 files changed, 25 insertions(+), 22 deletions(-) rename tests/cassettes/{Issue_iter_events.json => Issue_events.json} (100%) diff --git a/LATEST_VERSION_NOTES.rst b/LATEST_VERSION_NOTES.rst index ca5b54c2b..be04ce030 100644 --- a/LATEST_VERSION_NOTES.rst +++ b/LATEST_VERSION_NOTES.rst @@ -53,6 +53,7 @@ Old name New name ``GitHub#iter_user_repos`` ``GitHub#repositories_by`` ``GitHub#iter_user_teams`` ``GitHub#user_teams`` ``Issue#iter_comments`` ``Issue#comments`` +``Issue#iter_events`` ``Issue#events`` ``Organization#iter_members`` ``Organization#members`` ``Organization#iter_public_members`` ``Organization#public_members`` ``Organization#iter_repos`` ``Organization#repositories`` diff --git a/github3/issues/issue.py b/github3/issues/issue.py index 631e15a40..97fc4ca7c 100644 --- a/github3/issues/issue.py +++ b/github3/issues/issue.py @@ -212,16 +212,7 @@ def edit(self, title=None, body=None, assignee=None, state=None, return True return False - def is_closed(self): - """Checks if the issue is closed. - - :returns: bool - """ - if self.closed_at or (self.state == 'closed'): - return True - return False - - def iter_events(self, number=-1): + def events(self, number=-1): """Iterate over events associated with this issue only. :param int number: (optional), number of events to return. Default: -1 @@ -232,6 +223,15 @@ def iter_events(self, number=-1): url = self._build_url('events', base_url=self._api) return self._iter(int(number), url, IssueEvent) + def is_closed(self): + """Checks if the issue is closed. + + :returns: bool + """ + if self.closed_at or (self.state == 'closed'): + return True + return False + def iter_labels(self, number=-1, etag=None): """Iterate over the labels associated with this issue. diff --git a/tests/cassettes/Issue_iter_events.json b/tests/cassettes/Issue_events.json similarity index 100% rename from tests/cassettes/Issue_iter_events.json rename to tests/cassettes/Issue_events.json diff --git a/tests/integration/test_issue.py b/tests/integration/test_issue.py index ebc522166..254712920 100644 --- a/tests/integration/test_issue.py +++ b/tests/integration/test_issue.py @@ -20,14 +20,14 @@ def test_comments(self): for comment in comments: assert isinstance(comment, github3.issues.comment.IssueComment) - def test_iter_events(self): + def test_events(self): """Test the ability to iterate over issue events.""" self.token_login() - cassette_name = self.cassette_name('iter_events') + cassette_name = self.cassette_name('events') with self.recorder.use_cassette(cassette_name): repository = self.gh.repository('sigmavirus24', 'github3.py') issue = repository.issue(218) - for event in issue.iter_events(): + for event in issue.events(): assert isinstance(event, github3.issues.event.IssueEvent) assert event.issue is None assert isinstance(event.actor, github3.users.User) diff --git a/tests/test_issues.py b/tests/test_issues.py index f38135023..acf7e04f0 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -241,15 +241,6 @@ def test_is_closed(self): self.i.state = 'open' assert self.i.is_closed() is False - def test_iter_events(self): - self.response('issue_event', _iter=True) - self.get(self.api + '/events') - - e = next(self.i.iter_events()) - assert isinstance(e, IssueEvent) - assert repr(e).startswith(' Date: Sat, 16 Aug 2014 20:31:08 -0500 Subject: [PATCH 375/972] Rename Issue#iter_labels --- LATEST_VERSION_NOTES.rst | 1 + github3/issues/issue.py | 12 +++++++----- .../{Issue_iter_labels.json => Issue_labels.json} | 0 tests/integration/test_issue.py | 6 +++--- tests/test_issues.py | 15 +++------------ tests/unit/test_issues_issue.py | 11 +++++++++++ 6 files changed, 25 insertions(+), 20 deletions(-) rename tests/cassettes/{Issue_iter_labels.json => Issue_labels.json} (100%) diff --git a/LATEST_VERSION_NOTES.rst b/LATEST_VERSION_NOTES.rst index be04ce030..502b9af4f 100644 --- a/LATEST_VERSION_NOTES.rst +++ b/LATEST_VERSION_NOTES.rst @@ -54,6 +54,7 @@ Old name New name ``GitHub#iter_user_teams`` ``GitHub#user_teams`` ``Issue#iter_comments`` ``Issue#comments`` ``Issue#iter_events`` ``Issue#events`` +``Issue#iter_labels`` ``Issue#labels`` ``Organization#iter_members`` ``Organization#members`` ``Organization#iter_public_members`` ``Organization#public_members`` ``Organization#iter_repos`` ``Organization#repositories`` diff --git a/github3/issues/issue.py b/github3/issues/issue.py index 97fc4ca7c..2eeff94aa 100644 --- a/github3/issues/issue.py +++ b/github3/issues/issue.py @@ -64,7 +64,9 @@ def __init__(self, issue, session=None): self.id = issue.get('id') #: Returns the list of :class:`Label `\ s #: on this issue. - self.labels = [Label(l, self._session) for l in issue.get('labels')] + self.original_labels = [ + Label(l, self._session) for l in issue.get('labels') + ] labels_url = issue.get('labels_url') #: Labels URL Template. Expand with ``name`` self.labels_urlt = URITemplate(labels_url) if labels_url else None @@ -123,7 +125,7 @@ def assign(self, login): if not login: return False number = self.milestone.number if self.milestone else None - labels = [str(l) for l in self.labels] + labels = [str(l) for l in self.original_labels] return self.edit(self.title, self.body, login, self.state, number, labels) @@ -135,7 +137,7 @@ def close(self): """ assignee = self.assignee.login if self.assignee else '' number = self.milestone.number if self.milestone else None - labels = [str(l) for l in self.labels] + labels = [str(l) for l in self.original_labels] return self.edit(self.title, self.body, assignee, 'closed', number, labels) @@ -232,7 +234,7 @@ def is_closed(self): return True return False - def iter_labels(self, number=-1, etag=None): + def labels(self, number=-1, etag=None): """Iterate over the labels associated with this issue. :param int number: (optional), number of labels to return. Default: -1 @@ -285,6 +287,6 @@ def reopen(self): """ assignee = self.assignee.login if self.assignee else '' number = self.milestone.number if self.milestone else None - labels = [str(l) for l in self.labels] + labels = [str(l) for l in self.original_labels] return self.edit(self.title, self.body, assignee, 'open', number, labels) diff --git a/tests/cassettes/Issue_iter_labels.json b/tests/cassettes/Issue_labels.json similarity index 100% rename from tests/cassettes/Issue_iter_labels.json rename to tests/cassettes/Issue_labels.json diff --git a/tests/integration/test_issue.py b/tests/integration/test_issue.py index 254712920..0ced1a3d7 100644 --- a/tests/integration/test_issue.py +++ b/tests/integration/test_issue.py @@ -32,11 +32,11 @@ def test_events(self): assert event.issue is None assert isinstance(event.actor, github3.users.User) - def test_iter_labels(self): + def test_labels(self): """Test the ability to iterate over issue labels.""" - cassette_name = self.cassette_name('iter_labels') + cassette_name = self.cassette_name('labels') with self.recorder.use_cassette(cassette_name): issue = self.gh.issue('sigmavirus24', 'github3.py', 187) assert issue is not None - for label in issue.iter_labels(): + for label in issue.labels(): assert isinstance(label, github3.issues.label.Label) diff --git a/tests/test_issues.py b/tests/test_issues.py index acf7e04f0..588e209fb 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -94,15 +94,6 @@ def test_due_on(self): m = Milestone(json) assert isinstance(m.due_on, datetime.datetime) - def test_iter_labels(self): - self.response('label', _iter=True) - self.get(self.api + '/labels') - - i = self.m.iter_labels() - assert isinstance(i, github3.structs.GitHubIterator) - assert isinstance((next(i)), Label) - self.mock_assertions() - def test_update(self): self.response('milestone', 200) self.patch(self.api) @@ -173,7 +164,7 @@ def test_assign(self): self.not_called() assert self.i.assign('sigmavirus24') n = self.i.milestone.number if self.i.milestone else None - labels = [str(l) for l in self.i.labels] + labels = [str(l) for l in self.i.original_labels] ed.assert_called_once_with( self.i.title, self.i.body, 'sigmavirus24', self.i.state, n, labels @@ -190,7 +181,7 @@ def test_close(self): assert self.i.close() u = self.i.assignee.login if self.i.assignee else '' n = self.i.milestone.number if self.i.milestone else None - l = [str(label) for label in self.i.labels] + l = [str(label) for label in self.i.original_labels] ed.assert_called_once_with( self.i.title, self.i.body, u, self.i.state, n, l ) @@ -286,7 +277,7 @@ def test_reopen(self): with mock.patch.object(Issue, 'edit') as ed: ed.return_value = True assert self.i.reopen() - labels = [str(l) for l in self.i.labels] + labels = [str(l) for l in self.i.original_labels] ed.assert_called_once_with( self.i.title, self.i.body, u, 'open', n, labels ) diff --git a/tests/unit/test_issues_issue.py b/tests/unit/test_issues_issue.py index 970a644b8..fadefa96c 100644 --- a/tests/unit/test_issues_issue.py +++ b/tests/unit/test_issues_issue.py @@ -39,3 +39,14 @@ def test_events(self): params={'per_page': 100}, headers={} ) + + def test_labels(self): + """Test the request to retrieve an issue's labels.""" + i = self.instance.labels() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('labels'), + params={'per_page': 100}, + headers={} + ) From 52d5afc184fbb646f55d99dee27ae2d5f638cd70 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 22:13:31 -0500 Subject: [PATCH 376/972] Add a notebook for Issues --- example-notebooks/issues.ipynb | 241 +++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 example-notebooks/issues.ipynb diff --git a/example-notebooks/issues.ipynb b/example-notebooks/issues.ipynb new file mode 100644 index 000000000..e7558d319 --- /dev/null +++ b/example-notebooks/issues.ipynb @@ -0,0 +1,241 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:e29fc0dcf37df8c9b93eb43cc2a679a0127453d5c950e1c45c9540f809daf1b2" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "The Issues API in github3.py" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "issue = github3.issue('sigmavirus24', 'github3.py', 187)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print(issue.comments_count)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "3\n" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for label in issue.labels():\n", + " print(label)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Bug\n", + "Easy\n", + "Enhancement\n", + "Pair with Ian\n" + ] + } + ], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With an Issue object, we can clearly retrieve a lot of information about the issue itself.\n", + "\n", + "We can also very easily retrieve a the issue text (or body) in *three* ways:\n", + "\n", + "1. HTML\n", + "1. Plain text\n", + "1. Plain markdown" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print(issue.body_html)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "

https://twitter.com/brian_curtin/status/420665317270900736 made me realize I never documented it at all.

\n", + "\n", + "

Also it needs to be added to the github3.login function. We need a few good examples to document it with.

\n" + ] + } + ], + "prompt_number": 5 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print(issue.body_text)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "https://twitter.com/brian_curtin/status/420665317270900736 made me realize I never documented it at all.\n", + "\n", + "Also it needs to be added to the github3.login function. We need a few good examples to document it with.\n" + ] + } + ], + "prompt_number": 6 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print(issue.body)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "https://twitter.com/brian_curtin/status/420665317270900736 made me realize I never documented it *at all*.\r\n", + "\r\n", + "Also it needs to be added to the `github3.login` function. We need a few good examples to document it with.\n" + ] + } + ], + "prompt_number": 10 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print(issue.html_url)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "https://github.com/sigmavirus24/github3.py/issues/187\n" + ] + } + ], + "prompt_number": 7 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('#{0.number}: \"{0.title}\" opened by {0.user}'.format(issue))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "#187: \"Document two factor auth\" opened by sigmavirus24\n" + ] + } + ], + "prompt_number": 8 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for comment in issue.comments():\n", + " print('\"{0.body_text}\" posted by {0.user}'.format(comment))\n", + " print('-' * 80)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\"Note to self: Don't merge without documentation :-p \n", + "\n", + "But I totally thought I had some REPL/iPython output from testing this when it was implemented that would have worked well for an example.\" posted by esacteksab\n", + "--------------------------------------------------------------------------------\n", + "\"On Tue, Jan 07, 2014 at 05:48:28PM -0800, Barry Morrison wrote:\n", + " Note to self: _Don't merge without documentation_ :-p\n", + "A thousand times this.\n", + " But I totally thought I had some REPL/iPython output from testing this when\n", + " it was implemented that would have worked well for an example.\n", + "I'll take it!\" posted by sigmavirus24\n", + "--------------------------------------------------------------------------------\n", + "\"Went back through my things. I don't have anything. :(\" posted by esacteksab\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "prompt_number": 11 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see above [esacteksab](https://github.com/esacteksab) is the originator of the idea for using IPython notebooks to document github3.py" + ] + } + ], + "metadata": {} + } + ] +} \ No newline at end of file From 94be321eb591574219770480e0010be25add3baa Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 16 Aug 2014 22:14:14 -0500 Subject: [PATCH 377/972] Ignore checkpoints --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b869b6c70..03121cfc0 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ venv*/ build/ *.egg .env +.ipynb_checkpoints From 3578f76a9da4a163692106b29f0b9ece8f144ba5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 17 Aug 2014 13:34:15 -0500 Subject: [PATCH 378/972] Add notebook exploring the public gist API --- example-notebooks/public_gist_api.ipynb | 162 ++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 example-notebooks/public_gist_api.ipynb diff --git a/example-notebooks/public_gist_api.ipynb b/example-notebooks/public_gist_api.ipynb new file mode 100644 index 000000000..dd4213841 --- /dev/null +++ b/example-notebooks/public_gist_api.ipynb @@ -0,0 +1,162 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:38e38a4a830fca0d759f9c8ac7f7b947e53586dfe760575d6d01730893498fa5" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "Gists API" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "gist = github3.gist('44885b92ce00e105b92e')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('Gist {0.id} is {1}'.format(gist, 'public' if gist.public else 'private'))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Gist 44885b92ce00e105b92e is public\n" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('Gist {0.id} can be cloned from {0.git_pull_url}'.format(gist))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Gist 44885b92ce00e105b92e can be cloned from https://gist.github.com/44885b92ce00e105b92e.git\n" + ] + } + ], + "prompt_number": 4 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('Gist {0.id} was created by {0.owner} on {0.created_at}'.format(gist))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Gist 44885b92ce00e105b92e was created by sigmavirus24 on 2014-08-10 13:21:21+00:00\n" + ] + } + ], + "prompt_number": 6 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print(gist.comments_count)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "1\n" + ] + } + ], + "prompt_number": 7 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for comment in gist.comments():\n", + " print('\"{0.body_text}\" posted by {0.user}'.format(comment))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "\"funny\" posted by mauricioabreu\n" + ] + } + ], + "prompt_number": 8 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for gist_file in gist.files():\n", + " print('There is a file named {0.filename} that is {0.size} bytes long.'.format(gist_file))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "There is a file named pascal's output that is 278 bytes long.\n", + "There is a file named pascals_triangle.py that is 367 bytes long.\n" + ] + } + ], + "prompt_number": 9 + } + ], + "metadata": {} + } + ] +} \ No newline at end of file From baf47fc2f9fa498fe95e0cb132a07554f7a2a836 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 17 Aug 2014 14:24:29 -0500 Subject: [PATCH 379/972] Add example for iterating over public gists --- .../iterating_over_public_gists.ipynb | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 example-notebooks/iterating_over_public_gists.ipynb diff --git a/example-notebooks/iterating_over_public_gists.ipynb b/example-notebooks/iterating_over_public_gists.ipynb new file mode 100644 index 000000000..ea1104092 --- /dev/null +++ b/example-notebooks/iterating_over_public_gists.ipynb @@ -0,0 +1,132 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:ed8bc8a1a064aef4d07b01861dbb2b7f8470d20435e72d11928ccedfbf9a8254" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "An example of retrieving and iterating over public gists on GitHub" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for gist in github3.public_gists(number=50):\n", + " print('Gist {0.id} was created by {0.owner} on {0.created_at} and can be viewed at {0.html_url}'.format(gist))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Gist ac738b75a14615b88477 was created by adilakhter on 2014-08-17 19:20:24+00:00 and can be viewed at https://gist.github.com/ac738b75a14615b88477\n", + "Gist 0a9a309a9abcc6b5c4bf was created by openpanzer on 2014-08-17 19:20:10+00:00 and can be viewed at https://gist.github.com/0a9a309a9abcc6b5c4bf\n", + "Gist 7683f4f65b38f845db77 was created by rodoard on 2014-08-17 19:19:36+00:00 and can be viewed at https://gist.github.com/7683f4f65b38f845db77\n", + "Gist 9e0c32c8a14be8f5d5a6 was created by alexdgarland on 2014-08-17 19:18:18+00:00 and can be viewed at https://gist.github.com/9e0c32c8a14be8f5d5a6\n", + "Gist 0e7360f80a7c3e1314b1 was created by netsmertia on 2014-08-17 19:17:25+00:00 and can be viewed at https://gist.github.com/0e7360f80a7c3e1314b1\n", + "Gist 9d4801fea0a79a64d65f was created by johnjohnsp1 on 2014-08-17 19:16:57+00:00 and can be viewed at https://gist.github.com/9d4801fea0a79a64d65f\n", + "Gist 697b7c19baef76a7e255 was created by francescoagati on 2014-08-17 19:14:52+00:00 and can be viewed at https://gist.github.com/697b7c19baef76a7e255\n", + "Gist 2b3654bcc548ea46fd5a was created by jkhosla on 2014-08-17 19:14:37+00:00 and can be viewed at https://gist.github.com/2b3654bcc548ea46fd5a\n", + "Gist 52aef973e8cd3814273d was created by netsmertia on 2014-08-17 19:14:35+00:00 and can be viewed at https://gist.github.com/52aef973e8cd3814273d\n", + "Gist 0ebb15e96051435a8495 was created by ivycheung1208 on 2014-08-17 19:14:07+00:00 and can be viewed at https://gist.github.com/0ebb15e96051435a8495\n", + "Gist 3e5e5344a8f4d7497ccd was created by mitsuhiko on 2014-08-17 19:13:32+00:00 and can be viewed at https://gist.github.com/3e5e5344a8f4d7497ccd\n", + "Gist a5619a2de7ab2c207977 was created by asez73 on 2014-08-17 19:13:24+00:00 and can be viewed at https://gist.github.com/a5619a2de7ab2c207977\n", + "Gist 2a0ef712770ed207f046 was created by 1992chenlu on 2014-08-17 19:13:15+00:00 and can be viewed at https://gist.github.com/2a0ef712770ed207f046\n", + "Gist 81f1ea72ec368b282e12 was created by jdehlin on 2014-08-17 19:13:08+00:00 and can be viewed at https://gist.github.com/81f1ea72ec368b282e12\n", + "Gist 6c864bdfced90b81d0a4 was created by rodoard on 2014-08-17 19:12:48+00:00 and can be viewed at https://gist.github.com/6c864bdfced90b81d0a4\n", + "Gist b38bcc0d9882507c918d was created by intothev01d on 2014-08-17 19:12:18+00:00 and can be viewed at https://gist.github.com/b38bcc0d9882507c918d\n", + "Gist 300f20f2705ccfff121f was created by sfujiwara on 2014-08-17 19:12:03+00:00 and can be viewed at https://gist.github.com/300f20f2705ccfff121f\n", + "Gist cf20734ce190c295bce0 was created by rodoard on 2014-08-17 19:10:04+00:00 and can be viewed at https://gist.github.com/cf20734ce190c295bce0\n", + "Gist 3ef046deac453abe5281 was created by dior001 on 2014-08-17 19:09:35+00:00 and can be viewed at https://gist.github.com/3ef046deac453abe5281\n", + "Gist 30e1572599d409ea60ce was created by wilbyang on 2014-08-17 19:09:15+00:00 and can be viewed at https://gist.github.com/30e1572599d409ea60ce\n", + "Gist 67e992f23aeb0c56c8a6 was created by rodoard on 2014-08-17 19:07:53+00:00 and can be viewed at https://gist.github.com/67e992f23aeb0c56c8a6\n", + "Gist 3c5aca83fc49137db35d was created by openpanzer on 2014-08-17 19:07:52+00:00 and can be viewed at https://gist.github.com/3c5aca83fc49137db35d\n", + "Gist 57099359cefcbbb4c07f was created by Arexxk on 2014-08-17 19:07:42+00:00 and can be viewed at https://gist.github.com/57099359cefcbbb4c07f\n", + "Gist b4ca18b8868485ada245 was created by krushd on 2014-08-17 19:07:15+00:00 and can be viewed at https://gist.github.com/b4ca18b8868485ada245\n", + "Gist 06b688f9857475215d88 was created by sanjuthomas on 2014-08-17 19:06:49+00:00 and can be viewed at https://gist.github.com/06b688f9857475215d88\n", + "Gist aa929546abe78aa2be81 was created by sanjuthomas on 2014-08-17 19:05:39+00:00 and can be viewed at https://gist.github.com/aa929546abe78aa2be81\n", + "Gist 593a3e39950d6ccf6d28 was created by CHLibrarian on 2014-08-17 19:05:36+00:00 and can be viewed at https://gist.github.com/593a3e39950d6ccf6d28\n", + "Gist 07bb9aa25f2dec34c353 was created by CHLibrarian on 2014-08-17 19:04:57+00:00 and can be viewed at https://gist.github.com/07bb9aa25f2dec34c353\n", + "Gist 77445b12dccddf898869 was created by sheolseol on 2014-08-17 19:04:42+00:00 and can be viewed at https://gist.github.com/77445b12dccddf898869\n", + "Gist 8fd26b4887231d2b6de7 was created by sackio on 2014-08-17 19:04:30+00:00 and can be viewed at https://gist.github.com/8fd26b4887231d2b6de7\n", + "Gist 03e46b12816e092a1f21 was created by CHLibrarian on 2014-08-17 19:04:17+00:00 and can be viewed at https://gist.github.com/03e46b12816e092a1f21\n", + "Gist faaa524186cd804fc059 was created by ramntry on 2014-08-17 19:03:47+00:00 and can be viewed at https://gist.github.com/faaa524186cd804fc059\n", + "Gist 4f8322e21803a97058fe was created by grondilu on 2014-08-17 19:03:34+00:00 and can be viewed at https://gist.github.com/4f8322e21803a97058fe\n", + "Gist 20cf25445e5ac9bf0028 was created by sanjuthomas on 2014-08-17 19:03:10+00:00 and can be viewed at https://gist.github.com/20cf25445e5ac9bf0028\n", + "Gist beb09796768d42ce9523 was created by CHLibrarian on 2014-08-17 19:03:08+00:00 and can be viewed at https://gist.github.com/beb09796768d42ce9523\n", + "Gist 0ed95c271587870feb5b was created by jakelodwick on 2014-08-17 19:02:38+00:00 and can be viewed at https://gist.github.com/0ed95c271587870feb5b\n", + "Gist e22429a340cd28f2f626 was created by sanjuthomas on 2014-08-17 19:02:14+00:00 and can be viewed at https://gist.github.com/e22429a340cd28f2f626\n", + "Gist 5a62eddbe67dca0a45e2 was created by jakelodwick on 2014-08-17 19:01:46+00:00 and can be viewed at https://gist.github.com/5a62eddbe67dca0a45e2\n", + "Gist 3cbc187e86e302016fd3 was created by synthtech on 2014-08-17 19:01:25+00:00 and can be viewed at https://gist.github.com/3cbc187e86e302016fd3\n", + "Gist ef40230b822a2207c95b was created by sackio on 2014-08-17 19:00:04+00:00 and can be viewed at https://gist.github.com/ef40230b822a2207c95b\n", + "Gist 77df801086743a8159e7 was created by CHLibrarian on 2014-08-17 18:59:12+00:00 and can be viewed at https://gist.github.com/77df801086743a8159e7\n", + "Gist 0de978159530abcbba98 was created by sackio on 2014-08-17 18:59:05+00:00 and can be viewed at https://gist.github.com/0de978159530abcbba98\n", + "Gist fbc99df944d2fd369d10 was created by cythux on 2014-08-17 18:58:42+00:00 and can be viewed at https://gist.github.com/fbc99df944d2fd369d10\n", + "Gist 9ae1fe82f8c335af5160 was created by santiblanko on 2014-08-17 18:58:37+00:00 and can be viewed at https://gist.github.com/9ae1fe82f8c335af5160\n", + "Gist c241cb84f28250a77232 was created by pudquick on 2014-08-17 18:55:26+00:00 and can be viewed at https://gist.github.com/c241cb84f28250a77232\n", + "Gist 187815899d6c3b4cb36e was created by sackio on 2014-08-17 18:55:19+00:00 and can be viewed at https://gist.github.com/187815899d6c3b4cb36e\n", + "Gist 798fa78c90642eebb3b4 was created by prakhar1989 on 2014-08-17 18:55:08+00:00 and can be viewed at https://gist.github.com/798fa78c90642eebb3b4\n", + "Gist 0042d48fbb469ce4bd4c was created by Softsapiens on 2014-08-17 18:54:50+00:00 and can be viewed at https://gist.github.com/0042d48fbb469ce4bd4c\n", + "Gist 91fd537b432b96979459 was created by georgkreimer on 2014-08-17 18:54:11+00:00 and can be viewed at https://gist.github.com/91fd537b432b96979459\n", + "Gist 3a43e1ee0ae57fd4a3d7 was created by yagudaev on 2014-08-17 18:54:07+00:00 and can be viewed at https://gist.github.com/3a43e1ee0ae57fd4a3d7\n" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you omit the number argument, github3.py will attempt to iterate over all public gists on GitHub. With a ratelimit of 60 unauthenticated requests per hour, however, you will not be able to list them quickly. To increase your ratelimit you would have to do something like the following." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "gh = github3.login('username', 'password')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for gist in gh.public_gists():\n", + " print('Gist {0.id} was created by {0.owner} on {0.created_at} and can be viewed at {0.html_url}'.format(gist))" + ], + "language": "python", + "metadata": {}, + "outputs": [] + } + ], + "metadata": {} + } + ] +} \ No newline at end of file From 1c6e15efc66e68d45c37c6c02d296458db2f1e83 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 17 Aug 2014 20:36:40 -0500 Subject: [PATCH 380/972] Add example using all_repositories --- example-notebooks/all_repositories.ipynb | 132 +++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 example-notebooks/all_repositories.ipynb diff --git a/example-notebooks/all_repositories.ipynb b/example-notebooks/all_repositories.ipynb new file mode 100644 index 000000000..fff062f78 --- /dev/null +++ b/example-notebooks/all_repositories.ipynb @@ -0,0 +1,132 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:d7edf60ced4d549568da849ae1760941af6e0432378fa5832cdff325109ee570" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "How to retrieve all of the public repositories on GitHub" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for repository in github3.all_repositories(number=50):\n", + " print('{0}, id: {0.id}, url: {0.html_url}'.format(repository))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "mojombo/grit, id: 1, url: https://github.com/mojombo/grit\n", + "wycats/merb-core, id: 26, url: https://github.com/wycats/merb-core\n", + "rubinius/rubinius, id: 27, url: https://github.com/rubinius/rubinius\n", + "mojombo/god, id: 28, url: https://github.com/mojombo/god\n", + "vanpelt/jsawesome, id: 29, url: https://github.com/vanpelt/jsawesome\n", + "wycats/jspec, id: 31, url: https://github.com/wycats/jspec\n", + "defunkt/exception_logger, id: 35, url: https://github.com/defunkt/exception_logger\n", + "defunkt/ambition, id: 36, url: https://github.com/defunkt/ambition\n", + "technoweenie/restful-authentication, id: 42, url: https://github.com/technoweenie/restful-authentication\n", + "technoweenie/attachment_fu, id: 43, url: https://github.com/technoweenie/attachment_fu\n", + "topfunky/bong, id: 47, url: https://github.com/topfunky/bong\n", + "Caged/microsis, id: 48, url: https://github.com/Caged/microsis\n", + "anotherjesse/s3, id: 52, url: https://github.com/anotherjesse/s3\n", + "anotherjesse/taboo, id: 53, url: https://github.com/anotherjesse/taboo\n", + "anotherjesse/foxtracs, id: 54, url: https://github.com/anotherjesse/foxtracs\n", + "anotherjesse/fotomatic, id: 56, url: https://github.com/anotherjesse/fotomatic\n", + "mojombo/glowstick, id: 61, url: https://github.com/mojombo/glowstick\n", + "defunkt/starling, id: 63, url: https://github.com/defunkt/starling\n", + "wycats/merb-more, id: 65, url: https://github.com/wycats/merb-more\n", + "macournoyer/thin, id: 68, url: https://github.com/macournoyer/thin\n", + "jamesgolick/resource_controller, id: 71, url: https://github.com/jamesgolick/resource_controller\n", + "jamesgolick/markaby, id: 73, url: https://github.com/jamesgolick/markaby\n", + "jamesgolick/enum_field, id: 74, url: https://github.com/jamesgolick/enum_field\n", + "defunkt/subtlety, id: 75, url: https://github.com/defunkt/subtlety\n", + "defunkt/zippy, id: 92, url: https://github.com/defunkt/zippy\n", + "defunkt/cache_fu, id: 93, url: https://github.com/defunkt/cache_fu\n", + "KirinDave/phosphor, id: 95, url: https://github.com/KirinDave/phosphor\n", + "bmizerany/sinatra, id: 98, url: https://github.com/bmizerany/sinatra\n", + "jnewland/gsa-prototype, id: 102, url: https://github.com/jnewland/gsa-prototype\n", + "technoweenie/duplikate, id: 105, url: https://github.com/technoweenie/duplikate\n", + "jnewland/lazy_record, id: 118, url: https://github.com/jnewland/lazy_record\n", + "jnewland/gsa-feeds, id: 119, url: https://github.com/jnewland/gsa-feeds\n", + "jnewland/votigoto, id: 120, url: https://github.com/jnewland/votigoto\n", + "defunkt/mofo, id: 127, url: https://github.com/defunkt/mofo\n", + "jnewland/xhtmlize, id: 129, url: https://github.com/jnewland/xhtmlize\n", + "schacon/ruby-git, id: 130, url: https://github.com/schacon/ruby-git\n", + "ezmobius/bmhsearch, id: 131, url: https://github.com/ezmobius/bmhsearch\n", + "uggedal/mofo, id: 137, url: https://github.com/uggedal/mofo\n", + "mmower/simply_versioned, id: 139, url: https://github.com/mmower/simply_versioned\n", + "abhay/gchart, id: 140, url: https://github.com/abhay/gchart\n", + "benburkert/schemr, id: 141, url: https://github.com/benburkert/schemr\n", + "abhay/calais, id: 142, url: https://github.com/abhay/calais\n", + "mojombo/chronic, id: 144, url: https://github.com/mojombo/chronic\n", + "sr/git-wiki, id: 165, url: https://github.com/sr/git-wiki\n", + "automatthew/ambitious_activeldap, id: 176, url: https://github.com/automatthew/ambitious_activeldap\n", + "queso/signal-wiki, id: 177, url: https://github.com/queso/signal-wiki\n", + "drnic/ruby-on-rails-tmbundle, id: 179, url: https://github.com/drnic/ruby-on-rails-tmbundle\n", + "danwrong/low-pro-for-jquery, id: 185, url: https://github.com/danwrong/low-pro-for-jquery\n", + "wayneeseguin/merb-core, id: 186, url: https://github.com/wayneeseguin/merb-core\n", + "sr/dst, id: 190, url: https://github.com/sr/dst\n" + ] + } + ], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you omit the `number` parameter, github3.py will attempt to retrieve all of the public repositories available on GitHub. In order to iterate over all of them in a reasonable amount of time, you should authenticate like so:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "gh = github3.login('username', 'password')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for repository in gh.all_repositories():\n", + " print('{0} - id: {0.id}, url: {0.html_url}'.format(repository))" + ], + "language": "python", + "metadata": {}, + "outputs": [] + } + ], + "metadata": {} + } + ] +} \ No newline at end of file From 8f1c33a5f6f88428a2108367c717edc53abdd9a1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 18 Aug 2014 18:59:20 -0500 Subject: [PATCH 381/972] Add 2 more notebooks --- .../forking_repositories_by.ipynb | 176 ++++++++++++++++++ .../two_factor_authentication.ipynb | 110 +++++++++++ 2 files changed, 286 insertions(+) create mode 100644 example-notebooks/forking_repositories_by.ipynb create mode 100644 example-notebooks/two_factor_authentication.ipynb diff --git a/example-notebooks/forking_repositories_by.ipynb b/example-notebooks/forking_repositories_by.ipynb new file mode 100644 index 000000000..41683ffbf --- /dev/null +++ b/example-notebooks/forking_repositories_by.ipynb @@ -0,0 +1,176 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:2d234b400db23a8a564289d081cd262369729acb74813177cd991585e0f66fe9" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "Listing repositories by their owner" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for repository in github3.repositories_by('sigmavirus24'):\n", + " print('{0} created at {0.created_at}'.format(repository))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "sigmavirus24/betamax created at 2013-07-16 03:23:22+00:00\n", + "sigmavirus24/betamax_matchers created at 2014-07-19 18:51:39+00:00\n", + "sigmavirus24/catapultpgh created at 2013-02-11 17:16:43+00:00\n", + "sigmavirus24/charade created at 2012-11-28 03:24:20+00:00\n", + "sigmavirus24/clint created at 2013-02-10 21:09:02+00:00\n", + "sigmavirus24/contrib-hub created at 2013-11-30 18:36:55+00:00\n", + "sigmavirus24/crequests created at 2013-01-24 22:54:17+00:00\n", + "sigmavirus24/curryer created at 2013-11-10 02:03:42+00:00\n", + "sigmavirus24/c_libs created at 2012-06-11 14:45:35+00:00\n", + "sigmavirus24/ddg created at 2012-12-16 22:11:35+00:00\n", + "sigmavirus24/developer.github.com created at 2012-05-27 04:19:17+00:00\n", + "sigmavirus24/dream-python created at 2014-08-13 15:55:44+00:00\n", + "sigmavirus24/elephant created at 2013-03-27 18:25:03+00:00\n", + "sigmavirus24/euler.hs created at 2013-10-19 01:19:03+00:00\n", + "sigmavirus24/expecter created at 2012-07-25 03:02:58+00:00\n", + "sigmavirus24/format-geojson.clj created at 2013-10-25 22:17:20+00:00\n", + "sigmavirus24/ghsync created at 2012-10-17 13:49:42+00:00\n", + "sigmavirus24/git-hub created at 2012-10-05 19:35:45+00:00\n", + "sigmavirus24/GITenberg created at 2012-09-25 21:07:30+00:00\n", + "sigmavirus24/github-cli created at 2012-07-05 14:58:47+00:00\n", + "sigmavirus24/github3.py created at 2012-03-13 19:58:53+00:00\n", + "sigmavirus24/GitPython created at 2012-11-28 16:27:22+00:00\n", + "sigmavirus24/grequests created at 2012-12-30 23:04:12+00:00\n", + "sigmavirus24/gtk-vikb created at 2012-07-16 23:18:15+00:00\n", + "sigmavirus24/heroku-buildpack-python created at 2013-01-19 18:09:35+00:00\n", + "sigmavirus24/http11 created at 2014-07-21 01:57:47+00:00\n", + "sigmavirus24/httpbin created at 2013-07-19 18:53:30+00:00\n", + "sigmavirus24/hyper created at 2014-02-20 16:02:48+00:00\n", + "sigmavirus24/issues.py created at 2012-02-25 21:32:31+00:00\n", + "sigmavirus24/LendingClubAutoInvestor created at 2013-05-08 14:56:33+00:00\n", + "sigmavirus24/libyaml created at 2013-12-01 18:27:17+00:00\n", + "sigmavirus24/lyahfgg created at 2013-07-31 02:47:36+00:00\n", + "sigmavirus24/madison_geojson created at 2013-10-25 20:40:41+00:00\n", + "sigmavirus24/mccabe created at 2014-04-18 18:30:26+00:00\n", + "sigmavirus24/mixfaster created at 2012-06-30 00:13:21+00:00\n", + "sigmavirus24/mixminion created at 2011-09-06 13:34:15+00:00\n", + "sigmavirus24/mock_github_api created at 2012-12-21 23:14:08+00:00\n", + "sigmavirus24/nothub created at 2013-01-29 18:00:15+00:00\n", + "sigmavirus24/No_Agenda_Bat_Sig created at 2010-11-05 03:18:10+00:00\n", + "sigmavirus24/octokit.rb created at 2013-12-12 02:32:30+00:00\n", + "sigmavirus24/ordinary created at 2013-06-15 18:09:48+00:00\n", + "sigmavirus24/patch-converter created at 2012-11-26 13:52:57+00:00\n", + "sigmavirus24/pelican created at 2012-06-14 14:25:45+00:00\n", + "sigmavirus24/pelican-themes created at 2012-06-14 13:51:35+00:00\n", + "sigmavirus24/pep8 created at 2012-09-06 14:13:14+00:00\n", + "sigmavirus24/pip created at 2014-01-07 14:27:24+00:00\n", + "sigmavirus24/polynomials.py created at 2013-04-10 03:12:06+00:00\n", + "sigmavirus24/PyF-ck created at 2013-05-01 22:14:11+00:00\n", + "sigmavirus24/pyflakes created at 2014-07-23 15:06:17+00:00\n", + "sigmavirus24/pyflakes-old created at 2013-01-28 00:25:27+00:00\n", + "sigmavirus24/python-guide created at 2012-06-15 18:00:03+00:00\n", + "sigmavirus24/python-interview-questions created at 2014-08-13 02:32:38+00:00\n", + "sigmavirus24/pyyaml created at 2013-12-01 18:29:02+00:00\n", + "sigmavirus24/rack created at 2014-07-13 00:51:30+00:00\n", + "sigmavirus24/recipes created at 2013-01-25 04:31:44+00:00\n", + "sigmavirus24/repl_fun created at 2013-03-30 15:13:42+00:00\n", + "sigmavirus24/requests created at 2012-06-15 13:47:06+00:00\n", + "sigmavirus24/requests-data-schemes created at 2013-01-07 04:49:50+00:00\n", + "sigmavirus24/requests-ntlm created at 2014-07-18 21:32:31+00:00\n", + "sigmavirus24/requests-toolbelt created at 2013-12-29 21:19:08+00:00\n", + "sigmavirus24/requests.rb created at 2013-02-01 02:52:28+00:00\n", + "sigmavirus24/rfc3986 created at 2014-06-25 14:25:11+00:00\n", + "sigmavirus24/shipit created at 2013-05-22 19:32:18+00:00\n", + "sigmavirus24/solarized-pygment created at 2013-01-13 23:36:54+00:00\n", + "sigmavirus24/sprunge.py created at 2012-06-09 14:19:26+00:00\n", + "sigmavirus24/subscribed created at 2012-10-07 03:40:31+00:00\n", + "sigmavirus24/Todo.txt-python created at 2012-09-16 19:31:58+00:00\n", + "sigmavirus24/update_firefox created at 2012-06-19 01:56:02+00:00\n", + "sigmavirus24/uritemplate created at 2013-05-14 16:52:08+00:00\n", + "sigmavirus24/urllib3 created at 2013-12-04 03:04:13+00:00\n", + "sigmavirus24/vcr created at 2013-09-18 03:15:42+00:00\n", + "sigmavirus24/vim-stopsign created at 2013-09-03 13:26:03+00:00\n", + "sigmavirus24/www.gittip.com created at 2013-01-16 13:15:38+00:00\n", + "sigmavirus24/x11-ssh-askpass created at 2011-09-08 15:25:05+00:00\n", + "sigmavirus24/zero created at 2013-09-15 02:17:30+00:00\n", + "sigmavirus24/zero_buffer created at 2014-07-31 18:46:36+00:00\n" + ] + } + ], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you wanted to, you could also login and fork each one of these repositories." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "gh = github3.login('username', 'password')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for repository in gh.repositories_by('sigmavirus24'):\n", + " repository.create_fork()" + ], + "language": "python", + "metadata": {}, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Also if you had an organization you wanted to fork them to you could simply do" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for repository in gh.repositories_by('sigmavirus24'):\n", + " repository.create_fork('my-organization')" + ], + "language": "python", + "metadata": {}, + "outputs": [] + } + ], + "metadata": {} + } + ] +} \ No newline at end of file diff --git a/example-notebooks/two_factor_authentication.ipynb b/example-notebooks/two_factor_authentication.ipynb new file mode 100644 index 000000000..1ca85ac35 --- /dev/null +++ b/example-notebooks/two_factor_authentication.ipynb @@ -0,0 +1,110 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:d38420ae020c12c6526e5f233904ef68f88783f31ada12a2a091b4d23240e68f" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "Using GitHub's API with Two-Factor Authentication (2FA) Enabled" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When you enable 2FA in GitHub, this setting carries over to your usage of the API. github3.py provides a simple interface to manage 2FA.\n", + "\n", + "First, you need to create a callback handler that will prompt the user for their token (which they will receive either by SMS or by checking a phone application)." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "def callback_handler():\n", + " prompt_str = 'Please enter your 2FA token now: '\n", + " try:\n", + " token = raw_input(prompt_str)\n", + " except NameError:\n", + " token = input(prompt_str)\n", + " return token" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This handler will work on Python 2 and Python 3. (In Python 2, to prompt the user, you want to use `raw_input` but that was replaced in Python 3 with `input`.)\n", + "\n", + "This will simply ask the user to type in their token and then return it to github3.py. Naturally if you're developing a GUI, you want to write a different handler, but that is out of the scope of this example.\n", + "\n", + "To use the handler above you can pass it to the `github3.login` function." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "gh = github3.login('username', 'password', two_factor_callback=callback_handler)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The beauty of using the callback means that it only is used when it is necessary. If you have 2FA turned off, you'll never be prompted.\n", + "\n", + "If you have 2FA enabled, then every call you make to the API will require you to provide a passcode. The tokens cannot be reliably cached by github3.py. To avoid this, the API documentation and github3.py suggest you create an API Token. You should decide which [scopes](https://developer.github.com/v3/oauth/#scopes) you want the token to have before creating." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "authorization = github3.authorize('username', 'password', ['user'],\n", + " two_factor_callback=callback_handler)\n", + "gh = github3.login(token=authorization.token)" + ], + "language": "python", + "metadata": {}, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The call to `authorize` will create an `Authorization` object which has a token. With that you can pass the token to `login` and not have to worry about having to supply tokens generated by an mobile application or sent to your phone." + ] + } + ], + "metadata": {} + } + ] +} \ No newline at end of file From 3d43e624deab212e80ff5abb5b196fb880831b42 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 18 Aug 2014 21:08:16 -0500 Subject: [PATCH 382/972] Address @esacteksab's feedback --- example-notebooks/two_factor_authentication.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example-notebooks/two_factor_authentication.ipynb b/example-notebooks/two_factor_authentication.ipynb index 1ca85ac35..fe881667d 100644 --- a/example-notebooks/two_factor_authentication.ipynb +++ b/example-notebooks/two_factor_authentication.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:d38420ae020c12c6526e5f233904ef68f88783f31ada12a2a091b4d23240e68f" + "signature": "sha256:27a49a901befc18721b9ba5dc6be577023c2a672866235f26312f04f927faaa0" }, "nbformat": 3, "nbformat_minor": 0, @@ -48,7 +48,7 @@ "source": [ "This handler will work on Python 2 and Python 3. (In Python 2, to prompt the user, you want to use `raw_input` but that was replaced in Python 3 with `input`.)\n", "\n", - "This will simply ask the user to type in their token and then return it to github3.py. Naturally if you're developing a GUI, you want to write a different handler, but that is out of the scope of this example.\n", + "This will simply ask the user to type in their token and then return it to github3.py. If you're developing a GUI, you will want to write a different handler, but that is out of the scope of this example.\n", "\n", "To use the handler above you can pass it to the `github3.login` function." ] @@ -100,7 +100,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The call to `authorize` will create an `Authorization` object which has a token. With that you can pass the token to `login` and not have to worry about having to supply tokens generated by an mobile application or sent to your phone." + "The call to `authorize` will create an `Authorization` object which has a token. With that you can pass the token to `login` and not have to worry about having to supply tokens generated by a mobile application or sent to your phone." ] } ], From 1d4a377b2cb743ba2896aecd790794e4683e5162 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 18 Aug 2014 21:08:34 -0500 Subject: [PATCH 383/972] Add notebook demonstrating how to list issues on a repo --- .../retrieving_issues_on_a_repository.ipynb | 315 ++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 example-notebooks/retrieving_issues_on_a_repository.ipynb diff --git a/example-notebooks/retrieving_issues_on_a_repository.ipynb b/example-notebooks/retrieving_issues_on_a_repository.ipynb new file mode 100644 index 000000000..97549741d --- /dev/null +++ b/example-notebooks/retrieving_issues_on_a_repository.ipynb @@ -0,0 +1,315 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:fc7950b40a0653a8dc7ce1323731a435b263dc3b10b320ba7e6b3c74683ff36f" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "Retrieving a repository's issues" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "repo = github3.repository('sigmavirus24', 'github3.py')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for issue in repo.issues():\n", + " print('{0}#{1.number}: \"{1.title}\"\\n\\t{1.html_url}'.format(repo, issue))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "sigmavirus24/github3.py#270: \"IPython docs\"\n", + "\thttps://github.com/sigmavirus24/github3.py/pull/270\n", + "sigmavirus24/github3.py#269: \"Deprecate old team members API. Add new API\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/269\n", + "sigmavirus24/github3.py#263: \"Replace Repository#comments_on_commit with RepoCommit#comments\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/263\n", + "sigmavirus24/github3.py#262: \"iter_notifications(all=[bool]) should work passing True\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/262\n", + "sigmavirus24/github3.py#258: \"User Keys Are Now Immutable\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/258\n", + "sigmavirus24/github3.py#257: \"New attributes for PullRequestReviewComment events\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/257\n", + "sigmavirus24/github3.py#256: \"[New] Statuses\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/256\n", + "sigmavirus24/github3.py#255: \"Malformed Tag Causes AttributeError in models.py\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/255\n", + "sigmavirus24/github3.py#253: \"Pull request commits fields are not set\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/253\n", + "sigmavirus24/github3.py#248: \"Switch to (absolute) relative imports to allow for vendoring\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/248\n", + "sigmavirus24/github3.py#241: \"removed duplicate documentation\"\n", + "\thttps://github.com/sigmavirus24/github3.py/pull/241\n", + "sigmavirus24/github3.py#226: \"ETag support for single objects\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/226\n", + "sigmavirus24/github3.py#217: \"API does not handle unicode well\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/217\n", + "sigmavirus24/github3.py#206: \"Better documentation regarding a repo's issues\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/206\n", + "sigmavirus24/github3.py#191: \"Start a branch for updating the docs\"\n", + "\thttps://github.com/sigmavirus24/github3.py/pull/191\n", + "sigmavirus24/github3.py#187: \"Document two factor auth\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/187\n", + "sigmavirus24/github3.py#186: \"Support SNI for Releases API\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/186\n", + "sigmavirus24/github3.py#159: \"Create documentation for testing github3.py\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/159\n", + "sigmavirus24/github3.py#122: \"Roadmap for 1.0\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/122\n", + "sigmavirus24/github3.py#79: \"Caching support!\"\n", + "\thttps://github.com/sigmavirus24/github3.py/issues/79\n" + ] + } + ], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also list closed issues." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "repo = github3.repository('sigmavirus24', 'requests-toolbelt')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 5 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for issue in repo.issues(state='closed'):\n", + " print('{0}#{1.number}: \"{1.title}\"\\n\\t{1.html_url}'.format(repo, issue))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "sigmavirus24/requests-toolbelt#36: \"Some fields do not get uploaded\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/36\n", + "sigmavirus24/requests-toolbelt#35: \"Add ssl_version to the list of attributes\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/35\n", + "sigmavirus24/requests-toolbelt#34: \"SSLAdapter crashes if used with multiprocessing\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/34\n", + "sigmavirus24/requests-toolbelt#33: \"Add support for multipart/mixed\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/33\n", + "sigmavirus24/requests-toolbelt#31: \"MultipartEncoder.read() returns less than 8192 bytes even when more bytes are left\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/31\n", + "sigmavirus24/requests-toolbelt#29: \"Multipart encoder cannot be reused\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/29\n", + "sigmavirus24/requests-toolbelt#28: \"GuessAuth\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/28\n", + "sigmavirus24/requests-toolbelt#27: \"Request for Comments: Implement RFC 5987\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/27\n", + "sigmavirus24/requests-toolbelt#25: \"Import authors to setup.py\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/25\n", + "sigmavirus24/requests-toolbelt#24: \"Import metadata from package to setup.py\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/24\n", + "sigmavirus24/requests-toolbelt#23: \"Add encoding comment to `*.py`\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/23\n", + "sigmavirus24/requests-toolbelt#22: \"Add Monitor for MultipartEncoder\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/22\n", + "sigmavirus24/requests-toolbelt#20: \"README.rst: minor edits, syntax highlighting\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/20\n", + "sigmavirus24/requests-toolbelt#18: \"Slightly refactored MultipartEncoder + improved unit tests\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/18\n", + "sigmavirus24/requests-toolbelt#17: \"MultipartEncoder sometimes add bytes\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/17\n", + "sigmavirus24/requests-toolbelt#16: \"`MultipartEncoder` not fully compliant with RFC 1521\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/16\n", + "sigmavirus24/requests-toolbelt#15: \"Adding Multipart Decoder, redux\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/15\n", + "sigmavirus24/requests-toolbelt#14: \"Added MultipartDecoder.\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/14\n", + "sigmavirus24/requests-toolbelt#13: \"add explicit utf-8 encoding\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/13\n", + "sigmavirus24/requests-toolbelt#12: \"MultipartEncoder: added callback support and bytes read counter\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/12\n", + "sigmavirus24/requests-toolbelt#11: \"Get version info from a file that actually exists\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/11\n", + "sigmavirus24/requests-toolbelt#10: \"pip install fails with requests 1.2.3\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/10\n", + "sigmavirus24/requests-toolbelt#9: \"'file' does not have the buffer interface\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/9\n", + "sigmavirus24/requests-toolbelt#8: \"Invalid multipart encoding with a file\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/8\n", + "sigmavirus24/requests-toolbelt#7: \"Many docs updates\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/7\n", + "sigmavirus24/requests-toolbelt#6: \"Mention SSLAdapter in README.\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/6\n", + "sigmavirus24/requests-toolbelt#5: \"Include the ever-popular SSLAdapter.\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/5\n", + "sigmavirus24/requests-toolbelt#4: \"Attempt to limit how much is ever actually in memory\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/4\n", + "sigmavirus24/requests-toolbelt#3: \"User agent constructor.\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/3\n", + "sigmavirus24/requests-toolbelt#2: \"README fixes\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/2\n", + "sigmavirus24/requests-toolbelt#1: \"Uploader does not really stream\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/1\n" + ] + } + ], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, you can list `all` issues. This time, let's change the direction we list them in." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for issue in repo.issues(state='all', direction='asc'):\n", + " print('{0}#{1.number}: \"{1.title}\"\\n\\t{1.html_url}'.format(repo, issue))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "sigmavirus24/requests-toolbelt#1: \"Uploader does not really stream\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/1\n", + "sigmavirus24/requests-toolbelt#2: \"README fixes\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/2\n", + "sigmavirus24/requests-toolbelt#3: \"User agent constructor.\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/3\n", + "sigmavirus24/requests-toolbelt#4: \"Attempt to limit how much is ever actually in memory\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/4\n", + "sigmavirus24/requests-toolbelt#5: \"Include the ever-popular SSLAdapter.\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/5\n", + "sigmavirus24/requests-toolbelt#6: \"Mention SSLAdapter in README.\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/6\n", + "sigmavirus24/requests-toolbelt#7: \"Many docs updates\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/7\n", + "sigmavirus24/requests-toolbelt#8: \"Invalid multipart encoding with a file\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/8\n", + "sigmavirus24/requests-toolbelt#9: \"'file' does not have the buffer interface\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/9\n", + "sigmavirus24/requests-toolbelt#10: \"pip install fails with requests 1.2.3\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/10\n", + "sigmavirus24/requests-toolbelt#11: \"Get version info from a file that actually exists\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/11\n", + "sigmavirus24/requests-toolbelt#12: \"MultipartEncoder: added callback support and bytes read counter\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/12\n", + "sigmavirus24/requests-toolbelt#13: \"add explicit utf-8 encoding\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/13\n", + "sigmavirus24/requests-toolbelt#14: \"Added MultipartDecoder.\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/14\n", + "sigmavirus24/requests-toolbelt#15: \"Adding Multipart Decoder, redux\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/15\n", + "sigmavirus24/requests-toolbelt#16: \"`MultipartEncoder` not fully compliant with RFC 1521\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/16\n", + "sigmavirus24/requests-toolbelt#17: \"MultipartEncoder sometimes add bytes\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/17\n", + "sigmavirus24/requests-toolbelt#18: \"Slightly refactored MultipartEncoder + improved unit tests\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/18\n", + "sigmavirus24/requests-toolbelt#19: \"IPv6 Transport Adapter\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/19\n", + "sigmavirus24/requests-toolbelt#20: \"README.rst: minor edits, syntax highlighting\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/20\n", + "sigmavirus24/requests-toolbelt#21: \"WIP: AuthHandler\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/21\n", + "sigmavirus24/requests-toolbelt#22: \"Add Monitor for MultipartEncoder\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/22\n", + "sigmavirus24/requests-toolbelt#23: \"Add encoding comment to `*.py`\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/23\n", + "sigmavirus24/requests-toolbelt#24: \"Import metadata from package to setup.py\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/24\n", + "sigmavirus24/requests-toolbelt#25: \"Import authors to setup.py\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/25\n", + "sigmavirus24/requests-toolbelt#26: \"illegal seek uploading data stream\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/26\n", + "sigmavirus24/requests-toolbelt#27: \"Request for Comments: Implement RFC 5987\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/27\n", + "sigmavirus24/requests-toolbelt#28: \"GuessAuth\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/28\n", + "sigmavirus24/requests-toolbelt#29: \"Multipart encoder cannot be reused\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/29\n", + "sigmavirus24/requests-toolbelt#30: \"File object not closed\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/30\n", + "sigmavirus24/requests-toolbelt#31: \"MultipartEncoder.read() returns less than 8192 bytes even when more bytes are left\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/31\n", + "sigmavirus24/requests-toolbelt#32: \"Duplicated content in user.rst and README.rst?\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/32\n", + "sigmavirus24/requests-toolbelt#33: \"Add support for multipart/mixed\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/33\n", + "sigmavirus24/requests-toolbelt#34: \"SSLAdapter crashes if used with multiprocessing\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/34\n", + "sigmavirus24/requests-toolbelt#35: \"Add ssl_version to the list of attributes\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/35\n", + "sigmavirus24/requests-toolbelt#36: \"Some fields do not get uploaded\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/36\n", + "sigmavirus24/requests-toolbelt#37: \"Improve documentation\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/37\n", + "sigmavirus24/requests-toolbelt#38: \"Add from_file classmethod to StreamingIterator\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/38\n", + "sigmavirus24/requests-toolbelt#39: \"MultipartEncoder int encoding issues\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/39\n" + ] + } + ], + "prompt_number": 7 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [] + } + ], + "metadata": {} + } + ] +} \ No newline at end of file From aa7ff3074e369ac62cf7ba3bf2b27213e34c5d56 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 18 Aug 2014 21:53:10 -0500 Subject: [PATCH 384/972] Rename Milestone#labels --- github3/issues/milestone.py | 5 +- ...iter_labels.json => Milestone_labels.json} | 0 tests/integration/test_issues_milestone.py | 6 +- tests/unit/test_issues_milestone.py | 62 +++++++++++++++++++ 4 files changed, 67 insertions(+), 6 deletions(-) rename tests/cassettes/{Milestone_iter_labels.json => Milestone_labels.json} (100%) create mode 100644 tests/unit/test_issues_milestone.py diff --git a/github3/issues/milestone.py b/github3/issues/milestone.py index e051194f4..41b7c4d84 100644 --- a/github3/issues/milestone.py +++ b/github3/issues/milestone.py @@ -57,9 +57,8 @@ def delete(self): """ return self._boolean(self._delete(self._api), 204, 404) - def iter_labels(self, number=-1, etag=None): - """Iterate over the labels for every issue associated with this - milestone. + def labels(self, number=-1, etag=None): + r"""Iterate over the labels of every associated issue. .. versionchanged:: 0.9 diff --git a/tests/cassettes/Milestone_iter_labels.json b/tests/cassettes/Milestone_labels.json similarity index 100% rename from tests/cassettes/Milestone_iter_labels.json rename to tests/cassettes/Milestone_labels.json diff --git a/tests/integration/test_issues_milestone.py b/tests/integration/test_issues_milestone.py index 337d09c0c..8e1ab6639 100644 --- a/tests/integration/test_issues_milestone.py +++ b/tests/integration/test_issues_milestone.py @@ -4,12 +4,12 @@ class TestMilestone(IntegrationHelper): - def test_iter_labels(self): + def test_labels(self): """Test the ability to iterate over milestone labels.""" - cassette_name = self.cassette_name('iter_labels') + cassette_name = self.cassette_name('labels') with self.recorder.use_cassette(cassette_name): issue = self.gh.issue('sigmavirus24', 'github3.py', 206) milestone = issue.milestone assert milestone is not None - for label in milestone.iter_labels(): + for label in milestone.labels(): assert isinstance(label, github3.issues.label.Label) diff --git a/tests/unit/test_issues_milestone.py b/tests/unit/test_issues_milestone.py new file mode 100644 index 000000000..b5fd128c8 --- /dev/null +++ b/tests/unit/test_issues_milestone.py @@ -0,0 +1,62 @@ +"""Unit tests for the Milestone class.""" +import github3 + +from .helper import (UnitIteratorHelper, create_url_helper,) + +example_data = { + "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", + "number": 1, + "state": "open", + "title": "v1.0", + "description": "", + "creator": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": ("https://api.github.com/users/octocat/following" + "{/other_user}"), + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": ("https://api.github.com/users/octocat/starred" + "{/owner}{/repo}"), + "subscriptions_url": ("https://api.github.com/users/octocat/" + "subscriptions"), + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": ("https://api.github.com/users/octocat/" + "received_events"), + "type": "User", + "site_admin": False + }, + "open_issues": 4, + "closed_issues": 8, + "created_at": "2011-04-10T20:09:31Z", + "updated_at": "2014-03-03T18:58:10Z", + "due_on": None +} + +url_for = create_url_helper("https://api.github.com/repos/octocat/Hello-World/" + "milestones/1") + + +class TestMilestoneIterator(UnitIteratorHelper): + + """Test Milestone methods that return iterators.""" + + described_class = github3.issues.milestone.Milestone + example_data = example_data + + def test_labels(self): + """Test the request to retrieve labels associated with a milestone.""" + i = self.instance.labels() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('labels'), + params={'per_page': 100}, + headers={} + ) From d59987f23f93f54bf466656a9e47918a63ad0659 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 19 Aug 2014 08:46:09 -0500 Subject: [PATCH 385/972] Add note to changelog about renaming Milestone#labels --- LATEST_VERSION_NOTES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/LATEST_VERSION_NOTES.rst b/LATEST_VERSION_NOTES.rst index 502b9af4f..f16ce3540 100644 --- a/LATEST_VERSION_NOTES.rst +++ b/LATEST_VERSION_NOTES.rst @@ -55,6 +55,7 @@ Old name New name ``Issue#iter_comments`` ``Issue#comments`` ``Issue#iter_events`` ``Issue#events`` ``Issue#iter_labels`` ``Issue#labels`` +``Milestone#iter_labels`` ``Milestone#labels`` ``Organization#iter_members`` ``Organization#members`` ``Organization#iter_public_members`` ``Organization#public_members`` ``Organization#iter_repos`` ``Organization#repositories`` From 27c95f14ce4057d3602e3ae34d09665234b7cddc Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 19 Aug 2014 09:02:26 -0500 Subject: [PATCH 386/972] Rename Deployment#statuses --- LATEST_VERSION_NOTES.rst | 1 + github3/repos/deployment.py | 2 +- tests/integration/test_repos_deployment.py | 4 +- tests/unit/test_repos_deployment.py | 70 ++++++++++++++++++++++ 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 tests/unit/test_repos_deployment.py diff --git a/LATEST_VERSION_NOTES.rst b/LATEST_VERSION_NOTES.rst index f16ce3540..daad0fc79 100644 --- a/LATEST_VERSION_NOTES.rst +++ b/LATEST_VERSION_NOTES.rst @@ -30,6 +30,7 @@ Old name New name ``github3.iter_user_repos`` ``github3.repositories_by`` ``github3.iter_starred`` ``github3.starred_by`` ``github3.iter_subscriptions`` ``github3.subscriptions_for`` +``Deployment#iter_statuses`` ``Deployment#statuses`` ``Gist#iter_comments`` ``Gist#comments`` ``Gist#iter_commits`` ``Gist#commits`` ``Gist#iter_files`` ``Gist#files`` diff --git a/github3/repos/deployment.py b/github3/repos/deployment.py index 99acb3abf..93087fc42 100644 --- a/github3/repos/deployment.py +++ b/github3/repos/deployment.py @@ -73,7 +73,7 @@ def create_status(self, state, target_url='', description=''): return DeploymentStatus(json, self) if json else None - def iter_statuses(self, number=-1, etag=None): + def statuses(self, number=-1, etag=None): """Iterate over the deployment statuses for this deployment. :param int number: (optional), the number of statuses to return. diff --git a/tests/integration/test_repos_deployment.py b/tests/integration/test_repos_deployment.py index a5bddaefe..65a0cf6ff 100644 --- a/tests/integration/test_repos_deployment.py +++ b/tests/integration/test_repos_deployment.py @@ -27,7 +27,7 @@ def test_create_status(self): assert isinstance(status, github3.repos.deployment.DeploymentStatus) - def test_iter_statuses(self): + def test_statuses(self): """Show that a user can retrieve deployment statuses.""" cassette_name = self.cassette_name('statuses') with self.recorder.use_cassette(cassette_name): @@ -36,7 +36,7 @@ def test_iter_statuses(self): deployment = find(lambda d: d.id == 801, repository.deployments()) assert deployment is not None - statuses = list(deployment.iter_statuses(5)) + statuses = list(deployment.statuses(5)) for status in statuses: assert isinstance(status, diff --git a/tests/unit/test_repos_deployment.py b/tests/unit/test_repos_deployment.py new file mode 100644 index 000000000..aa071b190 --- /dev/null +++ b/tests/unit/test_repos_deployment.py @@ -0,0 +1,70 @@ +"""Unit tests for Deployment methods.""" +import github3 + +from .helper import UnitIteratorHelper, create_url_helper + +url_for = create_url_helper( + 'https://api.github.com/repos/octocat/example/deployments/1' +) + +example_data = { + "url": "https://api.github.com/repos/octocat/example/deployments/1", + "id": 1, + "sha": "a84d88e7554fc1fa21bcbc4efae3c782a70d2b9d", + "ref": "master", + "task": "deploy", + "payload": { + "task": "deploy:migrate" + }, + "environment": "production", + "description": "Deploy request from hubot", + "creator": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "somehexcode", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": ("https://api.github.com/users/octocat/following" + "{/other_user}"), + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": ("https://api.github.com/users/octocat/starred" + "{/owner}{/repo}"), + "subscriptions_url": ("https://api.github.com/users/octocat/" + "subscriptions"), + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": ("https://api.github.com/users/octocat/" + "received_events"), + "type": "User", + "site_admin": False + }, + "created_at": "2012-07-20T01:19:13Z", + "updated_at": "2012-07-20T01:19:13Z", + "statuses_url": ("https://api.github.com/repos/octocat/example/" + "deployments/1/statuses"), + "repository_url": "https://api.github.com/repos/octocat/example" +} + + +class TestDeploymentIterators(UnitIteratorHelper): + + """Test Deployment methods that return iterators.""" + + described_class = github3.repos.deployment.Deployment + example_data = example_data + + def test_statuses(self): + """Test the request to retrieve a deployment's statuses.""" + i = self.instance.statuses() + self.get_next(i) + + self.session.get.assert_called_once_with( + url_for('statuses'), + params={'per_page': 100}, + headers={ + 'Accept': 'application/vnd.github.cannonball-preview+json' + } + ) From 1aebd6d0f45c19bcc301d2e8c8e827fa62477a6a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 19 Aug 2014 20:37:54 -0500 Subject: [PATCH 387/972] Re-rename github3.repository_issues --- LATEST_VERSION_NOTES.rst | 4 ++-- github3/__init__.py | 10 +++++----- github3/api.py | 12 ++++++------ github3/github.py | 7 +++---- tests/unit/test_api.py | 8 ++++---- tests/unit/test_github.py | 10 +++++----- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/LATEST_VERSION_NOTES.rst b/LATEST_VERSION_NOTES.rst index daad0fc79..e79531c25 100644 --- a/LATEST_VERSION_NOTES.rst +++ b/LATEST_VERSION_NOTES.rst @@ -25,7 +25,7 @@ Old name New name ``github3.iter_events`` ``github3.all_events`` ``github3.iter_followers`` ``github3.followers_of`` ``github3.iter_following`` ``github3.followed_by`` -``github3.iter_repo_issues`` ``github3.repository_issues`` +``github3.iter_repo_issues`` ``github3.issues_on`` ``github3.iter_orgs`` ``github3.organizations_with`` ``github3.iter_user_repos`` ``github3.repositories_by`` ``github3.iter_starred`` ``github3.starred_by`` @@ -47,7 +47,7 @@ Old name New name ``GitHub#iter_org_issues`` ``GitHub#organization_issues`` ``GitHub#iter_issues`` ``GitHub#issues`` ``GitHub#iter_user_issues`` ``GitHub#user_issues`` -``GitHub#iter_repo_issues`` ``GitHub#repository_issues`` +``GitHub#iter_repo_issues`` ``GitHub#issues_on`` ``GitHub#iter_keys`` ``GitHub#keys`` ``GitHub#iter_orgs`` ``GitHub#{organizations,organizations_with}`` ``GitHub#iter_repos`` ``GitHub#reposistories`` diff --git a/github3/__init__.py b/github3/__init__.py index 35147696d..0dbd7f1a0 100644 --- a/github3/__init__.py +++ b/github3/__init__.py @@ -20,7 +20,7 @@ from github3.api import ( authorize, login, enterprise_login, emojis, gist, gitignore_template, create_gist, issue, markdown, octocat, organization, pull_request, - followers_of, followed_by, public_gists, gists_by, repository_issues, + followers_of, followed_by, public_gists, gists_by, issues_on, gitignore_templates, all_repositories, all_users, all_events, organizations_with, repositories_by, starred_by, subscriptions_for, rate_limit, repository, search_code, search_repositories, search_users, @@ -34,8 +34,8 @@ 'login', 'enterprise_login', 'emojis', 'gist', 'gitignore_template', 'create_gist', 'issue', 'markdown', 'octocat', 'organization', 'pull_request', 'followers_of', 'followed_by', 'public_gists', 'gists_by', - 'repository_issues', 'gitignore_templates', 'all_repositories', - 'all_users', 'all_events', 'organizations_with', 'repositories_by', - 'starred_by', 'subscriptions_for', 'rate_limit', 'repository', - 'search_code', 'search_repositories', 'search_users', 'user', 'zen', + 'issues_on', 'gitignore_templates', 'all_repositories', 'all_users', + 'all_events', 'organizations_with', 'repositories_by', 'starred_by', + 'subscriptions_for', 'rate_limit', 'repository', 'search_code', + 'search_repositories', 'search_users', 'user', 'zen', ) diff --git a/github3/api.py b/github3/api.py index c6ac1b163..df9f9bfe6 100644 --- a/github3/api.py +++ b/github3/api.py @@ -233,9 +233,9 @@ def gists_by(username, number=-1, etag=None): return iter([]) -def repository_issues(owner, repository, milestone=None, state=None, - assignee=None, mentioned=None, labels=None, sort=None, - direction=None, since=None, number=-1, etag=None): +def issues_on(owner, repository, milestone=None, state=None, assignee=None, + mentioned=None, labels=None, sort=None, direction=None, + since=None, number=-1, etag=None): """Iterate over issues on owner/repository. :param str owner: login of the owner of the repository @@ -263,9 +263,9 @@ def repository_issues(owner, repository, milestone=None, state=None, """ if owner and repository: - return gh.repository_issues(owner, repository, milestone, state, - assignee, mentioned, labels, sort, - direction, since, number, etag) + return gh.issues_on(owner, repository, milestone, state, assignee, + mentioned, labels, sort, direction, since, number, + etag) return iter([]) diff --git a/github3/github.py b/github3/github.py index f9eb8f6ff..4e25f34c8 100644 --- a/github3/github.py +++ b/github3/github.py @@ -702,10 +702,9 @@ def user_issues(self, filter='', state='', labels='', sort='', params.update(per_page=per_page) return self._iter(int(number), url, Issue, params, etag) - def repository_issues(self, owner, repository, milestone=None, - state=None, assignee=None, mentioned=None, - labels=None, sort=None, direction=None, since=None, - number=-1, etag=None): + def issues_on(self, owner, repository, milestone=None, state=None, + assignee=None, mentioned=None, labels=None, sort=None, + direction=None, since=None, number=-1, etag=None): """List issues on owner/repository. Only owner and repository are required. diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 850c518d0..5fdcb59c2 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -145,12 +145,12 @@ def test_repository(self): self.gh.repository.assert_called_once_with('sigmavirus24', 'github3.py') - def test_repository_issues(self): - """Show that github3.repository_issues proxies to GitHub.""" + def test_issues_on(self): + """Show that github3.issues_on proxies to GitHub.""" args = ('owner', 'repository', None, None, None, None, None, None, None, None, -1, None) - github3.repository_issues(*args) - self.gh.repository_issues.assert_called_with(*args) + github3.issues_on(*args) + self.gh.issues_on.assert_called_with(*args) def test_repositories_by(self): """Show that github3.repositories_by proxies to GitHub.""" diff --git a/tests/unit/test_github.py b/tests/unit/test_github.py index fe645d0ab..0f90a8fd8 100644 --- a/tests/unit/test_github.py +++ b/tests/unit/test_github.py @@ -480,9 +480,9 @@ def test_repositories_requires_auth(self): with pytest.raises(GitHubError): self.instance.repositories() - def test_repository_issues(self): + def test_issues_on(self): """Show that a user can iterate over a repository's issues.""" - i = self.instance.repository_issues('owner', 'repo') + i = self.instance.issues_on('owner', 'repo') self.get_next(i) self.session.get.assert_called_once_with( @@ -491,11 +491,11 @@ def test_repository_issues(self): headers={} ) - def test_repository_issues_with_params(self): - """Show that #repository_issues accepts multiple parameters.""" + def test_issues_on_with_params(self): + """Show that #issues_on accepts multiple parameters.""" params = {'milestone': 1, 'state': 'all', 'assignee': 'owner', 'mentioned': 'someone', 'labels': 'bug,high'} - i = self.instance.repository_issues('owner', 'repo', **params) + i = self.instance.issues_on('owner', 'repo', **params) self.get_next(i) params.update(per_page=100) From b568ca4c80ae0e1955c5c96154cf0fe279cb2a52 Mon Sep 17 00:00:00 2001 From: Barry Morrison Date: Tue, 19 Aug 2014 18:56:33 -0700 Subject: [PATCH 388/972] fixes #272 --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 806050fbe..99267ed1d 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,8 @@ "github3.search", ] -kwargs['tests_require'] = ['betamax >=0.2.0', 'pytest'] +kwargs['tests_require'] = ['betamax >=0.2.0', 'pytest', + 'betamax-matchers>=0.1.0'] if sys.version_info < (3, 0): kwargs['tests_require'].append('unittest2 ==0.5.1') if sys.version_info < (3, 3): From e61f79d6343d81186be6eabe7bbf03db7ae1a154 Mon Sep 17 00:00:00 2001 From: Barry Morrison Date: Tue, 19 Aug 2014 18:59:12 -0700 Subject: [PATCH 389/972] to_json -> as_json --- github3/models.py | 2 +- tests/test_auths.py | 2 +- tests/test_events.py | 4 ++-- tests/test_gists.py | 4 ++-- tests/test_git.py | 4 ++-- tests/test_issues.py | 8 ++++---- tests/test_notifications.py | 2 +- tests/test_repos.py | 12 ++++++------ tests/test_users.py | 6 +++--- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/github3/models.py b/github3/models.py index 85925c6f8..6edd7002e 100644 --- a/github3/models.py +++ b/github3/models.py @@ -32,7 +32,7 @@ def __init__(self, json): self._uniq = json.get('url', None) self._json_data = json - def to_json(self): + def as_json(self): """Return the json representing this object.""" return self._json_data diff --git a/tests/test_auths.py b/tests/test_auths.py index 915063378..fdae2811f 100644 --- a/tests/test_auths.py +++ b/tests/test_auths.py @@ -10,7 +10,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestAuthorization, self).setUp() - self.auth = github3.auths.Authorization(self.auth.to_json(), self.g) + self.auth = github3.auths.Authorization(self.auth.as_json(), self.g) def test_equality(self): a = github3.auths.Authorization(load('authorization')) diff --git a/tests/test_events.py b/tests/test_events.py index 5440e2649..120a90a4b 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -12,7 +12,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestEvent, self).setUp() - self.ev = github3.events.Event(self.ev.to_json()) + self.ev = github3.events.Event(self.ev.as_json()) def test_equality(self): e = github3.events.Event(load('event')) @@ -21,7 +21,7 @@ def test_equality(self): assert self.ev != e def test_org(self): - json = self.ev.to_json().copy() + json = self.ev.as_json().copy() json['org'] = self.o ev = github3.events.Event(json) assert isinstance(ev.org, github3.orgs.Organization) diff --git a/tests/test_gists.py b/tests/test_gists.py index 7bf0dda8b..2ad454361 100644 --- a/tests/test_gists.py +++ b/tests/test_gists.py @@ -11,7 +11,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestGist, self).setUp() - self.gist = gists.Gist(self.gist.to_json(), self.g) + self.gist = gists.Gist(self.gist.as_json(), self.g) # As opposed to creating an all new class for this def test_history(self): @@ -34,7 +34,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestGistComment, self).setUp() - self.comment = gists.comment.GistComment(self.comment.to_json(), + self.comment = gists.comment.GistComment(self.comment.as_json(), self.g) def test_equality(self): diff --git a/tests/test_git.py b/tests/test_git.py index b56c9924f..59f31b0b6 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -28,7 +28,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestReference, self).setUp() - self.ref = github3.git.Reference(self.ref.to_json(), self.g) + self.ref = github3.git.Reference(self.ref.as_json(), self.g) def test_repr(self): assert repr(self.ref).startswith('' @@ -89,7 +89,7 @@ def test_delete(self): self.mock_assertions() def test_due_on(self): - json = self.m.to_json().copy() + json = self.m.as_json().copy() json['due_on'] = '2012-12-31T23:59:59Z' m = Milestone(json) assert isinstance(m.due_on, datetime.datetime) @@ -128,7 +128,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestIssue, self).setUp() - self.i = Issue(self.i.to_json(), self.g) + self.i = Issue(self.i.as_json(), self.g) def test_equality(self): i = Issue(load('issue')) diff --git a/tests/test_notifications.py b/tests/test_notifications.py index 70e0b9545..9f0e3c9c5 100644 --- a/tests/test_notifications.py +++ b/tests/test_notifications.py @@ -16,7 +16,7 @@ def test_equality(self): assert self.thread != t def test_last_read_at(self): - json = self.thread.to_json().copy() + json = self.thread.as_json().copy() json['last_read_at'] = '2013-12-31T23:59:59Z' t = github3.notifications.Thread(json) assert isinstance(t.last_read_at, datetime.datetime) diff --git a/tests/test_repos.py b/tests/test_repos.py index 0d9cb4c82..c0da8fb83 100644 --- a/tests/test_repos.py +++ b/tests/test_repos.py @@ -12,7 +12,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestRepository, self).setUp() - self.repo = repos.Repository(self.repo.to_json(), self.g) + self.repo = repos.Repository(self.repo.as_json(), self.g) self.api = 'https://api.github.com/repos/sigmavirus24/github3.py/' def test_add_collaborator(self): @@ -582,7 +582,7 @@ def test_milestone(self): self.mock_assertions() def test_parent(self): - json = self.repo.to_json().copy() + json = self.repo.as_json().copy() json['parent'] = json.copy() r = repos.Repository(json) assert isinstance(r.parent, repos.Repository) @@ -633,7 +633,7 @@ def test_repr(self): assert repr(self.repo) == '' def test_source(self): - json = self.repo.to_json().copy() + json = self.repo.as_json().copy() json['source'] = json.copy() r = repos.Repository(json) assert isinstance(r.source, repos.Repository) @@ -781,7 +781,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestContents, self).setUp() - self.contents = repos.contents.Contents(self.contents.to_json(), + self.contents = repos.contents.Contents(self.contents.as_json(), self.g) def test_equality(self): @@ -849,7 +849,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestHook, self).setUp() - self.hook = repos.hook.Hook(self.hook.to_json(), self.g) + self.hook = repos.hook.Hook(self.hook.as_json(), self.g) def test_equality(self): h = repos.hook.Hook(load('hook')) @@ -938,7 +938,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestRepoComment, self).setUp() - self.comment = repos.comment.RepoComment(self.comment.to_json(), + self.comment = repos.comment.RepoComment(self.comment.as_json(), self.g) def test_delete(self): diff --git a/tests/test_users.py b/tests/test_users.py index 0b0e969bc..e0775af29 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -15,10 +15,10 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestKey, self).setUp() - self.key = github3.users.Key(self.key.to_json(), self.g) + self.key = github3.users.Key(self.key.as_json(), self.g) def test_equality(self): - k = github3.users.Key(self.key.to_json()) + k = github3.users.Key(self.key.as_json()) assert self.key == k k._uniq += "cruft" assert self.key != k @@ -82,7 +82,7 @@ def __init__(self, methodName='runTest'): def setUp(self): super(TestUser, self).setUp() - self.user = github3.users.User(self.user.to_json(), self.g) + self.user = github3.users.User(self.user.as_json(), self.g) if hasattr(self.user.name, 'decode'): self.user.name = self.user.name.decode('utf-8') From 9da17d15998c8d9965e629e5a93c7de09e30c7b9 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 19 Aug 2014 21:22:10 -0500 Subject: [PATCH 390/972] Add alternative method for retrieving issues --- .../retrieving_issues_on_a_repository.ipynb | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/example-notebooks/retrieving_issues_on_a_repository.ipynb b/example-notebooks/retrieving_issues_on_a_repository.ipynb index 97549741d..47e9fde1e 100644 --- a/example-notebooks/retrieving_issues_on_a_repository.ipynb +++ b/example-notebooks/retrieving_issues_on_a_repository.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:fc7950b40a0653a8dc7ce1323731a435b263dc3b10b320ba7e6b3c74683ff36f" + "signature": "sha256:41b324ac4bdb6264f2a2aded77c9a351e233ca9a680d13755eb32864f541a747" }, "nbformat": 3, "nbformat_minor": 0, @@ -300,6 +300,60 @@ ], "prompt_number": 7 }, + { + "cell_type": "heading", + "level": 2, + "metadata": {}, + "source": [ + "An alternative method to retrieving issues on a repository" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for issue in github3.issues_on('sigmavirus24', 'requests-toolbelt'):\n", + " print('sigmavirus24/requests-toolbelt#{0.number}: \"{0.title}\"\\n\\t{0.html_url}'.format(issue))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "sigmavirus24/requests-toolbelt#39: \"MultipartEncoder int encoding issues\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/39\n", + "sigmavirus24/requests-toolbelt#38: \"Add from_file classmethod to StreamingIterator\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/38\n", + "sigmavirus24/requests-toolbelt#37: \"Improve documentation\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/37\n", + "sigmavirus24/requests-toolbelt#32: \"Duplicated content in user.rst and README.rst?\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/32\n", + "sigmavirus24/requests-toolbelt#30: \"File object not closed\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/30\n", + "sigmavirus24/requests-toolbelt#26: \"illegal seek uploading data stream\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/26\n", + "sigmavirus24/requests-toolbelt#21: \"WIP: AuthHandler\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/pull/21\n", + "sigmavirus24/requests-toolbelt#19: \"IPv6 Transport Adapter\"\n", + "\thttps://github.com/sigmavirus24/requests-toolbelt/issues/19\n" + ] + } + ], + "prompt_number": 3 + }, { "cell_type": "code", "collapsed": false, From 1a9503f8f36de67f14d349f3a75a0e7a9e3bf9da Mon Sep 17 00:00:00 2001 From: Barry Morrison Date: Tue, 19 Aug 2014 19:30:36 -0700 Subject: [PATCH 391/972] bye bye iter_ --- github3/users.py | 18 +++++----- tests/cassettes/User_orgs.json | 1 + tests/integration/test_users.py | 6 ++-- tests/test_users.py | 58 ++++++++++++++++----------------- tests/unit/test_users.py | 6 ++++ 5 files changed, 48 insertions(+), 41 deletions(-) create mode 100644 tests/cassettes/User_orgs.json create mode 100644 tests/unit/test_users.py diff --git a/github3/users.py b/github3/users.py index 09c2a73b9..99be1371b 100644 --- a/github3/users.py +++ b/github3/users.py @@ -259,7 +259,7 @@ def is_following(self, login): url = self.following_urlt.expand(other_user=login) return self._boolean(self._get(url), 204, 404) - def iter_events(self, public=False, number=-1, etag=None): + def events(self, public=False, number=-1, etag=None): """Iterate over events performed by this user. :param bool public: (optional), only list public events for the @@ -276,7 +276,7 @@ def iter_events(self, public=False, number=-1, etag=None): url = self._build_url(*path, base_url=self._api) return self._iter(int(number), url, Event, etag=etag) - def iter_followers(self, number=-1, etag=None): + def followers(self, number=-1, etag=None): """Iterate over the followers of this user. :param int number: (optional), number of followers to return. Default: @@ -288,7 +288,7 @@ def iter_followers(self, number=-1, etag=None): url = self._build_url('followers', base_url=self._api) return self._iter(int(number), url, User, etag=etag) - def iter_following(self, number=-1, etag=None): + def following(self, number=-1, etag=None): """Iterate over the users being followed by this user. :param int number: (optional), number of users to return. Default: -1 @@ -300,7 +300,7 @@ def iter_following(self, number=-1, etag=None): url = self._build_url('following', base_url=self._api) return self._iter(int(number), url, User, etag=etag) - def iter_keys(self, number=-1, etag=None): + def keys(self, number=-1, etag=None): """Iterate over the public keys of this user. .. versionadded:: 0.5 @@ -314,7 +314,7 @@ def iter_keys(self, number=-1, etag=None): url = self._build_url('keys', base_url=self._api) return self._iter(int(number), url, Key, etag=etag) - def iter_org_events(self, org, number=-1, etag=None): + def org_events(self, org, number=-1, etag=None): """Iterate over events as they appear on the user's organization dashboard. You must be authenticated to view this. @@ -330,7 +330,7 @@ def iter_org_events(self, org, number=-1, etag=None): url = self._build_url('events', 'orgs', org, base_url=self._api) return self._iter(int(number), url, Event, etag=etag) - def iter_received_events(self, public=False, number=-1, etag=None): + def received_events(self, public=False, number=-1, etag=None): """Iterate over events that the user has received. If the user is the authenticated user, you will see private and public events, otherwise you will only see public events. @@ -349,7 +349,7 @@ def iter_received_events(self, public=False, number=-1, etag=None): url = self._build_url(*path, base_url=self._api) return self._iter(int(number), url, Event, etag=etag) - def iter_orgs(self, number=-1, etag=None): + def orgs(self, number=-1, etag=None): """Iterate over organizations the user is member of :param int number: (optional), number of organizations to return. @@ -363,7 +363,7 @@ def iter_orgs(self, number=-1, etag=None): url = self._build_url('orgs', base_url=self._api) return self._iter(int(number), url, Organization, etag=etag) - def iter_starred(self, sort=None, direction=None, number=-1, etag=None): + def starred(self, sort=None, direction=None, number=-1, etag=None): """Iterate over repositories starred by this user. .. versionchanged:: 0.5 @@ -387,7 +387,7 @@ def iter_starred(self, sort=None, direction=None, number=-1, etag=None): url = self.starred_urlt.expand(owner=None, repo=None) return self._iter(int(number), url, Repository, params, etag) - def iter_subscriptions(self, number=-1, etag=None): + def subscriptions(self, number=-1, etag=None): """Iterate over repositories subscribed to by this user. :param int number: (optional), number of subscriptions to return. diff --git a/tests/cassettes/User_orgs.json b/tests/cassettes/User_orgs.json new file mode 100644 index 000000000..bc0877b9c --- /dev/null +++ b/tests/cassettes/User_orgs.json @@ -0,0 +1 @@ +{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/users/sigmavirus24"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA51UwY6bMBT8lZXPZA2EJMRStSv1tIdeqlaV9hI9jCFPNTayDVEabb+9z5Cuulyq5AQyM/PGg8cXpm2Lhgnmse1gRDf4vGAJw5qJvEjLdZowGCGAOwxOE+4YQu8F5/Oif2wxHIdq8MpJa4Iy4VHajg98Jj+Nn3JSa91VI8oymRXlerOty32zzzdqu8+zXVkpldX7NchmR4TFrB6vc2ZxGub5wvAxdHphcbY2URbgxmptT6Sy3NT/BvF3Jpmc39G0d6oQ88JtOCrKlrb0FoNCH243NbEuPD4OWEcdTz/MqfpmY1ce2ToZcnThTvV2EhwqLx32Aa253eAHNqlZ14LBX3CfGrE9iURrt1uZWMRWI53V2+kz7cJ7hyPIc4zGKalwpLDvlFzwSTGce0U9+U6HIkaPQR2g7mJNG9BeJcxAFwEvYB4+W1eDl5aAdNB7MGf68BXkT9+DVLRaUcOvvaXank4nKkSrsZp68RvlzOcTLKHrQE5/hRhfoEZvTfLw4yXm1QHG/lOVmwaCtJoMtXZ8pmsDdRQj0BGdgkqTt6vRCi0TZtA6Yf1QaZSHOX+x276vTKeXic3mb6Ool0xkWf5Pw+JlRBsk9UBBQyAjeZqlq7RYZem3tBDpTqzzV7Iw9PUHTLFKy1VOmEwUmdiUr+ztD7pxIqP1BAAA", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "132026e9262a0093e437f99db5f1e499", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"7c17b31ec8a4aabe24ff6539b2680b7e\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "59", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "AE3281C2:0875:1BDC46C6:53F404D5", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 20 Aug 2014 01:41:58 GMT", "date": "Wed, 20 Aug 2014 02:15:50 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408504550"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/users/sigmavirus24"}, "recorded_at": "2014-08-20T02:15:50"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/1.0.0"}, "method": "GET", "uri": "https://api.github.com/users/sigmavirus24/orgs?per_page=25"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA63W246CMBCA4XfptVkELIjJZh9kszGIFchy2lJMjPHdt7TDSW6GpnfG9B/jfKn4/SRFneYVOZFHXBZkR/IrOQUR9emOdLyQ72dCNO3JceIm/0hzkXWXj6QunZqnrQMNZ03dnnHHHXVYfhC7s0qgK31aZiUrL4yjOzj+dPSLl5zQdJciT84bBy2r+bz4HouYv3999WYLG+taxpO6EvIbq+V1jlrx1/3TI6/dZCAylmRxlTKJAhZu4B6CAIPxFmNR5tl2nEVtgLTobWAtBlpG0xYrteZ6+83F4EU9Nzx6GLCxw1LpYDsSdAY8UNqAgVG2SfS6Vyb6l8pvHgOLNHEp6h7NU6zM2GzHmVIDnym2QTRNs62kt79S4uyvY63oHwf9c8c77qnvu5i7MyuxRkOynWgsDYTG1gbQOMyyDyx+5VO3cQM21N8HfhhhbKDCuvTHt5uoysBDdTYs1CDLDrDklYP8U8CvbHjEBJ7rHqIjhmIKsRpQbAcZQgOTIbXBMsyyLAM7X8swLvJbDpck9CIv8FCXJBlDtIwuDGQgNJGB1IoMzLIsAztfyWTx+PCXR2hAQ8yFgQpr0h/fDqIqAw3V2aBQg+w79EvWDj//73hwnVkOAAA=", "encoding": "utf-8"}, "headers": {"vary": "Accept, Accept-Encoding", "x-served-by": "a1d8c69b807c8e21f06cad9da377d1b0", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"4ddbcc15e253ff01d7edec56cd7f8cb0\"", "access-control-allow-credentials": "true", "status": "200 OK", "x-ratelimit-remaining": "58", "x-github-media-type": "github.v3; param=full; 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", "transfer-encoding": "chunked", "x-github-request-id": "AE3281C2:0875:1BDC476F:53F404D6", "cache-control": "public, max-age=60, s-maxage=60", "date": "Wed, 20 Aug 2014 02:15:50 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1408504550"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/users/sigmavirus24/orgs?per_page=25"}, "recorded_at": "2014-08-20T02:15:50"}], "recorded_with": "betamax/0.4.0"} \ No newline at end of file diff --git a/tests/integration/test_users.py b/tests/integration/test_users.py index c462c24b6..1b0cf88ab 100644 --- a/tests/integration/test_users.py +++ b/tests/integration/test_users.py @@ -4,9 +4,9 @@ class TestUser(IntegrationHelper): - def test_iter_orgs(self): - cassette_name = self.cassette_name('iter_orgs') + def test_orgs(self): + cassette_name = self.cassette_name('orgs') with self.recorder.use_cassette(cassette_name): u = self.gh.user('sigmavirus24') - for o in u.iter_orgs(number=25): + for o in u.orgs(number=25): assert isinstance(o, github3.orgs.Organization) diff --git a/tests/test_users.py b/tests/test_users.py index e0775af29..b2d509bdd 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -188,76 +188,76 @@ def test_is_following(self): assert self.user.is_following('kennethreitz') self.mock_assertions() - def test_iter_events(self): + def test_events(self): self.response('event', 200, _iter=True) self.get(self.api + '/events') - assert isinstance(next(self.user.iter_events()), github3.events.Event) + assert isinstance(next(self.user.events()), github3.events.Event) self.mock_assertions() self.get(self.api + '/events/public') - next(self.user.iter_events(public=True)) + next(self.user.events(public=True)) self.mock_assertions() - def test_iter_followers(self): - self.response('user', 200, _iter=True) - self.get(self.api + '/followers') - - assert isinstance(next(self.user.iter_followers()), github3.users.User) - self.mock_assertions() - - def test_iter_following(self): - self.response('user', 200, _iter=True) - self.get(self.api + '/following') - - assert isinstance(next(self.user.iter_following()), github3.users.User) - self.mock_assertions() - - def test_iter_org_events(self): +# def test_followers(self): +# self.response('user', 200, _iter=True) +# self.get(self.api + '/followers') +# +# assert isinstance(next(self.user.followers()), github3.users.User) +# self.mock_assertions() +# +# def test_following(self): +# self.response('user', 200, _iter=True) +# self.get(self.api + '/following') +# +# assert isinstance(next(self.user.following()), github3.users.User) +# self.mock_assertions() +# + def test_org_events(self): self.response('event', 200, _iter=True) self.get(self.api + '/events/orgs/foo') with self.assertRaises(StopIteration): - next(self.user.iter_org_events(None)) + next(self.user.org_events(None)) self.not_called() - assert isinstance(next(self.user.iter_org_events('foo')), + assert isinstance(next(self.user.org_events('foo')), github3.events.Event) self.mock_assertions() - def test_iter_received_events(self): + def test_received_events(self): self.response('event', 200, _iter=True) self.get(self.api + '/received_events') - assert isinstance(next(self.user.iter_received_events()), + assert isinstance(next(self.user.received_events()), github3.events.Event) self.mock_assertions() self.get(self.api + '/received_events/public') - next(self.user.iter_received_events(public=True)) + next(self.user.received_events(public=True)) self.mock_assertions() - def test_iter_starred(self): + def test_starred(self): self.response('repo', 200, _iter=True) self.get(self.api + '/starred') - assert isinstance(next(self.user.iter_starred()), + assert isinstance(next(self.user.starred()), github3.repos.Repository) self.mock_assertions() - def test_iter_subscriptions(self): + def test_subscriptions(self): self.response('repo', 200, _iter=True) self.get(self.api + '/subscriptions') - assert isinstance(next(self.user.iter_subscriptions()), + assert isinstance(next(self.user.subscriptions()), github3.repos.Repository) self.mock_assertions() - def test_iter_keys(self): + def test_keys(self): self.response('key', 200, _iter=True) self.get(self.api + '/keys') - assert isinstance(next(self.user.iter_keys()), github3.users.Key) + assert isinstance(next(self.user.keys()), github3.users.Key) self.mock_assertions() def test_update(self): diff --git a/tests/unit/test_users.py b/tests/unit/test_users.py new file mode 100644 index 000000000..36ac573fb --- /dev/null +++ b/tests/unit/test_users.py @@ -0,0 +1,6 @@ +import pytest + +from github3 import GitHubError +from github3.users import User + +from .helper import UnitHelper, UnitIteratorHelper, create_url_helper From 212e1576c7a5e4858f86298b904e010de2687fe3 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 19 Aug 2014 21:44:47 -0500 Subject: [PATCH 392/972] Add a notebook about how to manage issues --- example-notebooks/managing_issues.ipynb | 403 ++++++++++++++++++++++++ 1 file changed, 403 insertions(+) create mode 100644 example-notebooks/managing_issues.ipynb diff --git a/example-notebooks/managing_issues.ipynb b/example-notebooks/managing_issues.ipynb new file mode 100644 index 000000000..03316e802 --- /dev/null +++ b/example-notebooks/managing_issues.ipynb @@ -0,0 +1,403 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:b8cf2efcee4cc8dbd7cc3243958fbb66c6b0bd59d6d977e1c84b98e3058a616a" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "Creating, Editing, Closing, and Adding Labels to Issues" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import github3" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import os" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "gh = github3.login(os.environ['GH_USERNAME'], os.environ['GH_PASSWORD'])" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've created an authenticated client, let's fetch the repository we need to create our issue on." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "r = gh.repository('github3py', 'fork_this')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we create the issue using the `create_issue` method on the `Repository` object. It only requires that you pass the first parameter, `title`, to give the issue a title. The next parameter is `body` and it allows you to provide a description of the bug." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "i = r.create_issue('Here is a title', body='I ran into this bug using version 0.1-alpha the other day ...')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 5 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "repr(i)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 6, + "text": [ + "''" + ] + } + ], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What if we accidentally created an invalid bug report? We can close it right from here!" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "help(i.close)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Help on method close in module github3.issues.issue:\n", + "\n", + "close() method of github3.issues.issue.Issue instance\n", + " Close this issue.\n", + " \n", + " :returns: bool\n", + "\n" + ] + } + ], + "prompt_number": 7 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "i.close()" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 8, + "text": [ + "True" + ] + } + ], + "prompt_number": 8 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But actually, we were just able to reproduce the issue. Let's re-open it, then we'll add some more details to the description." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "i.reopen()" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 9, + "text": [ + "True" + ] + } + ], + "prompt_number": 9 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "body = i.body" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 10 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "i.edit(body=(body + 'I tried to call reopen on an open issue and then ...'))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 11, + "text": [ + "True" + ] + } + ], + "prompt_number": 11 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print(i.body)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "I ran into this bug using version 0.1-alpha the other day ...I tried to call reopen on an open issue and then ...\n" + ] + } + ], + "prompt_number": 12 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can even add comments" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "comment = i.create_comment('Thanks for this bug report!')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 13 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "repr(comment)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 14, + "text": [ + "''" + ] + } + ], + "prompt_number": 14 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, if you're a collaborator on a repository, you can add labels or a milestone to an issue." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "i.add_labels('enhancement', 'bug')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 15, + "text": [ + "[