Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • github3/github3.py
1 result
Show changes
Commits on Source (35)
Showing with 716 additions and 88 deletions
Loading
Loading
@@ -17,8 +17,6 @@ matrix:
include:
- python: 2.7
env: TOXENV=py27 REQUESTS_VERSION="===2.0.1"
- python: 3.3
env: TOXENV=py33 REQUESTS_VERSION="===2.0.1"
- python: 3.4
env: TOXENV=py34 REQUESTS_VERSION="===2.0.1"
- python: 3.5
Loading
Loading
@@ -27,8 +25,6 @@ matrix:
env: TOXENV=pypy REQUESTS_VERSION="===2.0.1"
- python: 2.7
env: TOXENV=py27 REQUESTS_VERSION=""
- python: 3.3
env: TOXENV=py33 REQUESTS_VERSION=""
- python: 3.4
env: TOXENV=py34 REQUESTS_VERSION=""
- python: 3.5
Loading
Loading
Loading
Loading
@@ -146,3 +146,9 @@ Contributors
- Björn Kautler (@Vampire)
 
- David Prothero (@dprothero)
- Jesse Keating (@omgjlk)
- @rco-ableton
- Mark Troyer (@discogestalt)
Loading
Loading
@@ -8,10 +8,6 @@ environment:
TOXENV: py27
- PYTHON: "C:\\Python27-x64"
TOXENV: py27
- PYTHON: "C:\\Python33"
TOXENV: py33
- PYTHON: "C:\\Python33-x64"
TOXENV: py33
- PYTHON: "C:\\Python34"
TOXENV: py34
- PYTHON: "C:\\Python34-x64"
Loading
Loading
.
#coverage==3.5.2
mock==1.0.1
pytest>=2.3.5
pytest>=2.3.5,<3.3.0
wheel==0.21.0
betamax>=0.5.0
betamax_matchers>=0.2.0
Loading
Loading
Loading
Loading
@@ -9,7 +9,7 @@ Creating a Blob Object
----------------------
 
One of the really cool (and under used, it seems) parts of the GitHub API
involves the ability to create commit and blob objects.
involves the ability to create blob objects.
 
.. code-block:: python
 
Loading
Loading
Loading
Loading
@@ -121,6 +121,13 @@ Creating a new repository
if r:
print("Created {0} successfully.".format(r.name))
 
Create a commit to change an existing file
------------------------------------------
::
repo.contents('/README.md').update('commit message', 'file content'.encode('utf-8'))
Follow another user on GitHub
-----------------------------
 
Loading
Loading
Loading
Loading
@@ -285,7 +285,7 @@ def organizations_with(username, number=-1, etag=None):
:param str etag: (optional), ETag from a previous request to the same
endpoint
:returns: generator of
:class:`Organization <github3.orgs.Organization>`
:class:`ShortOrganization <github3.orgs.ShortOrganization>`
 
"""
return gh.organizations_with(username, number, etag)
Loading
Loading
Loading
Loading
@@ -32,6 +32,24 @@ class EventUser(GitHubCore):
return self._instance_or_null(users.User, json)
 
 
class EventOrganization(GitHubCore):
"""The class that represents the org information returned in Events."""
def _update_attributes(self, org):
self.avatar_url = org['avatar_url']
self.gravatar_id = org['id']
self.id = org['id']
self.login = org['login']
self._api = self.url = org['url']
def to_org(self):
"""Retrieve a full Organization object for this EventOrganization."""
from . import orgs
url = self._build_url('orgs', self.login)
json = self._json(self._get(url), 200)
return self._instance_or_null(orgs.Organization, json)
class Event(GitHubCore):
 
"""The :class:`Event <Event>` object. It structures and handles the data
Loading
Loading
@@ -56,7 +74,6 @@ class Event(GitHubCore):
# not want to do:
event = copy.deepcopy(event)
 
from .orgs import Organization
#: :class:`User <github3.users.User>` object representing the actor.
self.actor = self._class_attribute(event, 'actor', EventUser)
#: datetime object representing when the event was created.
Loading
Loading
@@ -66,7 +83,7 @@ class Event(GitHubCore):
self.id = self._get_attribute(event, 'id')
 
#: List all possible types of Events
self.org = self._class_attribute(event, 'org', Organization)
self.org = self._class_attribute(event, 'org', EventOrganization)
 
#: Event type https://developer.github.com/v3/activity/events/types/
self.type = self._get_attribute(event, 'type')
Loading
Loading
Loading
Loading
@@ -18,7 +18,7 @@ class GitHubError(Exception):
#: List of errors provided by GitHub
if error.get('errors'):
self.errors = error.get('errors')
except: # Amazon S3 error
except Exception: # Amazon S3 error
self.msg = resp.content or '[No message]'
 
def __repr__(self):
Loading
Loading
@@ -34,6 +34,22 @@ class GitHubError(Exception):
return self.msg
 
 
class IncompleteResponse(GitHubError):
"""Exception for a response that doesn't have everything it should."""
def __init__(self, json, exception):
self.response = None
self.code = None
self.json = json
self.errors = []
self.exception = exception
self.msg = (
"The library was expecting more data in the response (%r)."
" Either GitHub modified it's response body, or your token"
" is not properly scoped to retrieve this information."
) % (exception,)
class ResponseError(GitHubError):
"""The base exception for errors stemming from GitHub responses."""
pass
Loading
Loading
Loading
Loading
@@ -17,7 +17,8 @@ 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 .orgs import Membership, ShortOrganization, Organization, Team
from .projects import Project, ProjectCard, ProjectColumn
from .pulls import PullRequest
from .repos.repo import Repository, repo_issue_params
from .search import (CodeSearchResult, IssueSearchResult,
Loading
Loading
@@ -105,11 +106,11 @@ class GitHub(GitHubCore):
endpoint
:param int per_page: (optional), number of organizations to list per
request
:returns: generator of :class:`Organization
<github3.orgs.Organization>`
:returns: generator of :class:`ShortOrganization
<github3.orgs.ShortOrganization>`
"""
url = self._build_url('organizations')
return self._iter(int(number), url, Organization,
return self._iter(int(number), url, ShortOrganization,
params={'since': since, 'per_page': per_page},
etag=etag)
 
Loading
Loading
@@ -921,10 +922,10 @@ class GitHub(GitHubCore):
:param str etag: (optional), ETag from a previous request to the same
endpoint
:returns: generator of
:class:`Organization <github3.orgs.Organization>`\ s
:class:`ShortOrganization <github3.orgs.ShortOrganization>`\ s
"""
url = self._build_url('user', 'orgs')
return self._iter(int(number), url, Organization, etag=etag)
return self._iter(int(number), url, ShortOrganization, etag=etag)
 
def organizations_with(self, username, number=-1, etag=None):
"""Iterate over organizations with ``username`` as a public member.
Loading
Loading
@@ -939,13 +940,55 @@ class GitHub(GitHubCore):
:param str etag: (optional), ETag from a previous request to the same
endpoint
:returns: generator of
:class:`Organization <github3.orgs.Organization>`\ s
:class:`ShortOrganization <github3.orgs.ShortOrganization>`\ s
"""
if username:
url = self._build_url('users', username, 'orgs')
return self._iter(int(number), url, Organization, etag=etag)
return self._iter(int(number), url, ShortOrganization, etag=etag)
return iter([])
 
def project(self, number):
"""Return the Project with id ``number``.
:param int number: id of the project
:returns: :class:`Project <github3.projects.Project>`
"""
number = int(number)
json = None
if number > 0:
url = self._build_url('projects', str(number))
json = self._json(self._get(
url, headers=Project.CUSTOM_HEADERS), 200)
return self._instance_or_null(Project, json)
def project_card(self, number):
"""Return the ProjectCard with id ``number``.
:param int number: id of the project card
:returns: :class:`ProjectCard <github3.projects.ProjectCard>`
"""
number = int(number)
json = None
if number > 0:
url = self._build_url('projects', 'columns', 'cards', str(number))
json = self._json(self._get(
url, headers=Project.CUSTOM_HEADERS), 200)
return self._instance_or_null(ProjectCard, json)
def project_column(self, number):
"""Return the ProjectColumn with id ``number``.
:param int number: id of the project column
:returns: :class:`ProjectColumn <github3.projects.ProjectColumn>`
"""
number = int(number)
json = None
if number > 0:
url = self._build_url('projects', 'columns', str(number))
json = self._json(self._get(
url, headers=Project.CUSTOM_HEADERS), 200)
return self._instance_or_null(ProjectColumn, json)
def public_gists(self, number=-1, etag=None):
"""Retrieve all public gists and iterate over them.
 
Loading
Loading
@@ -1705,12 +1748,12 @@ class GitHubEnterprise(GitHub):
:param str login: (required), The user's username.
:param str email: (required), The user's email address.
 
:returns: :class:`User <github3.users.User>`, if successful
:returns: :class:`ShortUser <github3.users.ShortUser>`, if successful
"""
url = self._build_url('admin', 'users')
payload = {'login': login, 'email': email}
json_data = self._json(self._post(url, data=payload), 201)
return self._instance_or_null(users.User, json_data)
return self._instance_or_null(users.ShortUser, json_data)
 
@requires_auth
def admin_stats(self, option):
Loading
Loading
Loading
Loading
@@ -48,7 +48,10 @@ class GitHubCore(object):
self.last_modified = json.pop('Last-Modified', None)
self._uniq = json.get('url', None)
self._json_data = json
self._update_attributes(json)
try:
self._update_attributes(json)
except KeyError as kerr:
raise exceptions.IncompleteResponse(json, kerr)
 
def _update_attributes(self, json):
pass
Loading
Loading
# -*- coding: utf-8 -*-
"""
github3.orgs
============
This module contains all of the classes related to organizations.
"""
"""This module contains all of the classes related to organizations."""
from __future__ import unicode_literals
 
import warnings
Loading
Loading
@@ -13,30 +7,22 @@ from json import dumps
 
from uritemplate import URITemplate
 
from . import users
from . import users, models
 
from .decorators import requires_auth
from .events import Event
from .models import BaseAccount, GitHubCore
from .projects import Project
from .repos import Repository
 
 
class Team(GitHubCore):
class Team(models.GitHubCore):
 
"""The :class:`Team <Team>` object.
 
Two team instances can be checked like so::
t1 == t2
t1 != t2
And is equivalent to::
t1.id == t2.id
t1.id != t2.id
See also: http://developer.github.com/v3/orgs/teams/
Please see GitHub's `Team Documentation`_ for more information.
 
.. _Team Documentation:
http://developer.github.com/v3/orgs/teams/
"""
 
# Roles available to members on a team.
Loading
Loading
@@ -92,11 +78,16 @@ class Team(GitHubCore):
def add_repository(self, repository, permission=''):
"""Add ``repository`` to this team.
 
If a permission is not provided, the team's default permission
will be assigned, by GitHub.
:param str repository: (required), form: 'user/repo'
:param str permission: (optional), ('pull', 'push', 'admin')
:returns: bool
"""
data = {'permission': permission}
data = {}
if permission:
data = {'permission': permission}
url = self._build_url('repos', repository, base_url=self._api)
return self._boolean(self._put(url, data=dumps(data)), 204, 404)
 
Loading
Loading
@@ -243,22 +234,14 @@ class Team(GitHubCore):
return self._boolean(self._delete(url), 204, 404)
 
 
class Organization(BaseAccount):
class _Organization(models.GitHubCore):
 
"""The :class:`Organization <Organization>` object.
 
Two organization instances can be checked like so::
o1 == o2
o1 != o2
And is equivalent to::
o1.id == o2.id
o1.id != o2.id
See also: http://developer.github.com/v3/orgs/
Please see GitHub's `Organization Documentation`_ for more information.
 
.. _Organization Documentation:
http://developer.github.com/v3/orgs/
"""
 
# Filters available when listing members. Note: ``"2fa_disabled"``
Loading
Loading
@@ -269,23 +252,30 @@ class Organization(BaseAccount):
members_roles = frozenset(['all', 'admin', 'member'])
 
def _update_attributes(self, org):
super(Organization, self)._update_attributes(org)
self.type = self.type or 'Organization'
#: URL of the avatar at gravatar
self.avatar_url = org['avatar_url']
# Set the type of object (this doens't come through API data)
self.type = 'Organization'
self.url = self._api = org['url']
#: Unique ID of the account
self.id = org['id']
 
#: Events url (not a template)
self.events_url = self._get_attribute(org, 'events_url')
#: Number of private repositories.
self.private_repos = self._get_attribute(org, 'private_repos')
#: Name of the organization
self.login = org['login']
 
#: Public Members URL Template. Expands with ``member``
self.public_members_urlt = self._class_attribute(
org,
'public_members_url',
URITemplate
)
self.public_members_urlt = URITemplate(org['public_members_url'])
#: Various urls (not templates)
for urltype in ('avatar_url', 'events_url', 'issues_url',
'repos_url'):
setattr(self, urltype, org[urltype])
 
#: Repositories url (not a template)
self.repos_url = self._get_attribute(org, 'repos_url')
def _repr(self):
return '<Organization [{s.login}:{s.name}]>'.format(s=self)
 
@requires_auth
def add_member(self, username, team_id):
Loading
Loading
@@ -327,7 +317,7 @@ class Organization(BaseAccount):
return self._boolean(self._put(url), 204, 404)
 
@requires_auth
def add_repository(self, repository, team_id):
def add_repository(self, repository, team_id): # FIXME(jlk): add perms
"""Add ``repository`` to ``team``.
 
.. versionchanged:: 1.0
Loading
Loading
@@ -346,6 +336,22 @@ class Organization(BaseAccount):
url = self._build_url('teams', str(team_id), 'repos', str(repository))
return self._boolean(self._put(url), 204, 404)
 
@requires_auth
def create_project(self, name, body=''):
"""Create a project for this organization.
If the client is authenticated and a member of the organization, this
will create a new project in the organization.
:param str name: (required), name of the project
:param str body: (optional), the body of the project
"""
url = self._build_url('projects', base_url=self._api)
data = {'name': name, 'body': body}
json = self._json(self._post(
url, data, headers=Project.CUSTOM_HEADERS), 201)
return self._instance_or_null(Project, json)
@requires_auth
def create_repository(self, name, description='', homepage='',
private=False, has_issues=True, has_wiki=True,
Loading
Loading
@@ -398,7 +404,7 @@ class Organization(BaseAccount):
return self._boolean(self._delete(url), 204, 404)
 
@requires_auth
def create_team(self, name, repo_names=[], permission=''):
def create_team(self, name, repo_names=[], permission='pull'):
"""Create a new team and return it.
 
This only works if the authenticated user owns this organization.
Loading
Loading
@@ -548,6 +554,35 @@ class Organization(BaseAccount):
url = self._build_url('public_members', base_url=self._api)
return self._iter(int(number), url, users.ShortUser, etag=etag)
 
def project(self, id, etag=None):
"""Return the organization project with the given ID.
:param int id: (required), ID number of the project
:returns: :class:`Project <github3.projects.Project>` if successful,
otherwise None
"""
url = self._build_url('projects', id, base_url=self._github_url)
json = self._json(self._get(url, headers=Project.CUSTOM_HEADERS), 200)
return self._instance_or_null(Project, json)
def projects(self, number=-1, etag=None):
"""Iterate over projects for this organization.
:param int number: (optional), number of members to return. Default:
-1 will return all available.
:param str etag: (optional), ETag from a previous request to the same
endpoint
:returns: generator of :class:`Project <github3.projects.Project>`
"""
url = self._build_url('projects', base_url=self._api)
return self._iter(
int(number),
url,
Project,
etag=etag,
headers=Project.CUSTOM_HEADERS
)
def repositories(self, type='', number=-1, etag=None):
r"""Iterate over repos for this organization.
 
Loading
Loading
@@ -628,7 +663,75 @@ class Organization(BaseAccount):
return self._instance_or_null(Team, json)
 
 
class Membership(GitHubCore):
class ShortOrganization(_Organization):
"""Object for the shortened representation of an Organization.
GitHub's API returns different amounts of information about orgs based
upon how that information is retrieved. Often times, when iterating over
several orgs, GitHub will return less information. To provide a clear
distinction between the types of orgs, github3.py uses different classes
with different sets of attributes.
.. versionadded:: 1.0.0
"""
pass
class Organization(_Organization):
"""Object for the full representation of a Organization.
GitHub's API returns different amounts of information about orgs based
upon how that information is retrieved. This object exists to represent
the full amount of information returned for a specific org. For example,
you would receive this class when calling
:meth:`~github3.github.GitHub.organization`. To provide a clear
distinction between the types of orgs, github3.py uses different classes
with different sets of attributes.
.. versionchanged:: 1.0.0
"""
def _update_attributes(self, org):
super(Organization, self)._update_attributes(org)
# this may be blank if the org hasn't set it
#: URL of the blog
self.blog = self._get_attribute(org, 'blog')
#: Name of the company
self.company = self._get_attribute(org, 'company')
#: datetime object representing the date the account was created
self.created_at = org['created_at']
#: E-mail address of the org
self.email = self._get_attribute(org, 'email')
# The number of people following this org
#: Number of followers
self.followers_count = org['followers']
# The number of people this org follows
#: Number of people the org is following
self.following_count = org['following']
#: Location of the org
self.location = self._get_attribute(org, 'location')
#: Display name of the org
self.name = self._get_attribute(org, 'name')
# The number of public_repos
#: Number of public repos owned by the org
self.public_repos_count = org['public_repos']
# e.g. https://github.com/self._login
#: URL of the org's profile
self.html_url = org['html_url']
class Membership(models.GitHubCore):
 
"""The wrapper for information about Team and Organization memberships."""
 
Loading
Loading
@@ -639,7 +742,7 @@ class Membership(GitHubCore):
self._api = self._get_attribute(membership, 'url')
 
self.organization = self._class_attribute(
membership, 'organization', Organization, self
membership, 'organization', ShortOrganization, self
)
 
self.organization_url = self._get_attribute(
Loading
Loading
@@ -665,7 +768,7 @@ class Membership(GitHubCore):
"""
if state and state.lower() == 'active':
data = dumps({'state': state.lower()})
json = self._json(self._patch(self._api, data=data))
json = self._json(self._patch(self._api, data=data), 200)
self._update_attributes(json)
return True
return False
# -*- coding: utf-8 -*-
"""
github3.projects
=============
This module contains all the classes relating to projects.
"""
from json import dumps
from . import models
from . import users
from .decorators import requires_auth
class Project(models.GitHubCore):
"""The :class:`Project <Project>` object.
See http://developer.github.com/v3/projects/
"""
CUSTOM_HEADERS = {
'Accept': 'application/vnd.github.inertia-preview+json',
}
def _update_attributes(self, project):
self._api = project['url']
#: The body of the project
self.body = project['body']
#: datetime object representing when the project was created
self.created_at = self._strptime(project['created_at'])
#: The user who created this project
self.creator = users.ShortUser(project['creator'], self)
#: The unique ID of the project
self.id = project['id']
#: The name of this project
self.name = project['name']
#: The number of the project
self.number = project['number']
#: The owner repo or organisation of this project
self.owner_url = project['owner_url']
#: datetime object representing the last time the object was changed
self.updated_at = self._strptime(project['updated_at'])
def _repr(self):
return '<Project [#{0}]>'.format(self.id)
def column(self, id):
"""Get a project column with the given ID.
:param int id: (required), the column ID
:returns: :class:`ProjectColumn <github3.projects.ProjectColumn>`
or None
"""
url = self._build_url(
'projects', 'columns', str(id), base_url=self._github_url)
json = self._json(self._get(url, headers=Project.CUSTOM_HEADERS), 200)
return self._instance_or_null(ProjectColumn, json)
def columns(self, number=-1, etag=None):
"""Iterate over the columns in this project.
:param int number: (optional), number of columns to return. Default:
-1 returns all available columns.
:param str etag: (optional), ETag from a previous request to the same
endpoint
:returns: generator of
:class:`ProjectColumn <github3.project.ProjectColumn>`
"""
url = self._build_url(
'projects', str(self.id), 'columns', base_url=self._github_url)
return self._iter(
int(number),
url,
ProjectColumn,
headers=Project.CUSTOM_HEADERS,
etag=etag
)
@requires_auth
def create_column(self, name):
"""Create a column in this project.
:param str name: (required), name of the column
:returns: :class:`ProjectColumn <github3.projects.ProjectColumn>`
or none
"""
url = self._build_url('columns', base_url=self._api)
json = None
if name:
json = self._json(self._post(
url, data={'name': name}, headers=Project.CUSTOM_HEADERS), 201)
return self._instance_or_null(ProjectColumn, json)
@requires_auth
def delete(self):
"""Delete this project.
:returns: bool
"""
return self._boolean(self._delete(
self._api, headers=self.CUSTOM_HEADERS), 204, 404)
@requires_auth
def update(self, name=None, body=None):
"""Update this project.
:param str name: (optional), name of the project
:param str body: (optional), body of the project
:returns: bool
"""
data = {'name': name, 'body': body}
json = None
self._remove_none(data)
if data:
json = self._json(self._patch(
self._api, data=dumps(data), headers=self.CUSTOM_HEADERS), 200)
if json:
self._update_attributes(json)
return True
return False
class ProjectColumn(models.GitHubCore):
"""The :class:`ProjectColumn <ProjectColumn>` object.
See http://developer.github.com/v3/projects/columns/
"""
def _update_attributes(self, project_column):
#: datetime object representing the last time the object was created
self.created_at = self._strptime(project_column['created_at'])
#: The ID of this column
self.id = project_column['id']
#: The name of this column
self.name = project_column['name']
#: The URL of this column's project
self.project_url = project_column['project_url']
#: datetime object representing the last time the object was changed
self.updated_at = self._strptime(project_column['updated_at'])
def _repr(self):
return '<ProjectColumn [#{0}]>'.format(self.id)
def card(self, id):
"""Get a project card with the given ID.
:param int id: (required), the card ID
:returns: :class:`ProjectCard <github3.projects.ProjectCard>` or None
"""
url = self._build_url(
'projects/columns/cards', str(id), base_url=self._github_url)
json = self._json(self._get(url, headers=Project.CUSTOM_HEADERS), 200)
return self._instance_or_null(ProjectCard, json)
def cards(self, number=-1, etag=None):
"""Iterate over the cards in this column.
:param int number: (optional), number of cards to return. Default:
-1 returns all available cards.
:param str etag: (optional), ETag from a previous request to the same
endpoint
:returns: generator of
:class:`ProjectCard <github3.project.ProjectCard>`
"""
url = self._build_url(
'projects/columns',
str(self.id),
'cards',
base_url=self._github_url
)
return self._iter(
int(number),
url,
ProjectCard,
headers=Project.CUSTOM_HEADERS,
etag=etag
)
@requires_auth
def create_card_with_content_id(self, content_id, content_type):
"""Create a content card in this project column.
:param int content_id: (required), the ID of the content
:param str content_type: (required), the type of the content
:returns: :class:`ProjectCard <github3.projects.ProjectCard>` or none
"""
if not content_id or not content_type:
return None
url = self._build_url(
'projects/columns',
str(self.id),
'cards',
base_url=self._github_url
)
json = None
data = {'content_id': content_id, 'content_type': content_type}
json = self._json(self._post(
url, data=data, headers=Project.CUSTOM_HEADERS), 201)
return self._instance_or_null(ProjectCard, json)
@requires_auth
def create_card_with_issue(self, issue):
"""Create a card in this project column linked with an Issue.
:param :class:`Issue <github3.issues.Issue>`: (required), an issue
with which to link the card
:returns: :class:`ProjectCard <github3.projects.ProjectCard>` or none
"""
if not issue:
return None
return self.create_card_with_content_id(issue.id, 'Issue')
@requires_auth
def create_card_with_note(self, note):
"""Create a note card in this project column.
:param str note: (required), the note content
:returns: :class:`ProjectCard <github3.projects.ProjectCard>` or none
"""
url = self._build_url(
'projects/columns',
str(self.id),
'cards',
base_url=self._github_url
)
json = None
if note:
json = self._json(self._post(
url, data={'note': note}, headers=Project.CUSTOM_HEADERS), 201)
return self._instance_or_null(ProjectCard, json)
@requires_auth
def delete(self):
"""Delete this column.
:returns: bool
"""
url = self._build_url(
'projects/columns', self.id, base_url=self._github_url)
return self._boolean(self._delete(
url, headers=Project.CUSTOM_HEADERS), 204, 404)
@requires_auth
def move(self, position):
"""Move this column.
:param str position: (required), can be one of `first`, `last`,
or `after:<column-id>`, where `<column-id>` is the id value
of a column in the same project.
:returns: bool
"""
if not position:
return False
url = self._build_url(
'projects/columns',
self.id,
'moves',
base_url=self._github_url
)
data = {'position': position}
return self._boolean(self._post(
url, data=data, headers=Project.CUSTOM_HEADERS), 201, 404)
@requires_auth
def update(self, name=None):
"""Update this column.
:param str name: (optional), name of the column
:returns: bool
"""
data = {'name': name}
json = None
self._remove_none(data)
if data:
url = self._build_url(
'projects/columns', self.id, base_url=self._github_url)
json = self._json(self._patch(
url, data=dumps(data), headers=Project.CUSTOM_HEADERS), 200)
if json:
self._update_attributes(json)
return True
return False
class ProjectCard(models.GitHubCore):
"""The :class:`ProjectCard <ProjectCard>` object.
See http://developer.github.com/v3/projects/cards/
"""
def _update_attributes(self, project_card):
#: The URL of this card's parent column
self.column_url = project_card['column_url']
#: The URL of this card's associated content
self.content_url = project_card.get('content_url')
#: datetime object representing the last time the object was created
self.created_at = project_card['created_at']
#: The ID of this card
self.id = project_card['id']
#: The note attached to the card
self.note = project_card['note']
#: datetime object representing the last time the object was changed
self.updated_at = project_card['updated_at']
def _repr(self):
return '<ProjectCard [#{0}]>'.format(self.id)
@requires_auth
def delete(self):
"""Delete this card.
:returns: bool
"""
url = self._build_url(
'projects/columns/cards', self.id, base_url=self._github_url)
return self._boolean(self._delete(
url, headers=Project.CUSTOM_HEADERS), 204, 404)
@requires_auth
def move(self, position, column_id):
"""Move this card.
:param str position: (required), can be one of `top`, `bottom`, or
`after:<card-id>`, where `<card-id>` is the id value of a card
in the same column, or in the new column specified by `column_id`.
:param int column_id: (required), the id value of a column in the
same project.
:returns: bool
"""
if not position or not column_id:
return False
url = self._build_url(
'projects/columns/cards',
self.id,
'moves',
base_url=self._github_url
)
data = {'position': position, 'column_id': column_id}
return self._boolean(self._post(
url, data=data, headers=Project.CUSTOM_HEADERS), 201, 404)
@requires_auth
def update(self, note=None):
"""Update this card.
:param str note: (optional), the card's note content. Only valid for
cards without another type of content, so this cannot be specified
if the card already has a content_id and content_type.
:returns: bool
"""
data = {'note': note}
json = None
self._remove_none(data)
if data:
url = self._build_url(
'projects/columns/cards', self.id, base_url=self._github_url)
json = self._json(self._patch(
url, data=dumps(data), headers=Project.CUSTOM_HEADERS), 200)
if json:
self._update_attributes(json)
return True
return False
Loading
Loading
@@ -185,6 +185,12 @@ class PullRequest(models.GitHubCore):
#: Dictionary of _links. Changed in 1.0
self.links = self._get_attribute(pull, '_links', {})
 
#: If unmerged, holds the sha of the commit to test mergability.
#: If merged, holds commit sha of the merge commit, squashed commit on
#: the base branch or the commit that the base branch was updated to
#: after rebasing the PR.
self.merge_commit_sha = self._get_attribute(pull, 'merge_commit_sha')
#: Boolean representing whether the pull request has been merged
self.merged = self._get_attribute(pull, 'merged')
 
Loading
Loading
@@ -421,11 +427,8 @@ class PullRequest(models.GitHubCore):
endpoint
:returns: generator of :class:`PullReview <PullReview>`\ s
"""
# Accept the preview headers for reviews
headers = {'Accept': 'application/vnd.github.black-cat-preview+json'}
url = self._build_url('reviews', base_url=self._api)
return self._iter(int(number), url, PullReview, etag=etag,
headers=headers)
return self._iter(int(number), url, PullReview, etag=etag)
 
@requires_auth
def update(self, title=None, body=None, state=None):
Loading
Loading
@@ -472,7 +475,7 @@ class PullReview(models.GitHubCore):
self.state = self._get_attribute(preview, 'state')
 
#: datetime object representing when the event was created.
self.created_at = self._strptime_attribute(preview, 'created_at')
self.submitted_at = self._strptime_attribute(preview, 'submitted_at')
 
#: Body text of the review
self.body = self._get_attribute(preview, 'body')
Loading
Loading
Loading
Loading
@@ -26,6 +26,7 @@ from ..issues.milestone import Milestone
from ..licenses import License
from ..models import GitHubCore
from ..notifications import Subscription, Thread
from ..projects import Project
from ..pulls import PullRequest
from ..utils import stream_response_to_file, timestamp_parameter
from .branch import Branch
Loading
Loading
@@ -963,6 +964,24 @@ class Repository(GitHubCore):
json = self._json(self._post(url, data=data), 201)
return self._instance_or_null(Milestone, json)
 
@requires_auth
def create_project(self, name, body=None):
"""Create a project for this repository.
:param str name: (required), name of the project
:param str body: (optional), body of the project
:returns: :class:`Project <github3.projects.Project>` if
successful, otherwise None
"""
url = self._build_url('projects', base_url=self._api)
data = {'name': name, 'body': body}
self._remove_none(data)
json = None
if data:
json = self._json(self._post(
url, data=data, headers=Project.CUSTOM_HEADERS), 201)
return self._instance_or_null(Project, json)
@requires_auth
def create_pull(self, title, base, head, body=None):
"""Create a pull request of ``head`` onto ``base`` branch in this repo.
Loading
Loading
@@ -1754,6 +1773,35 @@ class Repository(GitHubCore):
url = self._build_url('pages', 'builds', base_url=self._api)
return self._iter(int(number), url, PagesBuild, etag=etag)
 
def project(self, id, etag=None):
"""Return the organization project with the given ID.
:param int id: (required), ID number of the project
:returns: :class:`Project <github3.projects.Project>` if successful,
otherwise None
"""
url = self._build_url('projects', id, base_url=self._github_url)
json = self._json(self._get(url, headers=Project.CUSTOM_HEADERS), 200)
return self._instance_or_null(Project, json)
def projects(self, number=-1, etag=None):
"""Iterate over projects for this organization.
:param int number: (optional), number of members to return. Default:
-1 will return all available.
:param str etag: (optional), ETag from a previous request to the same
endpoint
:returns: generator of :class:`Project <github3.projects.Project>`
"""
url = self._build_url('projects', base_url=self._api)
return self._iter(
int(number),
url,
Project,
etag=etag,
headers=Project.CUSTOM_HEADERS
)
def pull_request(self, number):
"""Get the pull request indicated by ``number``.
 
Loading
Loading
Loading
Loading
@@ -328,12 +328,13 @@ class _User(models.GitHubCore):
Default: -1 returns all available organization
:param str etag: (optional), ETag from a previous request to the same
endpoint
:returns: generator of :class:`Event <github3.orgs.Organization>`\ s
:returns: generator of
:class:`ShortOrganization <github3.orgs.ShortOrganization>`\ s
"""
# Import here, because a toplevel import causes an import loop
from .orgs import Organization
from .orgs import ShortOrganization
url = self._build_url('orgs', base_url=self._api)
return self._iter(int(number), url, Organization, etag=etag)
return self._iter(int(number), url, ShortOrganization, etag=etag)
 
def starred_repositories(self, sort=None, direction=None, number=-1,
etag=None):
Loading
Loading
Loading
Loading
@@ -23,7 +23,7 @@ SNI_requirements = [
'pyasn1'
]
 
kwargs['tests_require'] = ['betamax >=0.2.0', 'pytest',
kwargs['tests_require'] = ['betamax >=0.2.0', 'pytest <3.3.0',
'betamax-matchers>=0.1.0']
if sys.version_info < (3, 0):
kwargs['tests_require'].append('unittest2 ==0.5.1')
Loading
Loading
{"http_interactions": [{"request": {"uri": "https://api.github.com/organizations?per_page=25", "method": "GET", "headers": {"Accept": "application/vnd.github.v3.full+json", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "User-Agent": "github3.py/1.0.0a2"}, "body": {"string": "", "encoding": "utf-8"}}, "recorded_at": "2015-07-27T16:50:16", "response": {"url": "https://api.github.com/organizations?per_page=25", "headers": {"x-github-media-type": "github.v3; param=full; format=json", "content-type": "application/json; charset=utf-8", "x-github-request-id": "3EBD09C7:4121:BE664F4:55B66147", "x-served-by": "065b43cd9674091fec48a221b420fbb3", "x-ratelimit-remaining": "58", "transfer-encoding": "chunked", "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-frame-options": "deny", "content-security-policy": "default-src 'none'", "status": "200 OK", "x-xss-protection": "1; mode=block", "date": "Mon, 27 Jul 2015 16:50:16 GMT", "x-ratelimit-limit": "60", "etag": "W/\"467f85325c09d7c93ffa03581d0b7de5\"", "cache-control": "public, max-age=60, s-maxage=60", "content-encoding": "gzip", "access-control-allow-origin": "*", "link": "<https://api.github.com/organizations?per_page=25&since=2595>; rel=\"next\", <https://api.github.com/organizations{?since}>; rel=\"first\"", "x-ratelimit-reset": "1438017277", "access-control-allow-credentials": "true", "vary": "Accept", "x-content-type-options": "nosniff", "server": "GitHub.com", "strict-transport-security": "max-age=31536000; includeSubdomains; preload"}, "status": {"message": "OK", "code": 200}, "body": {"base64_string": "H4sIAAAAAAAAA63ay27jNhSA4VcR1G0QX+JbAhRdzKqLAsV00UVRDGiZlomhRIGi7BqDefceySJFyRrMIXF2gyD/yYQfaElU/vmWSpWLMv1IudZnzXn6kopT+rHZvKSNlvD1izFV/bFYsEq85sJcmuNrpoqF0nm9GBrNK1V/QReL7vvhZ/ErL01I+AigLHhx5Dok7Ytvi8c/vsOQqjlKkX0JnzUO/ZHsygzT06Xovlj3C9jUXGeqNPCrd2vZLDab366/vsF/6MTrTIvKCAUmZSPl9xePqAQqfmf61CsdViglP0NDuSjCamhjuIaaRGwYR4x2WM2hpalPVohS1EbfM7Dmmlu41eodIzdTY/2mabji04QIy6cZFKJPQ4ldAWcOdrobMyUlz4y4cnHirN+Rq/UBA/vUYlnHYTjqpI8gnUygAJ2MpOZcH+Y40795cmyEPCW1Opsb0zwxCv4trzzRnMmk0uooeVG/jja0yjNLjbtGPgKsL3x3OGobRUi2GQVfO4faDHdBrNvf+ia0vWtZbZeY3ednWBjXhPMMaQTSEFNQDdOowbbLuU02/cyEq6C+39jdbqHdHuPlVVgum4RruTICy7UUVm4YNdVuj6EquD72TOsd6mmgL7BE7beH83RVBE3XUbB0g4hJYIFRJAru/uvqfuK6l3nb4u4jRyEaaKginLw4hsvLSdS8ecR4YIDBq+F+ojHCWLk9ak95FZbNJuFmrowAcy2FlhtGTbVH7bOb5mV2kezYnlB0pyEH1DYbdViuIQoH89oIMq+mQPPGEbPB8mN2mKiu8CSmCqa/ciPKs+r1ttst5i5jLsciPrXhls8jIkifh1DIPk8lBgahOeDxUYqG9ZCsOxl77Mo97ll71GFBhyhc0msjCL2aws4bR4wGyz+HNr3l10zIWqqre0Zb4m76/Q6tZn9WBJpLY8xcTELmphGLrWDp0WQnldunNORpZSf2yILAIIn0astYrrYl02qHUWP94Bgy/QSnU0bpOlHn5K8KXtkkrDwl5sKTX1b9Fz6pAh5TMp78DqfOue4+NJM/mTYlPDn4x9MlN3mjGwe92WGulEOFde6LcGYbRijblALZziI33uzmNmT6uTneEzD73G6pzrdQRyF5cmovgqoq4HAguSh4kTTivPHjRdWgPYCiDlj8DkvqmnDUIY1gHWIK2GEaPS3qs7ZmTV0JLq3YdoV6p+dlWDCbhHu5MoLLtRRabhg1Fqz63D6c3svcLvAOL5Oqce/xDhvck6EfYsGGnxZO5rURaF5NweaNo4aD9Z+DGz85GA0v6bo/N2gf5lfvuOeGocKC9UW4lg0jqGxK4WRnUSPBgs8hTXeXFCW8CSylUpWjwp08j0ssl1eFk/lxBJufU9D588j55k+n0z/YV/gDnPY29CLyS1JxfVa6YCXcd8JlNWFVBX9b0917Tt6hlspkl0NvvF4eUCehLsLyPoJw2b6LQO1LCs9+FDFlu9ZzO3H8cclPOc8Y3Fo+Pi/Xb0vUNc7LsEQ2CUdyZQSTaymg3DBqKlj1n1PlTLL/7rDJ7MVtvd2g/gBlFGK5higczGsjyLyaAs0bR80G6/9zttrAIx28DbI7bPuOOqH2MiyZTcLBXBnB5VoKLDeMnOp99tS5uy3593+CzYb+GisAAA==", "string": "", "encoding": "utf-8"}}}], "recorded_with": "betamax/0.4.2"}
\ No newline at end of file
{"http_interactions": [{"request": {"body": {"encoding": "utf-8", "string": ""}, "headers": {"User-Agent": "github3.py/1.0.0a4", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "Connection": "keep-alive", "Accept-Charset": "utf-8", "Content-Type": "application/json"}, "method": "GET", "uri": "https://api.github.com/organizations?per_page=25"}, "response": {"body": {"encoding": "utf-8", "base64_string": "H4sIAAAAAAAAA7XaQW+kNhTA8a9izaWXKBOSmWQSqVpVPVVqpWp7yKGqVh5wGCuAkYGZjlb73fvMgDEDJO9Z7q2K8n/bLr8aY/j7+ypTqSxWLyuh9ZsWYnWzksnqZbO5WTU6g58f6rqsXtZrXsrbVNaHZn8bq3ytdFqth0aLUlXf0MW6/X34s8RRFDUlvARQHpR6p4Tt75v/uqpqBCW8BFDmIt8LTUm74vv68g8/YEjZ7DMZf6PPGofuSH7kNdfXf/ntD6v77po1ldCxKmr4224vX7PebL4cf97Av1EiqljLspYKGBRNlv24cVQUoEOcuU46GLsIBcPN0DZs5MFjaOlChpaOZGh9nAx1ECrDOD8t0e3l//Cpll00p2W1cq3kspBVrc8xIBNa9GKi6BlDZqbGwrlO6XwmE8iIJhPIlCYTPEBNZoRgNRnqh+tuERcI+VxXrLJMxLU8CpkI3q1G0f0OY2vSYmWNQ7qrq56s6qonm7rqPURdTQjh6Wqkn6blGxuYmNX0Kti+kVnCKvVWn7gWrFbwz9lRMC14xkqt9pnIq9vRoqbSuLeG2xNdAiww+G26KhORKZmI7MdEHmhMFkKKmROcB27jU5m/4JPU/YY42t5hVho3wxqwDV3CkJI9DClZxZB62BjiEEKGaX5OHpZvStu7uWVkukGGHc+Jn/tF4vEJwwR2SH2FVdIndCS2JBuxJZmILT2E2DYEEDvMz8fyjjh6fJrzcbUlFnrfybh/RD1S55cCq8L8Ol1EW5E1tBVZQlt5KGi7EALaQX5Xf3nLCldz7upfrw65gofnqjwnQncMHra4p6FRiNYwVB4onJhuw4npRJzYR4qTBwHjzPNzs3xXgcuPcVPBZrSpZd2jeUKtHU6FFdMndC62JFuxJRmKLT2U2DYEETvMz8fyXeXhCbWunLQo4kPG9+2Jpjmv3aGWlVGHNTJEdCVOS3bitGQpTuthxalDaHHG+XlZXk/gumPWE1ke4dRE5Vy/i1oWb6pjs91uMdvVuRyrZ9LSEU1HkC1NR5BJTUd4yJoOCQFsOtXP2fJ+B6DMORvvdjVcloy3LxIuq9IT7nhu1GFdDREdlNOSJTktmZDTethx6hBonHGhtcB1R2jhMqsydbQnLHe4Z2ftdGgsfeNhxaZ0KjalS7GpDxQbB3Fip/kx+eCkFq74rJNX8RMcz/KC8VRmcE4reH45u5VFygpxMme1SRPXFXtTmtUHwU5if8t+KRKmDmyvzjfwAzPiXZofvbFUqYTxmsn6lr3yojZHvyel39kJ3mizpvoyOvNthSUq7c90kG+wnIzkEv4kT5am9FNpSj+UpvQ1adpgJM0wP5HL26lo6VXU74InBt9fJXwjwX5VOZwqxIL9Bm86U93e8tifXNcFPOe7r0QLUaeNbiykzSNmuzVUWEddQWfUh2RFfUhG1Icehvo0BKF+lp+g5Qe4KNo8zq5pX5v9mQGTr2ZxgbUtYbnam9UtMbsmVeZwUskOCl69jwTBwnZQFQAbDKFOmN0Oq8g2dEdDSpY0pGRLQ+qhaYhDeBqm/Q+iZu+S12eNvJC5fJfSQnlGvbFyMqyTPqEzsSVZiS3JSGzpYcS2IYjYYX5CPrprPc++qxo/nVW8qUopst7HNkJ9yuVkWB99QvdhS7IPW5J92NLDh21D+LDD/Hx8cE+CSz17TxrfaQ7w0VacqcZ+uLXb4A4V3RBr5GQjuhKnJTtxWrIUp/Ww4tQhtDjj/Lx8sJ7Ahf/cS63hW6z2I15zAB094856hgorpSvoTPqQbKQPyUD60ENHn4ag0c/yc/HB8zpc4zkX1zuRTBbwjVeRKVVaHbi33+MSK8Sp6ErcmCzFjcla3NhDjJuHUOPO85PzwR3oef59+eoP/g6f1JsjmoNMD6wUGk50cl7AszXsqBkvS/havn2+vvour1B1fNh1vO7vdqgXpDbCyroEdFRdR/bUdWRKXeehqCtDAOpGhbZjLu7cqjPe3YokFTGHh+fL7ej+4Q61d3EyrIk+oauwJdmFLckybOlhw7YhdNhhfj6WX02ZS/25j5Rn/N8zLCX9huV+u0F9Oz4KsUaGiK7EaclOnJYsxWk9rDh1CC3OuOBe4MIvePnnP/1FC/8QNwAA", "string": ""}, "headers": {"Date": "Fri, 15 Dec 2017 01:49:28 GMT", "Content-Type": "application/json; charset=utf-8", "Transfer-Encoding": "chunked", "Server": "GitHub.com", "Status": "200 OK", "X-RateLimit-Limit": "60", "X-RateLimit-Remaining": "59", "X-RateLimit-Reset": "1513306168", "Cache-Control": "public, max-age=60, s-maxage=60", "Vary": "Accept", "ETag": "W/\"b9532ff23420e55133e9ad4e8189cb00\"", "X-GitHub-Media-Type": "github.v3; param=full; format=json", "Link": "<https://api.github.com/organizations?per_page=25&since=2548>; rel=\"next\", <https://api.github.com/organizations{?since}>; rel=\"first\"", "Access-Control-Expose-Headers": "ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "Access-Control-Allow-Origin": "*", "Content-Security-Policy": "default-src 'none'", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "X-Content-Type-Options": "nosniff", "X-Frame-Options": "deny", "X-XSS-Protection": "1; mode=block", "X-Runtime-rack": "0.041933", "Content-Encoding": "gzip", "X-GitHub-Request-Id": "DC8F:266D9:865317:A2C53A:5A332A28"}, "status": {"code": 200, "message": "OK"}, "url": "https://api.github.com/organizations?per_page=25"}, "recorded_at": "2017-12-15T01:49:28"}], "recorded_with": "betamax/0.8.0"}
\ No newline at end of file
{"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/orgs/github3py"}, "response": {"body": {"base64_string": "H4sIAAAAAAAAA51Sy27DIBD8F6T0lNg8YjtGiqpeeu0lp14ibLCDZAPCOG0a5d+7NVHr5JZKHNjHLMvMnFFnW20QR60Oh7Fi7oSWSEvESbGhJMuXaPQdlA8huIGnqXA6ia1JbfvU+nZI51CvnB32D2DSCQGPqqMy4TFohAC2V32l/GPgK+acxssFxrix6nS9/8+0W+h8qDiKIPwdJTRpfSxMNMZryspcMakyxigWVVNuskyWhNaSyXLNSPMst5MOC/ayoK9wtATOdG3NMBMF8k0mCkWowHRD8obVJa6wFMV6XVJZVAVLnGmf/PYT/mxEr/7kTyb9YSUnzGmW1hbSFXgFcTN23RJsU4ugLTgnxqoXGnwSgysZUVme/RLb6iEMiOMlamzX2Q+QbBZpA9Ohdgh9d0fXzHFzs9VeiaDkXgRYlWJCVzhb0WKH15xmnOXvsPTo5E0PWxGywvkOM85KjqeecHI/HLz5Vhj9Ff91+QbZAsCwGwMAAA==", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "59", "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", "transfer-encoding": "chunked", "x-github-request-id": "48A0D4DF:77B3:324C724:527B0A26", "content-encoding": "gzip", "vary": "Accept, Accept-Encoding", "server": "GitHub.com", "cache-control": "public, max-age=60, s-maxage=60", "last-modified": "Wed, 06 Nov 2013 03:39:06 GMT", "x-ratelimit-limit": "60", "etag": "\"2f2ab6ad2640adc70fd0d93389d95d34\"", "access-control-allow-credentials": "true", "date": "Thu, 07 Nov 2013 03:33:58 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1383798838"}, "url": "https://api.github.com/orgs/github3py", "status_code": 200}, "recorded_at": "2013-11-07T03:33:56"}], "recorded_with": "betamax"}
\ No newline at end of file
{"http_interactions": [{"request": {"body": {"encoding": "utf-8", "string": ""}, "headers": {"User-Agent": "github3.py/1.0.0a4", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.v3.full+json", "Connection": "keep-alive", "Accept-Charset": "utf-8", "Content-Type": "application/json"}, "method": "GET", "uri": "https://api.github.com/orgs/github3py"}, "response": {"body": {"encoding": "utf-8", "base64_string": "H4sIAAAAAAAAA52Sy26DMBBFf6XyGsIjkESWqq67qLqJVKkbZMAFt+Cx/EhFo/x7B4Nakq7ozszcM8zjnkkHjZCEkkbY1pVbNZCAiJrQZH9Ik3wXEKc7TLfWKkOjiCmxmaSbCvoIdGOiJaq5AlOsYCJP4E/5iUu7Dp0QZFuAj3WoJ8ZRjXF8HTohyPa8L7leB8/MOZoeFyyjXNmJqvhPtWt0WZSdmGX69hA+aOL5gs5wXYG0uHd/TBfNR3843WfYWM1NpYWyAkaDYECynv9aZeO9gqBicliEBWC4RF9NUAcVm0s8sVoYkMHdyyNKeM/EaC18tswUaCUmxZfXFkrDO6+sIdRqxyeBN4qwoIc/6XkPk5Xo4WenjTBjjTggb9B18InXWnwJiS1irrV9d7OphcWX7q40Z5bXBbPYdxonaRjnYbo/xhlNc7rdveIsTtVXmjxEWZIdk4xmB7qNR40d1LjI58XI5PINiI3/14wDAAA=", "string": ""}, "headers": {"Date": "Fri, 15 Dec 2017 01:54:43 GMT", "Content-Type": "application/json; charset=utf-8", "Transfer-Encoding": "chunked", "Server": "GitHub.com", "Status": "200 OK", "X-RateLimit-Limit": "60", "X-RateLimit-Remaining": "58", "X-RateLimit-Reset": "1513306168", "Cache-Control": "public, max-age=60, s-maxage=60", "Vary": "Accept", "ETag": "W/\"40a5e37ece9deda11312ca78b2c2ac5a\"", "Last-Modified": "Mon, 14 Dec 2015 14:48:30 GMT", "X-GitHub-Media-Type": "github.v3; param=full; format=json", "Access-Control-Expose-Headers": "ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "Access-Control-Allow-Origin": "*", "Content-Security-Policy": "default-src 'none'", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "X-Content-Type-Options": "nosniff", "X-Frame-Options": "deny", "X-XSS-Protection": "1; mode=block", "X-Runtime-rack": "0.024670", "Content-Encoding": "gzip", "X-GitHub-Request-Id": "DD5D:266E1:309BAC8:3A1BEB2:5A332B63"}, "status": {"code": 200, "message": "OK"}, "url": "https://api.github.com/orgs/github3py"}, "recorded_at": "2017-12-15T01:54:43"}], "recorded_with": "betamax/0.8.0"}
\ No newline at end of file
{"http_interactions": [{"response": {"headers": {"X-GitHub-Media-Type": "github.inertia-preview; format=json", "X-GitHub-Request-Id": "E462:26DD:F42A5A:12F9A02:58FA1673", "X-Content-Type-Options": "nosniff", "Content-Type": "application/json; charset=utf-8", "X-RateLimit-Remaining": "4992", "Cache-Control": "private, max-age=60, s-maxage=60", "Content-Security-Policy": "default-src 'none'", "Server": "GitHub.com", "Content-Encoding": "gzip", "Access-Control-Allow-Origin": "*", "X-Served-By": "15bc4ab707db6d6b474783868c7cc828", "X-RateLimit-Reset": "1492787938", "X-OAuth-Scopes": "repo, user:email", "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", "X-Accepted-OAuth-Scopes": "public_repo, repo", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "Date": "Fri, 21 Apr 2017 14:25:56 GMT", "X-XSS-Protection": "1; mode=block", "X-Frame-Options": "deny", "X-RateLimit-Limit": "5000", "Transfer-Encoding": "chunked", "ETag": "W/\"261c15fcb665321c15adfb9cb1484d9b\"", "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", "Status": "200 OK"}, "status": {"code": 200, "message": "OK"}, "body": {"string": "", "encoding": "utf-8", "base64_string": "H4sIAPG3AVkC/52TUW/CIBCA/8rCcxVpzXRNlv2J7WUvBlusLC0QuNZ0Tf/7DuycumwGn9rAfd8dBzcQfVDCblpbk5zsAYzLKeVGzisJ+3Y7L3RDrTDaUSerhnfSti5d0uNuNjc9Sci/sLH6QxTgaPa0ztgaw/fQ1FcJz+L/SPPjYagodN02ym1iMtMJQlyWJD8uJkTxRqADhIPZRGDEVpf9tPoQ/jGwbbbCkpwlxAEHD2kjlK/GCg4atwZS60oq3Dk/xZSQsXSVsadVQnjHgf/qeVh02XSC1glbaAVCQThMS7/5l+45Q2VlJ413k1u34HWXVxh1ERi803WtD2jZRCaiJ/Jkkaq604LkQDXs/ZPFmNE3QjqILypQQ/hgB70HL9VaUUabJg7L8pM0DmFcgrDdusJKA1Kr+AIvaLRpW3ElP/l9NqS9JExyNBwopEWHrzEeP2IDzqPseNGPoY5CyA6bfafyikcj9MZP5BvG+tZLEBteNn4Wd7x2YpymFBEOGJcu2Gq2SGfp4pU95stVzrJ3P0OmvBEzfgGQvxGbMgUAAA=="}, "url": "https://api.github.com/projects/398318"}, "request": {"headers": {"User-Agent": "github3.py/1.0.0a4", "Authorization": "token <AUTH_TOKEN>", "Content-Type": "application/json", "Accept-Charset": "utf-8", "Connection": "keep-alive", "Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.inertia-preview+json"}, "uri": "https://api.github.com/projects/398318", "method": "GET", "body": {"string": "", "encoding": "utf-8"}}, "recorded_at": "2017-04-21T14:26:02"}], "recorded_with": "betamax/0.8.0"}
\ No newline at end of file