├── .gitignore ├── .travis.yml ├── AUTHORS.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── docs ├── Makefile ├── conf.py ├── events.rst ├── gists.rst ├── git_data.rst ├── github.rst ├── index.rst ├── installation.rst ├── issues.rst ├── orgs.rst ├── pull_requests.rst ├── repos.rst ├── resources.rst ├── result.rst ├── services.rst └── users.rst ├── pygithub3 ├── __init__.py ├── core │ ├── __init__.py │ ├── client.py │ ├── compat.py │ ├── errors.py │ ├── json │ │ └── __init__.py │ ├── result │ │ ├── __init__.py │ │ ├── base.py │ │ ├── link.py │ │ ├── normal.py │ │ └── smart.py │ └── third_libs │ │ ├── __init__.py │ │ └── link_header.py ├── exceptions.py ├── github.py ├── requests │ ├── __init__.py │ ├── base.py │ ├── events │ │ ├── __init__.py │ │ ├── networks.py │ │ ├── orgs.py │ │ ├── repos.py │ │ └── users.py │ ├── gists │ │ ├── __init__.py │ │ └── comments.py │ ├── git_data │ │ ├── __init__.py │ │ ├── blobs.py │ │ ├── commits.py │ │ ├── references.py │ │ ├── tags.py │ │ └── trees.py │ ├── issues │ │ ├── __init__.py │ │ ├── comments.py │ │ ├── events.py │ │ ├── labels.py │ │ └── milestones.py │ ├── orgs │ │ ├── __init__.py │ │ ├── members.py │ │ └── teams.py │ ├── pull_requests │ │ ├── __init__.py │ │ └── comments.py │ ├── repos │ │ ├── __init__.py │ │ ├── collaborators.py │ │ ├── commits.py │ │ ├── downloads.py │ │ ├── forks.py │ │ ├── hooks.py │ │ ├── keys.py │ │ └── watchers.py │ └── users │ │ ├── __init__.py │ │ ├── emails.py │ │ ├── followers.py │ │ └── keys.py ├── resources │ ├── __init__.py │ ├── base.py │ ├── events.py │ ├── gists.py │ ├── git_data.py │ ├── issues.py │ ├── orgs.py │ ├── pull_requests.py │ ├── repos.py │ └── users.py ├── services │ ├── __init__.py │ ├── base.py │ ├── events │ │ ├── __init__.py │ │ ├── networks.py │ │ ├── orgs.py │ │ ├── repos.py │ │ └── users.py │ ├── gists │ │ ├── __init__.py │ │ └── comments.py │ ├── git_data │ │ ├── __init__.py │ │ ├── blobs.py │ │ ├── commits.py │ │ ├── references.py │ │ ├── tags.py │ │ └── trees.py │ ├── issues │ │ ├── __init__.py │ │ ├── comments.py │ │ ├── events.py │ │ ├── labels.py │ │ └── milestones.py │ ├── orgs │ │ ├── __init__.py │ │ ├── members.py │ │ └── teams.py │ ├── pull_requests │ │ ├── __init__.py │ │ └── comments.py │ ├── repos │ │ ├── __init__.py │ │ ├── collaborators.py │ │ ├── commits.py │ │ ├── downloads.py │ │ ├── forks.py │ │ ├── hooks.py │ │ ├── keys.py │ │ └── watchers.py │ └── users │ │ ├── __init__.py │ │ ├── emails.py │ │ ├── followers.py │ │ └── keys.py └── tests │ ├── __init__.py │ ├── core │ ├── __init__.py │ ├── test_client.py │ ├── test_json.py │ └── test_result.py │ ├── requests │ ├── __init__.py │ └── test_core.py │ ├── resources │ ├── __init__.py │ ├── test_core.py │ └── test_issues.py │ ├── services │ ├── __init__.py │ ├── test_core.py │ ├── test_events.py │ ├── test_gists.py │ ├── test_git_data.py │ ├── test_issues.py │ ├── test_orgs.py │ ├── test_pull_requests.py │ ├── test_repos.py │ └── test_users.py │ └── utils │ ├── __init__.py │ ├── base.py │ ├── core.py │ ├── requests.py │ ├── resources.py │ └── services.py ├── requirements ├── base.txt └── dev.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | *.swp 3 | *.DS_STORE 4 | *.rope* 5 | MANIFEST 6 | docs/_build 7 | dist/ 8 | build/ 9 | *egg-info 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.6" 4 | - "2.7" 5 | install: 6 | - pip install -r requirements/dev.txt --use-mirrors 7 | script: nosetests 8 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | python-github3 is written and maintained by **David Medina** and 2 | 3 | various contributors: 4 | 5 | Development Lead 6 | ================= 7 | 8 | - David Medina 9 | 10 | Forked and redesign from Kenneth Reitz's repo 11 | ---------------------------------------------- 12 | 13 | Forked from https://github.com/kennethreitz/python-github3 14 | 15 | Kenneth Reitz is also the author of the awesome 16 | `requests `_ library, which 17 | `python-github3` requires. 18 | 19 | Patches and Suggestions 20 | ......................... 21 | 22 | - Mahdi Yusuf 23 | - Rok Garbas 24 | - Antti Kaihola 25 | - Francisco Marcos 26 | - Nathaniel Williams 27 | - Alejandro Gómez 28 | - Stefano Rivera 29 | - Ouertani Mohammed Amine 30 | - Conor Branagan 31 | - Ralph Bean 32 | - Jason A. Donenfeld 33 | - Brad Montgomery 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 David Medina 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include README.rst 3 | include LICENSE 4 | include requirements/base.txt 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | init: 2 | pip install -r requirements/dev.txt 3 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. image:: https://secure.travis-ci.org/copitux/python-github3.png 2 | 3 | Pygithub3 4 | ========== 5 | 6 | Pygithub3 is a wrapper to the **Github API v3**, 7 | written in Python. 8 | 9 | It has been developed with extensibility in mind, because the ``API`` is in a 10 | beta state, trying to achieve a very loosly coupled software. 11 | 12 | It should be very easy to extend to support new ``requests`` and ``resources``, 13 | because each of them are managed by itself. 14 | 15 | `Pygithub3 docs `_ 16 | 17 | `Github API v3 docs `_ 18 | 19 | Fast install 20 | ------------- 21 | :: 22 | 23 | pip install pygithub3 24 | 25 | Fast example 26 | ------------- 27 | :: 28 | 29 | from pygithub3 import Github 30 | 31 | gh = Github(login='copitux', password='password') 32 | 33 | copitux = gh.users.get() 34 | kennethreitz = gh.users.get('kennethreitz') 35 | 36 | copitux_repos = gh.repos.list().all() 37 | kennethreitz_repos = gh.repos.list('kennethreitz').all() 38 | 39 | Achievements 40 | ------------- 41 | 42 | - The core 43 | - `Users service `_ 44 | - `Repos service `_ 45 | - `Gists service `_ 46 | - `Git Data service `_ 47 | - `Pull requests service `_ 48 | - `Orgs service `_ 49 | - `Issues service `_ 50 | - `Events service `_ 51 | 52 | TODO 53 | ----- 54 | 55 | - Oauth authorization API (service?) 56 | - Proxy methods into resources (e.g copitux.followers) 57 | 58 | Contribute 59 | ----------- 60 | 61 | 1. Fork the `repository `_ 62 | 2. Write a test to cover new feature or to reproduce bug 63 | 3. Code with `pep8 `_ rules 64 | 4. Add yourself to ``AUTHORS`` 65 | 5. Pull request it to ``develop`` branch 66 | 67 | Tests 68 | ----- 69 | 70 | Run ``make init`` to install test requirements and ``nosetests`` to run tests. 71 | -------------------------------------------------------------------------------- /docs/events.rst: -------------------------------------------------------------------------------- 1 | .. _Events service: 2 | 3 | Events service 4 | ============== 5 | 6 | This service exposes the `Events API`_. Much of this API is read-only, and while 7 | pagination is supported, there is a fixed page size of 30 with a limit of 10 8 | page requests. 9 | 10 | Many events have an `actor` which denotes the user that performed an event. 11 | Additionally, there may be `org` or `repo` attributes for events related to 12 | Organizations and Repos. Finally, each event object contains a `payload` 13 | attribute containing more detailed information about the event. 14 | 15 | .. _public events: 16 | 17 | Public Events 18 | ------------- 19 | Yields the most recent public events from Github. 20 | 21 | :: 22 | 23 | from pygithub3 import Github 24 | 25 | gh = Github() 26 | 27 | events = gh.events.list().all() 28 | print events[0].payload 29 | 30 | Event 31 | ....... 32 | 33 | .. autoclass:: pygithub3.services.events.Event 34 | :members: 35 | 36 | .. attribute:: issues 37 | 38 | :ref:`Issues events ` 39 | 40 | .. attribute:: networks 41 | 42 | :ref:`Events network service` 43 | 44 | .. attribute:: orgs 45 | 46 | :ref:`Events org service` 47 | 48 | .. attribute:: repos 49 | 50 | :ref:`Events repo service` 51 | 52 | .. attribute:: users 53 | 54 | :ref:`Events user service` 55 | 56 | .. _repository events: 57 | 58 | Repo Events 59 | ----------- 60 | 61 | These are events for a specific repo, including issue and network events. The 62 | Issues events are proxied to the :ref:`Issues service`. 63 | 64 | :: 65 | 66 | events = gh.events.repos.list(user="copitux", repo="python-github3") 67 | for e in events.next(): 68 | print("{t}".format(t=e.type)) 69 | 70 | # Get the issue Events 71 | events = gh.events.issues.list_by_repo(user="copitux", 72 | repo="python-github3") 73 | 74 | # Get the Public Events for a Repo's Network 75 | events = gh.events.networks.list(user="copitux", repo="python-github3") 76 | 77 | .. _Events network service: 78 | 79 | Network 80 | ....... 81 | 82 | .. autoclass:: pygithub3.services.events.networks.Network 83 | :members: 84 | 85 | 86 | .. _Events repo service: 87 | 88 | Repo 89 | ........ 90 | 91 | .. autoclass:: pygithub3.services.events.repos.Repo 92 | :members: 93 | 94 | 95 | .. _organziation events: 96 | 97 | Organization Events 98 | ------------------- 99 | 100 | These are the public events for an Organization 101 | 102 | :: 103 | 104 | events = gh.events.orgs.list(org="Acme") 105 | 106 | You may also get a user's feed of events for an Organization, but you *must* be 107 | authenticated as the provided user, and you must be a member of the given 108 | organization. 109 | 110 | :: 111 | 112 | events = gh.events.users.orgs(user="copitux", org="acme") 113 | 114 | .. _Events org service: 115 | 116 | Org 117 | ........ 118 | 119 | .. autoclass:: pygithub3.services.events.orgs.Org 120 | :members: 121 | 122 | .. _user events: 123 | 124 | User Events 125 | ----------- 126 | 127 | You can retrieve the public events performed by a user and the public events 128 | that a user receives. If you're authenticated, you may also receive private 129 | events. 130 | 131 | :: 132 | 133 | received_events = gh.events.users.list_received_public(user="copitux") 134 | performed_events = gh.events.users.list_performed_public(user="copitux") 135 | 136 | If authenticated as `copitux`, you could get private events with the 137 | following, otherwise you'll just get the public events as above: 138 | 139 | :: 140 | 141 | received_events = gh.events.users.list_received(user="copitux") 142 | performed_events = gh.events.users.list_performed(user="copitux") 143 | 144 | .. _Events user service: 145 | 146 | User 147 | ........ 148 | 149 | .. autoclass:: pygithub3.services.events.users.User 150 | :members: 151 | -------------------------------------------------------------------------------- /docs/gists.rst: -------------------------------------------------------------------------------- 1 | .. _Gists service: 2 | 3 | Gists services 4 | =============== 5 | 6 | **Fast sample**:: 7 | 8 | from pygithub3 import Github 9 | 10 | auth = dict(login='octocat', password='pass') 11 | gh = Github(**auth) 12 | 13 | octocat_gists = gh.gists.list() 14 | the_first_gist = gh.gists.get(1) 15 | 16 | the_first_gist_comments = gh.gists.comments.list(1) 17 | 18 | Gist 19 | ----- 20 | 21 | .. autoclass:: pygithub3.services.gists.Gist 22 | :members: 23 | 24 | .. attribute:: comments 25 | 26 | :ref:`Comments service` 27 | 28 | .. _Comments service: 29 | 30 | Comments 31 | ---------- 32 | 33 | .. autoclass:: pygithub3.services.gists.Comments 34 | :members: 35 | 36 | .. _github gists doc: http://developer.github.com/v3/gists 37 | .. _github comments doc: http://developer.github.com/v3/gists/comments 38 | -------------------------------------------------------------------------------- /docs/git_data.rst: -------------------------------------------------------------------------------- 1 | .. _Git Data service: 2 | 3 | Git Data services 4 | ================= 5 | 6 | **Example**:: 7 | 8 | from pygithub3 import Github 9 | 10 | gh = Github(user='someone', repo='some_repo') 11 | 12 | a_blob = gh.git_data.blobs.get('a long sha') 13 | 14 | dev_branch = gh.git_data.references.get('heads/add_a_thing') 15 | 16 | 17 | GitData 18 | ------- 19 | 20 | .. autoclass:: pygithub3.services.git_data.GitData 21 | :members: 22 | 23 | .. attribute:: blobs 24 | 25 | :ref:`Blobs service` 26 | 27 | .. attribute:: commits 28 | 29 | :ref:`Gitdata commits service` 30 | 31 | .. attribute:: references 32 | 33 | :ref:`References service` 34 | 35 | .. attribute:: tags 36 | 37 | :ref:`Tags service` 38 | 39 | .. attribute:: trees 40 | 41 | :ref:`Trees service` 42 | 43 | 44 | .. _Blobs service: 45 | 46 | Blobs 47 | ----- 48 | 49 | .. autoclass:: pygithub3.services.git_data.Blobs 50 | :members: 51 | 52 | 53 | .. _Gitdata commits service: 54 | 55 | Commits 56 | ------- 57 | 58 | .. autoclass:: pygithub3.services.git_data.Commits 59 | :members: 60 | 61 | 62 | .. _References service: 63 | 64 | References 65 | ---------- 66 | 67 | .. autoclass:: pygithub3.services.git_data.References 68 | :members: 69 | 70 | 71 | .. _Tags service: 72 | 73 | Tags 74 | ---- 75 | 76 | .. autoclass:: pygithub3.services.git_data.Tags 77 | :members: 78 | 79 | 80 | .. _Trees service: 81 | 82 | Trees 83 | ----- 84 | 85 | .. autoclass:: pygithub3.services.git_data.Trees 86 | :members: 87 | 88 | .. _github commits doc: http://developer.github.com/v3/git/commits 89 | .. _github refs doc: http://developer.github.com/v3/git/refs 90 | .. _github tags doc: http://developer.github.com/v3/git/tags 91 | .. _github trees doc: http://developer.github.com/v3/git/trees 92 | -------------------------------------------------------------------------------- /docs/github.rst: -------------------------------------------------------------------------------- 1 | Github 2 | ======== 3 | 4 | This is the main entrance of **pygithub3** 5 | 6 | .. autoclass:: pygithub3.Github 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Documentation Overview 2 | ======================= 3 | 4 | **pygithub3** is a Github APIv3 python wrapper. 5 | 6 | You can consume the API with several :doc:`services` (users, repos...) like 7 | you see in `Github API v3 documentation`_. 8 | 9 | When you do an API request, **pygithub3** map the result into :doc:`resources` 10 | which can do its own related requests in future releases. 11 | 12 | Fast sample 13 | ----------- 14 | :: 15 | 16 | from pygithub3 import Github 17 | 18 | gh = Github(login='octocat', password='password') 19 | 20 | octocat = gh.users.get() # Auth required 21 | copitux = gh.users.get('copitux') 22 | # copitux = 23 | 24 | octocat_followers = gh.users.followers.list().all() 25 | copitux_followers = gh.users.followers.list('copitux').all() 26 | # copitux_followers = [, , ...] 27 | 28 | 29 | Others 30 | ------- 31 | 32 | You must apologize my English level. I'm trying to do my best 33 | 34 | 35 | .. toctree:: 36 | :maxdepth: 3 37 | 38 | installation 39 | github 40 | services 41 | result 42 | resources 43 | 44 | .. _Github API v3 documentation: http://developer.github.com 45 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============= 3 | :: 4 | 5 | pip install pygithub3 6 | 7 | or 8 | 9 | easy_install pygithub3 10 | 11 | 12 | Dependencies 13 | --------------- 14 | 15 | Required 16 | ......... 17 | 18 | This library depends only on the `requests`_ module. 19 | 20 | If you install ``pygithub3`` with ``pip`` all is done. This is the best option. 21 | 22 | Optional 23 | ......... 24 | 25 | The test suite uses `nose`_, `mock`_, and `unittest2`_ (python 2.6). Compiling 26 | the documentation requires `sphinx`_. 27 | 28 | Install all of these by running ``pip install -r test_requirements.txt``. Then 29 | just run ``nosetests`` to run the tests. 30 | 31 | .. _requests: http://docs.python-requests.org/en/v0.10.6/index.html 32 | .. _nose: http://readthedocs.org/docs/nose/en/latest 33 | .. _mock: http://pypi.python.org/pypi/mock 34 | .. _unittest2: http://pypi.python.org/pypi/unittest2 35 | .. _sphinx: http://sphinx.pocoo.org/ 36 | -------------------------------------------------------------------------------- /docs/issues.rst: -------------------------------------------------------------------------------- 1 | .. _Issues service: 2 | 3 | Issues services 4 | =============== 5 | 6 | **Fast sample**:: 7 | 8 | from pygithub3 import Github 9 | 10 | auth = dict(login='octocat', password='pass') 11 | gh = Github(**auth) 12 | 13 | octocat_issues = gh.issues.list() 14 | octocat_repo_issues = gh.issues.list_by_repo('octocat', 'Hello-World') 15 | 16 | Issues 17 | ------ 18 | 19 | .. autoclass:: pygithub3.services.issues.Issue 20 | :members: 21 | 22 | .. attribute:: comments 23 | 24 | :ref:`Issues comments service` 25 | 26 | .. attribute:: events 27 | 28 | :ref:`Issues events service` 29 | 30 | .. attribute:: labels 31 | 32 | :ref:`Labels service` 33 | 34 | .. attribute:: milestones 35 | 36 | :ref:`Milestones service` 37 | 38 | .. _Issues comments service: 39 | 40 | Comments 41 | -------- 42 | 43 | .. autoclass:: pygithub3.services.issues.Comments 44 | :members: 45 | 46 | .. _Issues events service: 47 | 48 | Events 49 | ------ 50 | 51 | .. autoclass:: pygithub3.services.issues.Events 52 | :members: 53 | 54 | .. _Labels service: 55 | 56 | Labels 57 | ------ 58 | 59 | .. autoclass:: pygithub3.services.issues.Labels 60 | :members: 61 | 62 | .. _Milestones service: 63 | 64 | Milestones 65 | ---------- 66 | 67 | .. autoclass:: pygithub3.services.issues.Milestones 68 | :members: 69 | 70 | .. _github issues doc: http://developer.github.com/v3/issues 71 | .. _github comments doc: http://developer.github.com/v3/issues/comments 72 | .. _github events doc: http://developer.github.com/v3/issues/events 73 | .. _github labels doc: http://developer.github.com/v3/issues/labels 74 | .. _github milestones doc: http://developer.github.com/v3/issues/milestones 75 | -------------------------------------------------------------------------------- /docs/orgs.rst: -------------------------------------------------------------------------------- 1 | .. _Orgs service: 2 | 3 | Orgs services 4 | ============== 5 | 6 | **Fast sample**:: 7 | 8 | from pygithub3 import Github 9 | 10 | gh = Github(token='abc123') 11 | 12 | auth_orgs = gh.orgs.list().all() 13 | members = gh.orgs.members.list('github') 14 | 15 | Org 16 | ------ 17 | 18 | .. autoclass:: pygithub3.services.orgs.Org 19 | :members: 20 | 21 | .. attribute:: members 22 | 23 | :ref:`Members service` 24 | 25 | .. attribute:: teams 26 | 27 | :ref:`Teams service` 28 | 29 | .. _Members service: 30 | 31 | Members 32 | --------- 33 | 34 | .. autoclass:: pygithub3.services.orgs.members.Members 35 | :members: 36 | 37 | .. _Teams service: 38 | 39 | Teams 40 | ------- 41 | 42 | .. autoclass:: pygithub3.services.orgs.teams.Teams 43 | :members: 44 | 45 | .. _github orgs doc: http://developer.github.com/v3/orgs 46 | .. _github orgs teams doc: http://developer.github.com/v3/orgs/teams 47 | -------------------------------------------------------------------------------- /docs/pull_requests.rst: -------------------------------------------------------------------------------- 1 | .. _Pull Requests service: 2 | 3 | Pull Requests service 4 | ===================== 5 | 6 | **Example**:: 7 | 8 | from pygithub3 import Github 9 | 10 | gh = Github(user='octocat', repo='sample') 11 | 12 | pull_requests = gh.pull_requests.list().all() 13 | pull_request_commits = gh.pull_requests.list_commits(2512).all() 14 | 15 | Pull Requests 16 | ------------- 17 | 18 | .. autoclass:: pygithub3.services.pull_requests.PullRequests 19 | :members: 20 | 21 | .. attribute:: comments 22 | 23 | :ref:`Pull Request Comments service` 24 | 25 | 26 | .. _Pull Request Comments service: 27 | 28 | Pull Request Comments 29 | --------------------- 30 | 31 | .. autoclass:: pygithub3.services.pull_requests.Comments 32 | :members: 33 | 34 | .. _github pullrequests doc: http://developer.github.com/v3/pulls 35 | .. _github pullrequests comments doc: http://developer.github.com/v3/pulls/comments 36 | -------------------------------------------------------------------------------- /docs/repos.rst: -------------------------------------------------------------------------------- 1 | .. _Repos service: 2 | 3 | Repos services 4 | =================== 5 | 6 | **Fast sample**:: 7 | 8 | from pygithub3 import Github 9 | 10 | gh = Github() 11 | 12 | django_compressor = gh.repos.get(user='jezdez', repo='django_compressor') 13 | requests_collaborators = gh.repos.collaborators(user='kennethreitz', 14 | repo='requests') 15 | 16 | .. _config precedence: 17 | 18 | Config precedence 19 | ------------------ 20 | 21 | Some request always need ``user`` and ``repo`` parameters, both, to identify 22 | a `repository`. Because there are a lot of requests which need that parameters, 23 | you can :ref:`config each service` with ``user`` and ``repo`` globally. 24 | 25 | So several requests follow a simple precedence 26 | ``user_in_arg > user_in_config | repo_in_arg > repo_in_config`` 27 | 28 | You can see it better with an example: :: 29 | 30 | from pygithub3 import Github 31 | 32 | gh = Github(user='octocat', repo='oct_repo') 33 | oct_repo = gh.repos.get() 34 | another_repo_from_octocat = gh.repos.get(repo='another_repo') 35 | 36 | django_compressor = gh.repos.get(user='jezdez', repo='django_compressor') 37 | 38 | .. note:: 39 | 40 | Remember that each service is isolated from the rest :: 41 | 42 | # continue example... 43 | gh.repos.commits.set_user('copitux') 44 | oct_repo = gh.repos.get() 45 | oct_repo_collaborators = gh.repos.collaborators.list().all() 46 | 47 | # Fail because copitux/oct_repo doesn't exist 48 | gh.repos.commits.list_comments() 49 | 50 | Repo 51 | ------- 52 | 53 | .. autoclass:: pygithub3.services.repos.Repo 54 | :members: 55 | 56 | .. attribute:: collaborators 57 | 58 | :ref:`Collaborators service` 59 | 60 | .. attribute:: commits 61 | 62 | :ref:`Commits service` 63 | 64 | .. attribute:: downloads 65 | 66 | :ref:`Downloads service` 67 | 68 | .. attribute:: forks 69 | 70 | :ref:`Forks service` 71 | 72 | .. attribute:: keys 73 | 74 | :ref:`RepoKeys service` 75 | 76 | .. attribute:: watchers 77 | 78 | :ref:`Watchers service` 79 | 80 | .. _Collaborators service: 81 | 82 | Collaborators 83 | -------------- 84 | 85 | .. autoclass:: pygithub3.services.repos.Collaborators 86 | :members: 87 | 88 | .. _Commits service: 89 | 90 | Commits 91 | ---------- 92 | 93 | .. autoclass:: pygithub3.services.repos.Commits 94 | :members: 95 | 96 | .. _Downloads service: 97 | 98 | Downloads 99 | ------------ 100 | 101 | .. autoclass:: pygithub3.services.repos.Downloads 102 | :members: 103 | 104 | 105 | .. _Forks service: 106 | 107 | Forks 108 | --------- 109 | 110 | .. autoclass:: pygithub3.services.repos.Forks 111 | :members: 112 | 113 | 114 | .. _RepoKeys service: 115 | 116 | Keys 117 | ---------- 118 | 119 | .. autoclass:: pygithub3.services.repos.Keys 120 | :members: 121 | 122 | 123 | .. _Watchers service: 124 | 125 | Watchers 126 | --------- 127 | 128 | .. autoclass:: pygithub3.services.repos.Watchers 129 | :members: 130 | 131 | .. _Hooks service: 132 | 133 | Hooks 134 | --------- 135 | 136 | .. autoclass:: pygithub3.services.repos.Hooks 137 | :members: 138 | 139 | .. _github repos doc: http://developer.github.com/v3/repos 140 | .. _github collaborators doc: http://developer.github.com/v3/repos/collaborators 141 | .. _github commits doc: http://developer.github.com/v3/repos/commits 142 | .. _github downloads doc: http://developer.github.com/v3/repos/downloads 143 | .. _github forks doc: http://developer.github.com/v3/repos/forks 144 | .. _github keys doc: http://developer.github.com/v3/repos/keys 145 | .. _github watching doc: http://developer.github.com/v3/repos/watching 146 | .. _github hooks doc: http://developer.github.com/v3/repos/hooks 147 | -------------------------------------------------------------------------------- /docs/resources.rst: -------------------------------------------------------------------------------- 1 | Resources 2 | ========== 3 | -------------------------------------------------------------------------------- /docs/result.rst: -------------------------------------------------------------------------------- 1 | 2 | Result 3 | ======= 4 | 5 | Some requests returns multiple :doc:`resources`, for that reason the 6 | ``Github API`` paginate it and **pygithub3** too 7 | 8 | Smart Result 9 | -------------- 10 | 11 | .. autoclass:: pygithub3.core.result.smart.Result 12 | :members: 13 | 14 | Normal Result 15 | --------------- 16 | 17 | .. autoclass:: pygithub3.core.result.normal.Result 18 | 19 | -------------------------------------------------------------------------------- /docs/services.rst: -------------------------------------------------------------------------------- 1 | Services 2 | ========== 3 | 4 | :doc:`github` class is a glue to all of them and the recommended option to 5 | start 6 | 7 | Overview 8 | ---------- 9 | 10 | You can access to the API requests through the different services. 11 | 12 | If you take a look at 13 | `github API v3 documentation `_, you'll see a 14 | few sections in the sidebar. 15 | 16 | **pygithub3** has one service per each section of request-related 17 | 18 | For example: :: 19 | 20 | repos => services.repos.repo 21 | collaborators => services.repos.collaborators 22 | commits => services.repos.commits 23 | .... 24 | 25 | Each service has the functions to throw the API requests and **is isolated 26 | from the rest**. 27 | 28 | .. _config each service: 29 | 30 | Config each service 31 | ---------------------- 32 | 33 | Each service can be configurated with some variables (behind the scenes, each 34 | service has her client which is configurated with this variables). 35 | 36 | .. note:: 37 | 38 | Also you can configure :doc:`github` as a service 39 | 40 | .. autoclass:: pygithub3.services.base.Service 41 | :members: 42 | 43 | .. _mimetypes-section: 44 | 45 | MimeTypes 46 | ---------- 47 | 48 | Some services supports `mimetypes`_ 49 | 50 | With them the :doc:`resources` will have ``body``, ``body_text``, ``body_html`` 51 | attributes or all of them. 52 | 53 | .. autoclass:: pygithub3.services.base.MimeTypeMixin 54 | :members: 55 | 56 | **Fast example**:: 57 | 58 | from pygithub3 import Github 59 | 60 | gh = Github() 61 | 62 | gh.gists.comments.set_html() 63 | comment = gh.gists.comments.list(1).all()[0] 64 | print comment.body, comment.body_text, comment.body_html 65 | 66 | List of services 67 | ------------------- 68 | 69 | .. toctree:: 70 | :maxdepth: 2 71 | 72 | users 73 | repos 74 | gists 75 | git_data 76 | pull_requests 77 | orgs 78 | issues 79 | events 80 | 81 | .. _mimetypes: http://developer.github.com/v3/mime 82 | -------------------------------------------------------------------------------- /docs/users.rst: -------------------------------------------------------------------------------- 1 | .. _Users service: 2 | 3 | Users services 4 | =============== 5 | 6 | **Fast sample**:: 7 | 8 | from pygithub3 import Github 9 | 10 | auth = dict(login='octocat', password='pass') 11 | gh = Github(**auth) 12 | 13 | # Get copitux user 14 | gh.users.get('copitux') 15 | 16 | # Get copitux's followers 17 | gh.users.followers.list('copitux') 18 | 19 | # Get octocat's emails 20 | gh.users.emails.list() 21 | 22 | User 23 | -------- 24 | 25 | .. autoclass:: pygithub3.services.users.User 26 | :members: 27 | 28 | .. attribute:: emails 29 | 30 | :ref:`Emails service` 31 | .. attribute:: keys 32 | 33 | :ref:`Keys service` 34 | .. attribute:: followers 35 | 36 | :ref:`Followers service` 37 | 38 | .. _Emails service: 39 | 40 | Emails 41 | -------- 42 | 43 | .. autoclass:: pygithub3.services.users.Emails 44 | :members: 45 | 46 | .. _Keys service: 47 | 48 | Keys 49 | ------ 50 | 51 | .. autoclass:: pygithub3.services.users.Keys 52 | :members: 53 | 54 | .. _Followers service: 55 | 56 | Followers 57 | ----------- 58 | 59 | .. autoclass:: pygithub3.services.users.Followers 60 | :members: 61 | -------------------------------------------------------------------------------- /pygithub3/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | __title__ = 'pygithub3' 4 | __version__ = '0.5.1' 5 | __author__ = 'David Medina' 6 | __email__ = 'davidmedina9@gmail.com' 7 | __license__ = 'ISC' 8 | __copyright__ = 'Copyright 2012 David Medina' 9 | 10 | from github import Github 11 | -------------------------------------------------------------------------------- /pygithub3/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/copitux/python-github3/321385860cb2ecaea1221612682c20e8069768b0/pygithub3/core/__init__.py -------------------------------------------------------------------------------- /pygithub3/core/client.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | import requests 4 | 5 | from .errors import GithubError 6 | 7 | VALID_REQUEST_ARGS = set(( 8 | 'params', 'data', 'headers', 'cookies', 'files', 'auth', 'timeout', 9 | 'allow_redirects', 'proxies', 'return_response', 'config', 10 | 'prefetch', 'verify')) 11 | 12 | 13 | class Client(object): 14 | """ Client to send configurated requests""" 15 | 16 | remaining_requests = '~' 17 | 18 | def __init__(self, **kwargs): 19 | self.requester = requests.session() 20 | self.config = { 21 | 'per_page': 100, 22 | 'base_url': 'https://api.github.com/' 23 | } 24 | self.config.update(kwargs) 25 | self.set_credentials(self.config.get('login'), 26 | self.config.get('password')) 27 | self.set_token(self.config.get('token')) 28 | self.__set_params(self.config) 29 | 30 | @property 31 | def user(self): 32 | return self.config.get('user') 33 | 34 | @user.setter 35 | def user(self, user): 36 | self.config['user'] = user 37 | 38 | @property 39 | def repo(self): 40 | return self.config.get('repo') 41 | 42 | @repo.setter 43 | def repo(self, repo): 44 | self.config['repo'] = repo 45 | 46 | def set_credentials(self, login, password): 47 | if login and password: 48 | self.requester.auth = (login, password) 49 | 50 | def set_token(self, token): 51 | if token: 52 | self.requester.params['access_token'] = token 53 | 54 | def __set_params(self, config): 55 | self.requester.params['per_page'] = config.get('per_page') 56 | if config.get('verbose'): 57 | self.requester.config = {'verbose': config['verbose']} 58 | if config.get('timeout'): 59 | self.requester.timeout = config['timeout'] 60 | 61 | def __parse_kwargs(func): 62 | """ Decorator to put extra args into requests.params """ 63 | 64 | def wrapper(self, verb, request, **kwargs): 65 | diffs = set(kwargs.keys()) - VALID_REQUEST_ARGS 66 | new_params = kwargs.get('params', {}) 67 | for key in diffs: # Put each key in new_params and delete it 68 | new_params[key] = kwargs[key] 69 | del kwargs[key] 70 | kwargs['params'] = new_params 71 | return func(self, verb, request, **kwargs) 72 | return wrapper 73 | 74 | @__parse_kwargs 75 | def request(self, verb, request, **kwargs): 76 | request = "%s%s" % (self.config['base_url'], request) 77 | response = self.requester.request(verb, request, **kwargs) 78 | Client.remaining_requests = response.headers.get( 79 | 'x-ratelimit-remaining', -1) 80 | GithubError(response).process() 81 | return response 82 | 83 | def get(self, request, **kwargs): 84 | response = self.request('get', request, **kwargs) 85 | assert response.status_code == 200 86 | return response 87 | 88 | def post(self, request, **kwargs): 89 | response = self.request('post', request, **kwargs) 90 | assert response.status_code == 201 91 | return response 92 | 93 | def patch(self, request, **kwargs): 94 | response = self.request('patch', request, **kwargs) 95 | assert response.status_code == 200 96 | return response 97 | 98 | def put(self, request, **kwargs): 99 | response = self.request('put', request, **kwargs) 100 | # assert response.status_code != '204' 101 | # I don't do an assert. See `services.base.Service._put` comment 102 | return response 103 | 104 | def delete(self, request, **kwargs): 105 | response = self.request('delete', request, **kwargs) 106 | assert response.status_code == 204 107 | return response 108 | 109 | def head(self, request, **kwargs): 110 | return self.request('head', request, **kwargs) 111 | -------------------------------------------------------------------------------- /pygithub3/core/compat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | """ Utils to support python 2.6 compatibility """ 4 | 5 | from collections import MutableMapping 6 | 7 | 8 | def _import_module(module_uri): 9 | return __import__(module_uri, {}, {}, ['']) 10 | 11 | 12 | def import_module(module_uri): 13 | """ Import module by string 'from.path.module' 14 | 15 | To support python 2.6 16 | """ 17 | try: 18 | from importlib import import_module 19 | callback = import_module 20 | except ImportError: 21 | callback = _import_module 22 | 23 | return callback(module_uri) 24 | 25 | 26 | class _OrderedDict(dict, MutableMapping): 27 | """ 28 | Src: http://code.activestate.com/recipes/576669/ 29 | Author: Raymond Hettinger (Promoter of PEP which introduces OrderDict into 30 | colletions module in python >2.7) 31 | """ 32 | 33 | # Methods with direct access to underlying attributes 34 | 35 | def __init__(self, *args, **kwds): 36 | if len(args) > 1: 37 | raise TypeError('expected at 1 argument, got %d', len(args)) 38 | if not hasattr(self, '_keys'): 39 | self._keys = [] 40 | self.update(*args, **kwds) 41 | 42 | def clear(self): 43 | del self._keys[:] 44 | dict.clear(self) 45 | 46 | def __setitem__(self, key, value): 47 | if key not in self: 48 | self._keys.append(key) 49 | dict.__setitem__(self, key, value) 50 | 51 | def __delitem__(self, key): 52 | dict.__delitem__(self, key) 53 | self._keys.remove(key) 54 | 55 | def __iter__(self): 56 | return iter(self._keys) 57 | 58 | def __reversed__(self): 59 | return reversed(self._keys) 60 | 61 | def popitem(self): 62 | if not self: 63 | raise KeyError 64 | key = self._keys.pop() 65 | value = dict.pop(self, key) 66 | return key, value 67 | 68 | def __reduce__(self): 69 | items = [[k, self[k]] for k in self] 70 | inst_dict = vars(self).copy() 71 | inst_dict.pop('_keys', None) 72 | return (self.__class__, (items,), inst_dict) 73 | 74 | # Methods with indirect access via the above methods 75 | 76 | setdefault = MutableMapping.setdefault 77 | update = MutableMapping.update 78 | pop = MutableMapping.pop 79 | keys = MutableMapping.keys 80 | values = MutableMapping.values 81 | items = MutableMapping.items 82 | 83 | def __repr__(self): 84 | pairs = ', '.join(map('%r: %r'.__mod__, self.items())) 85 | return '%s({%s})' % (self.__class__.__name__, pairs) 86 | 87 | def copy(self): 88 | return self.__class__(self) 89 | 90 | @classmethod 91 | def fromkeys(cls, iterable, value=None): 92 | d = cls() 93 | for key in iterable: 94 | d[key] = value 95 | return d 96 | 97 | try: 98 | from collections import OrderedDict 99 | except ImportError: 100 | OrderedDict = _OrderedDict 101 | -------------------------------------------------------------------------------- /pygithub3/core/errors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from pygithub3.core import json 5 | from pygithub3.exceptions import NotFound, BadRequest, UnprocessableEntity 6 | 7 | 8 | class GithubError(object): 9 | """ Handler for API errors """ 10 | 11 | def __init__(self, response): 12 | self.response = response 13 | self.status_code = response.status_code 14 | try: 15 | self.debug = json.loads(response.content) 16 | except (ValueError, TypeError): 17 | self.debug = {'message': response.content} 18 | 19 | def error_404(self): 20 | raise NotFound("404 - %s" % self.debug.get('message')) 21 | 22 | def error_400(self): 23 | raise BadRequest("400 - %s" % self.debug.get('message')) 24 | 25 | def error_422(self): 26 | errors = self.debug.get('errors', ()) 27 | errors = ['Resource: {resource}: {field} => {code}'.format(**error) 28 | for error in errors] 29 | raise UnprocessableEntity( 30 | '422 - %s %s' % (self.debug.get('message'), errors)) 31 | 32 | def process(self): 33 | raise_error = getattr(self, 'error_%s' % self.status_code, False) 34 | if raise_error: 35 | raise raise_error() 36 | self.response.raise_for_status() 37 | -------------------------------------------------------------------------------- /pygithub3/core/json/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Emulate json module with encode/decoders to support github datetime format 4 | """ 5 | 6 | from datetime import datetime 7 | try: 8 | import simplejson as json 9 | except ImportError: 10 | import json 11 | 12 | GITHUB_DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ' 13 | 14 | 15 | class GHJSONEncoder(json.JSONEncoder): 16 | def default(self, o): 17 | try: 18 | return datetime.strftime(o, GITHUB_DATE_FORMAT) 19 | except: 20 | return super(GHJSONEncoder, self).default(o) 21 | 22 | 23 | def gh_decoder_hook(dict_): 24 | for k, v in dict_.iteritems(): 25 | try: 26 | date = datetime.strptime(v, GITHUB_DATE_FORMAT) 27 | dict_[k] = date 28 | except: 29 | continue 30 | return dict_ 31 | 32 | 33 | def dumps(obj, cls=GHJSONEncoder, **kwargs): 34 | return json.dumps(obj, cls=cls, **kwargs) 35 | 36 | 37 | def loads(s, object_hook=gh_decoder_hook, **kwargs): 38 | return json.loads(s, object_hook=object_hook, **kwargs) 39 | 40 | dump = json.dump 41 | load = json.load 42 | -------------------------------------------------------------------------------- /pygithub3/core/result/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /pygithub3/core/result/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | import functools 5 | 6 | 7 | class Method(object): 8 | """ It wraps the requester method, with behaviour to results """ 9 | 10 | def __init__(self, method, request, **method_args): 11 | self.method = functools.partial(method, request, **method_args) 12 | self.resource = request.resource 13 | self.cache = {} 14 | 15 | def __call__(self): 16 | raise NotImplementedError 17 | 18 | 19 | class Page(object): 20 | """ Iterator of resources """ 21 | 22 | def __init__(self, getter, page=1): 23 | self.getter = getter 24 | self.page = page 25 | 26 | def __iter__(self): 27 | return self 28 | 29 | def __add__(self, number): 30 | return self.page + number 31 | 32 | def __radd__(self, number): 33 | return number + self.page 34 | 35 | def __sub__(self, number): 36 | return self.page - number 37 | 38 | def __rsub__(self, number): 39 | return number - self.page 40 | 41 | def __lt__(self, number): 42 | return self.page < number 43 | 44 | def __le__(self, number): 45 | return self.page <= number 46 | 47 | def __eq__(self, number): 48 | return self.page == number 49 | 50 | def __ne__(self, number): 51 | return self.page != number 52 | 53 | def __gt__(self, number): 54 | return self.page > number 55 | 56 | def __ge__(self, number): 57 | return self.page >= number 58 | 59 | @property 60 | def resources(self): 61 | return getattr(self, 'count', None) or '~' 62 | 63 | def get_content(func): 64 | def wrapper(self): 65 | if not hasattr(self, 'count'): 66 | content = self.getter(self.page) 67 | self.count = len(content) 68 | self.iterable = iter(content) 69 | return func(self) 70 | return wrapper 71 | 72 | @get_content 73 | def __next__(self): 74 | try: 75 | return self.iterable.next() 76 | except StopIteration: 77 | self.iterable = iter(self.getter(self.page)) 78 | raise StopIteration 79 | 80 | def next(self): 81 | return self.__next__() 82 | 83 | def __str__(self): 84 | return '<{name}{page} resources={resources}>'.format( 85 | name=self.__class__.__name__, 86 | page=self.page, 87 | resources=self.resources) 88 | 89 | 90 | class Result(object): 91 | """ Iterator of pages """ 92 | 93 | def __init__(self, method): 94 | self.getter = method 95 | 96 | def __iter__(self): 97 | return self 98 | 99 | def next(self): 100 | return self.__next__() 101 | 102 | def iterator(self): 103 | """ generator """ 104 | for page in self: 105 | for resource in page: 106 | yield resource 107 | 108 | def all(self): 109 | return list(self.iterator()) 110 | -------------------------------------------------------------------------------- /pygithub3/core/result/link.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from urlparse import urlparse, parse_qs 5 | 6 | from pygithub3.core.third_libs.link_header import parse_link_value 7 | 8 | 9 | class Link(str): 10 | 11 | class Url(str): 12 | 13 | @property 14 | def query(self): 15 | return urlparse(self).query 16 | 17 | @property 18 | def params(self): 19 | return dict([ 20 | (param, values.pop()) 21 | for param, values in parse_qs(self.query).items()]) 22 | 23 | def __init__(self, object_): 24 | str.__init__(object_) 25 | parsed = parse_link_value(self) 26 | for url in parsed: 27 | setattr(self, parsed[url]['rel'], Link.Url(url)) 28 | -------------------------------------------------------------------------------- /pygithub3/core/result/normal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import base 5 | from .link import Link 6 | 7 | 8 | class Method(base.Method): 9 | """ Cache support and builds next request """ 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(Method, self).__init__(*args, **kwargs) 13 | self.next = True 14 | 15 | def cached(func): 16 | def wrapper(self, page=1): 17 | if str(page) in self.cache: 18 | return self.cache[str(page)]['content'] 19 | return func(self, page) 20 | return wrapper 21 | 22 | def next_getter_from(self, response): 23 | link = Link(response.headers.get('link')) 24 | if hasattr(link, 'next'): 25 | return base.functools.partial(self.method, **link.next.params) 26 | self.next = False 27 | 28 | @cached 29 | def __call__(self, page=1): 30 | prev = self.cache.get(str(page - 1)) 31 | method = prev and prev['next'] or self.method 32 | response = method() 33 | self.cache[str(page)] = { 34 | 'content': self.resource.loads(response.content), 35 | 'next': self.next_getter_from(response) 36 | } 37 | return self.cache[str(page)]['content'] 38 | 39 | 40 | class Page(base.Page): 41 | """ Consumed when instance """ 42 | 43 | def __init__(self, getter, page=1): 44 | super(Page, self).__init__(getter, page) 45 | content = getter(page) 46 | self.iterable = iter(content) 47 | self.count = len(content) 48 | 49 | 50 | class Result(base.Result): 51 | """ 52 | It's a middle-lazy iterator, because to get a new page it needs 53 | make a real request, besides it's **cached**, so never repeats a request. 54 | 55 | You have several ways to consume it 56 | 57 | #. Iterating over the result:: 58 | 59 | result = some_request() 60 | for page in result: 61 | for resource in page: 62 | print resource 63 | 64 | #. With a generator:: 65 | 66 | result = some_request() 67 | for resource in result.iterator(): 68 | print resource 69 | 70 | #. As a list:: 71 | 72 | result = some_request() 73 | print result.all() 74 | 75 | """ 76 | 77 | """ TODO: limit in {all/iterator} 78 | .. note:: 79 | You can use ``limit`` with `all` and `iterator` 80 | :: 81 | result = some_request() 82 | _5resources = result.all(limit=5) 83 | 84 | This exists because it can't request a explitic page, and some requests 85 | can have thousand of resources (e.g Repository's commits) 86 | """ 87 | 88 | def __init__(self, method): 89 | super(Result, self).__init__(method) 90 | self._counter = 0 91 | self._cached = False 92 | 93 | def _get_cached(func): 94 | def wrapper(self): 95 | if self._cached: 96 | if str(self._counter) in self.getter.cache: 97 | page = Page(self.getter, self._counter) 98 | self._counter += 1 99 | return page 100 | self._reset() 101 | raise StopIteration 102 | return func(self) 103 | return wrapper 104 | 105 | @_get_cached 106 | def __next__(self): 107 | if self.getter.next: 108 | self._counter += 1 109 | return Page(self.getter, self._counter) 110 | self._reset() 111 | raise StopIteration 112 | 113 | def _reset(self): 114 | self._counter = 1 115 | self._cached = True 116 | -------------------------------------------------------------------------------- /pygithub3/core/result/smart.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import base 5 | from .link import Link 6 | 7 | 8 | class Method(base.Method): 9 | """ Lazy and cache support """ 10 | 11 | def cached(func): 12 | """ Decorator to don't do a request if it's cached """ 13 | def wrapper(self, page=1): 14 | if str(page) in self.cache: 15 | return self.cache[str(page)] 16 | return func(self, page) 17 | return wrapper 18 | 19 | def if_needs_lastpage(func): 20 | """ Decorator to set last page only if it can and it hasn't retrieved 21 | before """ 22 | def wrapper(self, has_link): 23 | has_last_page = hasattr(self, 'last_page') 24 | if not has_last_page and has_link: 25 | return func(self, has_link) 26 | elif not has_last_page and not has_link: 27 | self.last_page = 1 28 | return wrapper 29 | 30 | @if_needs_lastpage 31 | def __set_last_page_from(self, link_header): 32 | """ Get and set last_page form link header """ 33 | link = Link(link_header) 34 | self.last_page = int(link.last.params.get('page')) 35 | 36 | @cached 37 | def __call__(self, page=1): 38 | """ Call a real request """ 39 | response = self.method(page=page) 40 | self.__set_last_page_from(response.headers.get('link')) 41 | self.cache[str(page)] = self.resource.loads(response.content) 42 | return self.cache[str(page)] 43 | 44 | @property 45 | def last(self): 46 | if not hasattr(self, 'last_page'): 47 | self() 48 | return self.last_page 49 | 50 | 51 | class Result(base.Result): 52 | """ 53 | It's a very **lazy** paginator beacuse only do a real request 54 | when is needed, besides it's **cached**, so never repeats a request. 55 | 56 | You have several ways to consume it 57 | 58 | #. Iterating over the result:: 59 | 60 | result = some_request() 61 | for page in result: 62 | for resource in page: 63 | print resource 64 | 65 | #. With a generator:: 66 | 67 | result = some_request() 68 | for resource in result.iterator(): 69 | print resource 70 | 71 | #. As a list:: 72 | 73 | result = some_request() 74 | print result.all() 75 | 76 | #. Also you can request some page manually 77 | 78 | Each ``Page`` is an iterator and contains resources:: 79 | 80 | result = some_request() 81 | assert result.pages > 3 82 | page3 = result.get_page(3) 83 | page3_resources = list(page3) 84 | """ 85 | 86 | def __init__(self, method): 87 | super(Result, self).__init__(method) 88 | self.page = base.Page(self.getter) 89 | 90 | def __next__(self): 91 | if self.page <= self.pages: 92 | page_to_return = self.page 93 | self.page = base.Page(self.getter, page_to_return + 1) 94 | return page_to_return 95 | self.page = base.Page(self.getter) 96 | raise StopIteration 97 | 98 | @property 99 | def pages(self): 100 | """ Total number of pages in request """ 101 | return self.getter.last 102 | 103 | def get_page(self, page): 104 | """ Get ``Page`` of resources 105 | 106 | :param int page: Page number 107 | """ 108 | if page in xrange(1, self.pages + 1): 109 | return base.Page(self.getter, page) 110 | return None 111 | -------------------------------------------------------------------------------- /pygithub3/core/third_libs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/copitux/python-github3/321385860cb2ecaea1221612682c20e8069768b0/pygithub3/core/third_libs/__init__.py -------------------------------------------------------------------------------- /pygithub3/core/third_libs/link_header.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | HTTP Link Header Parsing 5 | 6 | Simple routines to parse and manipulate Link headers. 7 | """ 8 | 9 | __license__ = """ 10 | Copyright (c) 2009 Mark Nottingham 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to deal 14 | in the Software without restriction, including without limitation the rights 15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in 20 | all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | THE SOFTWARE. 29 | """ 30 | 31 | import re 32 | 33 | TOKEN = r'(?:[^\(\)<>@,;:\\"/\[\]\?={} \t]+?)' 34 | QUOTED_STRING = r'(?:"(?:\\"|[^"])*")' 35 | PARAMETER = r'(?:%(TOKEN)s(?:=(?:%(TOKEN)s|%(QUOTED_STRING)s))?)' % locals() 36 | LINK = r'<[^>]*>\s*(?:;\s*%(PARAMETER)s?\s*)*' % locals() 37 | COMMA = r'(?:\s*(?:,\s*)+)' 38 | LINK_SPLIT = r'%s(?=%s|\s*$)' % (LINK, COMMA) 39 | 40 | def _unquotestring(instr): 41 | if instr[0] == instr[-1] == '"': 42 | instr = instr[1:-1] 43 | instr = re.sub(r'\\(.)', r'\1', instr) 44 | return instr 45 | def _splitstring(instr, item, split): 46 | if not instr: 47 | return [] 48 | return [ h.strip() for h in re.findall(r'%s(?=%s|\s*$)' % (item, split), instr)] 49 | 50 | link_splitter = re.compile(LINK_SPLIT) 51 | 52 | def parse_link_value(instr): 53 | """ 54 | Given a link-value (i.e., after separating the header-value on commas), 55 | return a dictionary whose keys are link URLs and values are dictionaries 56 | of the parameters for their associated links. 57 | 58 | Note that internationalised parameters (e.g., title*) are 59 | NOT percent-decoded. 60 | 61 | Also, only the last instance of a given parameter will be included. 62 | 63 | For example, 64 | 65 | >>> parse_link_value('; rel="self"; title*=utf-8\'de\'letztes%20Kapitel') 66 | {'/foo': {'title*': "utf-8'de'letztes%20Kapitel", 'rel': 'self'}} 67 | 68 | """ 69 | out = {} 70 | if not instr: 71 | return out 72 | for link in [h.strip() for h in link_splitter.findall(instr)]: 73 | url, params = link.split(">", 1) 74 | url = url[1:] 75 | param_dict = {} 76 | for param in _splitstring(params, PARAMETER, "\s*;\s*"): 77 | try: 78 | a, v = param.split("=", 1) 79 | param_dict[a.lower()] = _unquotestring(v) 80 | except ValueError: 81 | param_dict[param.lower()] = None 82 | out[url] = param_dict 83 | return out 84 | 85 | 86 | if __name__ == '__main__': 87 | import sys 88 | if len(sys.argv) > 1: 89 | print parse_link_value(sys.argv[1]) -------------------------------------------------------------------------------- /pygithub3/exceptions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | 5 | class InvalidBodySchema(Exception): 6 | """ Raised when the 'valids_body' attribute of Resource isn't in a 7 | valid form (required.issubsetof(schema))""" 8 | pass 9 | 10 | 11 | class RequestDoesNotExist(Exception): 12 | """ Raised when `Request` factory can't find the subclass """ 13 | pass 14 | 15 | 16 | class UriInvalid(Exception): 17 | """ Raised when `Request` factory's maker isn't in a valid form """ 18 | pass 19 | 20 | 21 | class ValidationError(Exception): 22 | """ Raised when a `Request` doesn't have the necessary args to make a 23 | valid URI """ 24 | pass 25 | 26 | 27 | class BadRequest(Exception): 28 | """ Raised when server response is 400 """ 29 | pass 30 | 31 | 32 | class UnprocessableEntity(Exception): 33 | """ Raised when server response is 400 """ 34 | pass 35 | 36 | 37 | class NotFound(Exception): 38 | """ Raised when server response is 404 39 | 40 | Caught with a pygithub3-exception to `services.base.Service._bool` method 41 | """ 42 | pass 43 | -------------------------------------------------------------------------------- /pygithub3/github.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | 5 | #TODO: Move the imports out. setup related 6 | class Github(object): 7 | """ 8 | You can preconfigure all services globally with a ``config`` dict. See 9 | :attr:`~pygithub3.services.base.Service` 10 | 11 | Example:: 12 | 13 | gh = Github(user='kennethreitz', token='ABC...', repo='requests') 14 | """ 15 | 16 | def __init__(self, **config): 17 | from pygithub3.services.users import User 18 | from pygithub3.services.repos import Repo 19 | from pygithub3.services.gists import Gist 20 | from pygithub3.services.events import Event 21 | from pygithub3.services.git_data import GitData 22 | from pygithub3.services.pull_requests import PullRequests 23 | from pygithub3.services.orgs import Org 24 | from pygithub3.services.issues import Issue 25 | self._users = User(**config) 26 | self._repos = Repo(**config) 27 | self._gists = Gist(**config) 28 | self._git_data = GitData(**config) 29 | self._pull_requests = PullRequests(**config) 30 | self._orgs = Org(**config) 31 | self._issues = Issue(**config) 32 | self._events = Event(**config) 33 | 34 | @property 35 | def remaining_requests(self): 36 | """ Limit of Github API v3 """ 37 | from pygithub3.core.client import Client 38 | return Client.remaining_requests 39 | 40 | @property 41 | def users(self): 42 | """ 43 | :ref:`Users service ` 44 | """ 45 | return self._users 46 | 47 | @property 48 | def repos(self): 49 | """ 50 | :ref:`Repos service ` 51 | """ 52 | return self._repos 53 | 54 | @property 55 | def gists(self): 56 | """ 57 | :ref:`Gists service ` 58 | """ 59 | return self._gists 60 | 61 | @property 62 | def git_data(self): 63 | """ 64 | :ref:`Git Data service ` 65 | """ 66 | return self._git_data 67 | 68 | @property 69 | def pull_requests(self): 70 | """ 71 | :ref:`Pull Requests service ` 72 | """ 73 | return self._pull_requests 74 | 75 | @property 76 | def orgs(self): 77 | """ 78 | :ref:`Orgs service ` 79 | """ 80 | return self._orgs 81 | 82 | @property 83 | def issues(self): 84 | """ 85 | :ref:`Issues service ` 86 | """ 87 | return self._issues 88 | 89 | @property 90 | def events(self): 91 | """ 92 | :ref:`Events service ` 93 | """ 94 | return self._events 95 | -------------------------------------------------------------------------------- /pygithub3/requests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /pygithub3/requests/base.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | import re 4 | 5 | from pygithub3.core import json 6 | from pygithub3.core.compat import import_module 7 | from pygithub3.exceptions import (RequestDoesNotExist, UriInvalid, 8 | ValidationError, InvalidBodySchema) 9 | from pygithub3.resources.base import Raw 10 | 11 | ABS_IMPORT_PREFIX = 'pygithub3.requests' 12 | 13 | 14 | class Body(object): 15 | """ Input's request handler """ 16 | 17 | def __init__(self, content, schema, required): 18 | self.content = content 19 | self.schema = schema 20 | self.required = required 21 | 22 | def dumps(self): 23 | if not self.schema: 24 | return self.content or None 25 | return json.dumps(self.parse()) 26 | 27 | def parse(self): 28 | """ Parse body with schema-required rules """ 29 | if not hasattr(self.content, 'items'): 30 | raise ValidationError("It needs a content dictionary (%s)" % ( 31 | self.content, )) 32 | parsed = dict([(key, self.content[key]) for key in self.schema 33 | if key in self.content]) 34 | for attr_required in self.required: 35 | if attr_required not in parsed: 36 | raise ValidationError("'%s' attribute is required" % 37 | attr_required) 38 | if parsed[attr_required] is None: 39 | raise ValidationError("'%s' attribute can't be empty" % 40 | attr_required) 41 | return parsed 42 | 43 | 44 | class Request(object): 45 | 46 | uri = '' 47 | resource = Raw 48 | body_schema = {} 49 | 50 | def __init__(self, **kwargs): 51 | self.body = kwargs.pop('body', {}) 52 | self.args = kwargs 53 | self.clean() 54 | 55 | def __getattr__(self, name): 56 | return self.args.get(name) 57 | 58 | def __str__(self): 59 | return self.populate_uri() 60 | 61 | def populate_uri(self): 62 | try: 63 | populated_uri = self.uri.format(**self.args) 64 | except KeyError: 65 | raise ValidationError( 66 | "'%s' request wasn't be able to populate the uri '%s' with " 67 | "'%s' args" % (self.__class__.__name__, self.uri, self.args)) 68 | return str(populated_uri).strip('/') 69 | 70 | def clean(self): 71 | self.uri = self.clean_uri() or self.uri 72 | self.body = Body(self.clean_body(), **self._clean_valid_body()) 73 | 74 | def clean_body(self): 75 | return self.body 76 | 77 | def clean_uri(self): 78 | return None 79 | 80 | def _clean_valid_body(self): 81 | schema = set(self.body_schema.get('schema', ())) 82 | required = set(self.body_schema.get('required', ())) 83 | if not required.issubset(schema): 84 | raise InvalidBodySchema( 85 | "'%s:valid_body' attribute is invalid. " 86 | "'%s required' isn't a subset of '%s schema'" % ( 87 | self.__class__.__name__, required, schema)) 88 | return dict(schema=schema, required=required) 89 | 90 | def get_body(self): 91 | return self.body.dumps() 92 | 93 | 94 | class Factory(object): 95 | """ Request builder """ 96 | 97 | import_pattern = re.compile(r'^(\w+\.)+\w+$') 98 | 99 | def validate(func): 100 | """ Decorator to check if request_uri 101 | has valid format: 'from.path.module.class' """ 102 | 103 | def wrapper(self, request_uri, **kwargs): 104 | if not Factory.import_pattern.match(request_uri): 105 | raise UriInvalid("'%s' isn't valid form" % request_uri) 106 | return func(self, request_uri.lower(), **kwargs) 107 | return wrapper 108 | 109 | @validate 110 | def __call__(self, request_uri, **kwargs): 111 | module_chunk, s, request_chunk = request_uri.rpartition('.') 112 | request_chunk = request_chunk.capitalize() 113 | try: 114 | # TODO: CamelCase and under_score support, now only Class Name 115 | module = import_module('%s.%s' % (ABS_IMPORT_PREFIX, module_chunk)) 116 | request_class = getattr(module, request_chunk) 117 | request = request_class(**kwargs) 118 | assert isinstance(request, Request) 119 | return request 120 | except ImportError: 121 | raise RequestDoesNotExist("'%s' module does not exist" 122 | % module_chunk) 123 | except AttributeError: 124 | raise RequestDoesNotExist("'%s' request does not exist in " 125 | "'%s' module" % (request_chunk, 126 | module_chunk)) 127 | -------------------------------------------------------------------------------- /pygithub3/requests/events/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.events import Event 5 | 6 | 7 | class List(Request): 8 | 9 | uri = 'events' 10 | resource = Event 11 | -------------------------------------------------------------------------------- /pygithub3/requests/events/networks.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from . import Request 4 | from pygithub3.resources.events import Network 5 | 6 | 7 | class List(Request): 8 | 9 | uri = 'networks/{user}/{repo}/events' 10 | resource = Network 11 | -------------------------------------------------------------------------------- /pygithub3/requests/events/orgs.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from . import Request 4 | from pygithub3.resources.events import Org 5 | 6 | 7 | class List(Request): 8 | 9 | uri = 'orgs/{org}/events' 10 | resource = Org 11 | -------------------------------------------------------------------------------- /pygithub3/requests/events/repos.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from . import Request 4 | from pygithub3.resources.events import Repo 5 | 6 | 7 | class List(Request): 8 | 9 | uri = 'repos/{user}/{repo}/events' 10 | resource = Repo 11 | -------------------------------------------------------------------------------- /pygithub3/requests/events/users.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from . import Request 4 | from pygithub3.resources.events import User, Org 5 | 6 | 7 | class List_received(Request): 8 | 9 | uri = 'users/{user}/received_events' 10 | resource = User 11 | 12 | 13 | class List_received_public(Request): 14 | 15 | uri = 'users/{user}/received_events/public' 16 | resource = User 17 | 18 | 19 | class List_performed(Request): 20 | 21 | uri = 'users/{user}/events' 22 | resource = User 23 | 24 | 25 | class List_performed_public(Request): 26 | 27 | uri = 'users/{user}/events/public' 28 | resource = User 29 | 30 | 31 | class List_org_events(Request): 32 | 33 | uri = 'users/{user}/events/orgs/{org}' 34 | resource = Org 35 | -------------------------------------------------------------------------------- /pygithub3/requests/gists/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.gists import Gist 5 | 6 | 7 | class List(Request): 8 | 9 | uri = 'users/{user}/gists' 10 | resource = Gist 11 | 12 | def clean_uri(self): 13 | if not self.user: 14 | return 'gists' 15 | 16 | 17 | class Public(Request): 18 | 19 | uri = 'gists/public' 20 | resource = Gist 21 | 22 | 23 | class Starred(Request): 24 | 25 | uri = 'gists/starred' 26 | resource = Gist 27 | 28 | 29 | class Get(Request): 30 | 31 | uri = 'gists/{id}' 32 | resource = Gist 33 | 34 | 35 | class Create(Request): 36 | 37 | uri = 'gists' 38 | resource = Gist 39 | body_schema = { 40 | 'schema': ('description', 'public', 'files'), 41 | 'required': ('public', 'files') 42 | } 43 | 44 | 45 | class Update(Request): 46 | 47 | uri = 'gists/{id}' 48 | resource = Gist 49 | body_schema = { 50 | 'schema': ('description', 'public', 'files'), 51 | 'required': (), 52 | } 53 | 54 | 55 | class Star(Request): 56 | 57 | uri = 'gists/{id}/star' 58 | 59 | 60 | class Unstar(Request): 61 | 62 | uri = 'gists/{id}/star' 63 | 64 | 65 | class Is_starred(Request): 66 | 67 | uri = 'gists/{id}/star' 68 | 69 | 70 | class Fork(Request): 71 | 72 | uri = 'gists/{id}/fork' 73 | resource = Gist 74 | 75 | 76 | class Delete(Request): 77 | 78 | uri = 'gists/{id}' 79 | -------------------------------------------------------------------------------- /pygithub3/requests/gists/comments.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.gists import Comment 5 | 6 | 7 | class List(Request): 8 | 9 | uri = 'gists/{gist_id}/comments' 10 | resource = Comment 11 | 12 | 13 | class Get(Request): 14 | 15 | uri = 'gists/comments/{id}' 16 | resource = Comment 17 | 18 | 19 | class Create(Request): 20 | 21 | uri = 'gists/{gist_id}/comments' 22 | resource = Comment 23 | body_schema = { 24 | 'schema': ('body', ), 25 | 'required': ('body', ) 26 | } 27 | 28 | 29 | class Update(Request): 30 | 31 | uri = 'gists/comments/{id}' 32 | resource = Comment 33 | body_schema = { 34 | 'schema': ('body', ), 35 | 'required': ('body', ) 36 | } 37 | 38 | 39 | class Delete(Request): 40 | 41 | uri = 'gists/comments/{id}' 42 | -------------------------------------------------------------------------------- /pygithub3/requests/git_data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/copitux/python-github3/321385860cb2ecaea1221612682c20e8069768b0/pygithub3/requests/git_data/__init__.py -------------------------------------------------------------------------------- /pygithub3/requests/git_data/blobs.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.git_data import Blob 5 | 6 | 7 | class Get(Request): 8 | uri = 'repos/{user}/{repo}/git/blobs/{sha}' 9 | resource = Blob 10 | 11 | 12 | class Create(Request): 13 | uri = 'repos/{user}/{repo}/git/blobs' 14 | resource = Blob 15 | body_schema = { 16 | 'schema': ('content', 'encoding'), 17 | 'required': ('content', 'encoding'), # TODO: is enc really required? 18 | } 19 | -------------------------------------------------------------------------------- /pygithub3/requests/git_data/commits.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.repos import Commit 5 | 6 | 7 | class Get(Request): 8 | uri = 'repos/{user}/{repo}/git/commits/{sha}' 9 | resource = Commit 10 | 11 | 12 | class Create(Request): 13 | uri = 'repos/{user}/{repo}/git/commits' 14 | resource = Commit 15 | body_schema = { 16 | 'schema': ('message', 'tree', 'parents', 'author', 'committer'), 17 | 'required': ('message', 'tree', 'parents'), 18 | } 19 | -------------------------------------------------------------------------------- /pygithub3/requests/git_data/references.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.git_data import Reference 5 | 6 | 7 | class Get(Request): 8 | uri = 'repos/{user}/{repo}/git/refs/{ref}' 9 | resource = Reference 10 | 11 | 12 | class List(Request): 13 | uri = 'repos/{user}/{repo}/git/refs/{namespace}' 14 | resource = Reference 15 | 16 | 17 | class Create(Request): 18 | uri = 'repos/{user}/{repo}/git/refs' 19 | resource = Reference 20 | body_schema = { 21 | 'schema': ('ref', 'sha'), 22 | 'required': ('ref', 'sha'), 23 | } 24 | 25 | 26 | class Update(Request): 27 | uri = 'repos/{user}/{repo}/git/refs/{ref}' 28 | resource = Reference 29 | body_schema = { 30 | 'schema': ('sha', 'force'), 31 | 'required': ('sha',), 32 | } 33 | 34 | 35 | class Delete(Request): 36 | uri = 'repos/{user}/{repo}/git/refs/{ref}' 37 | -------------------------------------------------------------------------------- /pygithub3/requests/git_data/tags.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.git_data import Tag 5 | 6 | 7 | class Get(Request): 8 | uri = 'repos/{user}/{repo}/git/tags/{sha}' 9 | resource = Tag 10 | 11 | 12 | class Create(Request): 13 | uri = 'repos/{user}/{repo}/git/tags' 14 | resource = Tag 15 | body_schema = { 16 | 'schema': ('tag', 'message', 'object', 'type', 'tagger'), 17 | 'required': ('type',), 18 | } 19 | -------------------------------------------------------------------------------- /pygithub3/requests/git_data/trees.py: -------------------------------------------------------------------------------- 1 | from pygithub3.requests.base import Request 2 | from pygithub3.resources.git_data import Tree 3 | 4 | 5 | class Get(Request): 6 | uri = 'repos/{user}/{repo}/git/trees/{sha}' 7 | resource = Tree 8 | 9 | 10 | class Create(Request): 11 | uri = 'repos/{user}/{repo}/git/trees' 12 | resource = Tree 13 | body_schema = { 14 | 'schema': ('tree', 'base_tree'), 15 | 'required': ('tree',), 16 | } 17 | -------------------------------------------------------------------------------- /pygithub3/requests/issues/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from pygithub3.requests.base import Request 5 | from pygithub3.resources.issues import Issue 6 | 7 | 8 | class List(Request): 9 | 10 | uri = 'issues' 11 | resource = Issue 12 | 13 | 14 | class List_by_repo(Request): 15 | 16 | uri = 'repos/{user}/{repo}/issues' 17 | resource = Issue 18 | 19 | 20 | class Get(Request): 21 | 22 | uri = 'repos/{user}/{repo}/issues/{number}' 23 | resource = Issue 24 | 25 | 26 | class Create(Request): 27 | 28 | uri = 'repos/{user}/{repo}/issues' 29 | resource = Issue 30 | body_schema = { 31 | 'schema': ('title', 'body', 'assignee', 'milestone', 'labels'), 32 | 'required': ('title', ) 33 | } 34 | 35 | 36 | class Update(Request): 37 | 38 | uri = 'repos/{user}/{repo}/issues/{number}' 39 | resource = Issue 40 | body_schema = { 41 | 'schema': ('title', 'body', 'assignee', 'state', 'milestone', 42 | 'lables'), 43 | 'required': () 44 | } 45 | -------------------------------------------------------------------------------- /pygithub3/requests/issues/comments.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.issues import Comment 5 | 6 | 7 | class List(Request): 8 | 9 | uri = 'repos/{user}/{repo}/issues/{number}/comments' 10 | resource = Comment 11 | 12 | 13 | class Get(Request): 14 | 15 | uri = 'repos/{user}/{repo}/issues/comments/{id}' 16 | resource = Comment 17 | 18 | 19 | class Create(Request): 20 | 21 | uri = 'repos/{user}/{repo}/issues/{number}/comments' 22 | resource = Comment 23 | body_schema = { 24 | 'schema': ('body', ), 25 | 'required': ('body', ) 26 | } 27 | 28 | 29 | class Edit(Request): 30 | 31 | uri = 'repos/{user}/{repo}/issues/comments/{id}' 32 | resource = Comment 33 | body_schema = { 34 | 'schema': ('body', ), 35 | 'required': ('body', ) 36 | } 37 | 38 | 39 | class Delete(Request): 40 | 41 | uri = 'repos/{user}/{repo}/issues/comments/{id}' 42 | resource = Comment 43 | -------------------------------------------------------------------------------- /pygithub3/requests/issues/events.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.issues import Event 5 | 6 | 7 | class List_by_issue(Request): 8 | 9 | uri = 'repos/{user}/{repo}/issues/{number}/events' 10 | resource = Event 11 | 12 | 13 | class List_by_repo(Request): 14 | 15 | uri = 'repos/{user}/{repo}/issues/events' 16 | resource = Event 17 | 18 | 19 | class Get(Request): 20 | 21 | uri = 'repos/{user}/{repo}/issues/events/{id}' 22 | resource = Event 23 | -------------------------------------------------------------------------------- /pygithub3/requests/issues/labels.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request, ValidationError 4 | from pygithub3.resources.issues import Label 5 | 6 | 7 | class List(Request): 8 | 9 | uri = 'repos/{user}/{repo}/labels' 10 | resource = Label 11 | 12 | 13 | class Get(Request): 14 | uri = 'repos/{user}/{repo}/labels/{name}' 15 | resource = Label 16 | 17 | 18 | class Create(Request): 19 | uri = 'repos/{user}/{repo}/labels' 20 | resource = Label 21 | body_schema = { 22 | 'schema': ('name', 'color'), 23 | 'required': ('name', 'color') 24 | } 25 | 26 | def clean_body(self): 27 | color = self.body.get('color', '') 28 | if not Label.is_valid_color(color): 29 | raise ValidationError('colors must have 6 hexadecimal characters, ' 30 | 'without # in the beggining') 31 | else: 32 | return self.body 33 | 34 | 35 | class Update(Create): 36 | 37 | uri = 'repos/{user}/{repo}/labels/{name}' 38 | resource = Label 39 | body_schema = { 40 | 'schema': ('name', 'color'), 41 | 'required': ('name', 'color') 42 | } 43 | 44 | 45 | class Delete(Request): 46 | uri = 'repos/{user}/{repo}/labels/{name}' 47 | resource = Label 48 | 49 | 50 | class List_by_issue(Request): 51 | uri = 'repos/{user}/{repo}/issues/{number}/labels' 52 | resource = Label 53 | 54 | 55 | class Add_to_issue(Request): 56 | uri = 'repos/{user}/{repo}/issues/{number}/labels' 57 | resource = Label 58 | 59 | 60 | class Remove_from_issue(Request): 61 | uri = 'repos/{user}/{repo}/issues/{number}/labels/{name}' 62 | resource = Label 63 | 64 | 65 | class Replace_all(Request): 66 | uri = 'repos/{user}/{repo}/issues/{number}/labels' 67 | resource = Label 68 | 69 | 70 | class Remove_all(Request): 71 | uri = 'repos/{user}/{repo}/issues/{number}/labels' 72 | resource = Label 73 | 74 | 75 | class List_by_milestone(Request): 76 | uri = 'repos/{user}/{repo}/milestones/{number}/labels' 77 | resource = Label 78 | -------------------------------------------------------------------------------- /pygithub3/requests/issues/milestones.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request, ValidationError 4 | from pygithub3.resources.issues import Milestone 5 | 6 | 7 | class List(Request): 8 | uri = 'repos/{user}/{repo}/milestones' 9 | resource = Milestone 10 | 11 | 12 | class Get(Request): 13 | uri = 'repos/{user}/{repo}/milestones/{number}' 14 | resource = Milestone 15 | 16 | 17 | class Create(Request): 18 | uri = 'repos/{user}/{repo}/milestones' 19 | resource = Milestone 20 | body_schema = { 21 | 'schema': ('title', 'state', 'description', 'due_on'), 22 | 'required': ('title',) 23 | } 24 | 25 | def clean_body(self): # Test if API normalize it 26 | state = self.body.get('state', '') 27 | if state and state.lower() not in ('open', 'closed'): 28 | raise ValidationError("'state' must be 'open' or 'closed'") 29 | return self.body 30 | 31 | 32 | class Update(Create): 33 | 34 | uri = 'repos/{user}/{repo}/milestones/{number}' 35 | 36 | 37 | class Delete(Request): 38 | uri = 'repos/{user}/{repo}/milestones/{number}' 39 | resource = Milestone 40 | -------------------------------------------------------------------------------- /pygithub3/requests/orgs/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.orgs import Org 5 | 6 | 7 | class List(Request): 8 | uri = 'users/{user}/orgs' 9 | resource = Org 10 | 11 | def clean_uri(self): 12 | if not self.user: 13 | return 'user/orgs' 14 | 15 | 16 | class Get(Request): 17 | uri = 'orgs/{org}' 18 | resource = Org 19 | 20 | 21 | class Update(Request): 22 | uri = 'orgs/{org}' 23 | resource = Org 24 | body_schema = { 25 | 'schema': ('billing_email', 'company', 'email', 'location', 'name'), 26 | 'required': (), 27 | } 28 | -------------------------------------------------------------------------------- /pygithub3/requests/orgs/members.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.resources.orgs import Member 4 | from . import Request 5 | 6 | 7 | class List(Request): 8 | uri = 'orgs/{org}/members' 9 | resource = Member 10 | 11 | 12 | class Is_member(Request): 13 | uri = 'orgs/{org}/members/{user}' 14 | 15 | 16 | class Delete(Request): 17 | uri = 'orgs/{org}/members/{user}' 18 | 19 | 20 | class Listpublic(Request): 21 | uri = 'orgs/{org}/public_members' 22 | resource = Member 23 | 24 | 25 | class Is_public_member(Request): 26 | uri = 'orgs/{org}/public_members/{user}' 27 | 28 | 29 | class Publicize(Request): 30 | uri = 'orgs/{org}/public_members/{user}' 31 | 32 | 33 | class Conceal(Request): 34 | uri = 'orgs/{org}/public_members/{user}' 35 | -------------------------------------------------------------------------------- /pygithub3/requests/orgs/teams.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.resources.orgs import Member, Team 4 | from pygithub3.resources.repos import Repo 5 | from . import Request 6 | 7 | 8 | class List(Request): 9 | uri = 'orgs/{org}/teams' 10 | resource = Team 11 | 12 | 13 | class Get(Request): 14 | uri = 'teams/{id}' 15 | resource = Team 16 | 17 | 18 | class Create(Request): 19 | uri = 'orgs/{org}/teams' 20 | resource = Team 21 | body_schema = { 22 | 'schema': ('name', 'repo_names', 'permission',), 23 | 'required': ('name',), 24 | } 25 | 26 | # TODO: Check if this request fails with invalid permission 27 | #def clean_body(self): 28 | 29 | 30 | class Update(Request): 31 | uri = 'teams/{id}' 32 | resource = Team 33 | body_schema = { 34 | 'schema': ('name', 'permission',), 35 | 'required': ('name',), 36 | } 37 | 38 | 39 | class Delete(Request): 40 | uri = 'teams/{id}' 41 | 42 | 43 | class List_members(Request): 44 | uri = 'teams/{id}/members' 45 | resource = Member 46 | 47 | 48 | class Is_member(Request): 49 | uri = 'teams/{id}/members/{user}' 50 | 51 | 52 | class Add_member(Request): 53 | uri = 'teams/{id}/members/{user}' 54 | 55 | 56 | class Remove_member(Request): 57 | uri = 'teams/{id}/members/{user}' 58 | 59 | 60 | class List_repos(Request): 61 | uri = 'teams/{id}/repos' 62 | resource = Repo 63 | 64 | 65 | class Contains_repo(Request): 66 | uri = 'teams/{id}/repos/{user}/{repo}' 67 | 68 | 69 | class Add_repo(Request): 70 | uri = 'teams/{id}/repos/{user}/{repo}' 71 | 72 | 73 | class Remove_repo(Request): 74 | uri = 'teams/{id}/repos/{user}/{repo}' 75 | -------------------------------------------------------------------------------- /pygithub3/requests/pull_requests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request, ValidationError 4 | from pygithub3.resources.pull_requests import PullRequest, File 5 | from pygithub3.resources.repos import Commit 6 | 7 | 8 | class List(Request): 9 | uri = 'repos/{user}/{repo}/pulls' 10 | resource = PullRequest 11 | 12 | 13 | class Get(Request): 14 | uri = 'repos/{user}/{repo}/pulls/{number}' 15 | resource = PullRequest 16 | 17 | 18 | class Create(Request): 19 | uri = 'repos/{user}/{repo}/pulls' 20 | resource = PullRequest 21 | body_schema = { 22 | 'schema': ('title', 'body', 'base', 'head', 'issue'), 23 | 'required': ('base', 'head'), 24 | } 25 | 26 | def clean_body(self): 27 | if (not ('title' in self.body and 'body' in self.body) and 28 | not 'issue' in self.body): 29 | raise ValidationError('pull request creation requires either an ' 30 | 'issue number or a title and body') 31 | return self.body 32 | 33 | 34 | class Update(Request): 35 | uri = 'repos/{user}/{repo}/pulls/{number}' 36 | resource = PullRequest 37 | body_schema = { 38 | 'schema': ('title', 'body', 'state'), 39 | 'required': (), 40 | } 41 | 42 | def clean_body(self): 43 | if ('state' in self.body and 44 | self.body['state'] not in ['open', 'closed']): 45 | raise ValidationError('If a state is specified, it must be one ' 46 | 'of "open" or "closed"') 47 | return self.body 48 | 49 | 50 | class List_commits(Request): 51 | uri = 'repos/{user}/{repo}/pulls/{number}/commits' 52 | resource = Commit 53 | 54 | 55 | class List_files(Request): 56 | uri = 'repos/{user}/{repo}/pulls/{number}/files' 57 | resource = File 58 | 59 | 60 | class Is_merged(Request): 61 | uri = 'repos/{user}/{repo}/pulls/{number}/merge' 62 | 63 | 64 | class Merge(Request): 65 | uri = 'repos/{user}/{repo}/pulls/{number}/merge' 66 | body_schema = { 67 | 'schema': ('commit_message',), 68 | 'required': (), 69 | } 70 | -------------------------------------------------------------------------------- /pygithub3/requests/pull_requests/comments.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request, ValidationError 4 | from pygithub3.resources.pull_requests import Comment 5 | 6 | 7 | class List(Request): 8 | uri = 'repos/{user}/{repo}/pulls/{number}/comments' 9 | resource = Comment 10 | 11 | 12 | class Get(Request): 13 | uri = 'repos/{user}/{repo}/pulls/comments/{number}' 14 | resource = Comment 15 | 16 | 17 | class Create(Request): 18 | uri = 'repos/{user}/{repo}/pulls/{number}/comments' 19 | resource = Comment 20 | body_schema = { 21 | 'schema': ('body', 'commit_id', 'path', 'position', 'in_reply_to'), 22 | 'required': ('body',), 23 | } 24 | 25 | def clean_body(self): 26 | if (not ('commit_id' in self.body and 27 | 'path' in self.body and 28 | 'position' in self.body) and 29 | not 'in_reply_to' in self.body): 30 | raise ValidationError('supply either in_reply_to or commit_id, ' 31 | 'path, and position') 32 | return self.body 33 | 34 | 35 | class Update(Request): 36 | uri = 'repos/{user}/{repo}/pulls/comments/{number}' 37 | resource = Comment 38 | body_schema = { 39 | 'schema': ('body',), 40 | 'required': ('body',), 41 | } 42 | 43 | 44 | class Delete(Request): 45 | uri = 'repos/{user}/{repo}/pulls/comments/{number}' 46 | resource = Comment 47 | -------------------------------------------------------------------------------- /pygithub3/requests/repos/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request 4 | from pygithub3.resources.orgs import Team 5 | from pygithub3.resources.repos import Repo, Tag, Branch 6 | from pygithub3.resources.users import User 7 | 8 | 9 | class List(Request): 10 | 11 | uri = 'users/{user}/repos' 12 | resource = Repo 13 | 14 | def clean_uri(self): 15 | if not self.user: 16 | return 'user/repos' 17 | 18 | 19 | class List_by_org(Request): 20 | 21 | uri = 'orgs/{org}/repos' 22 | resource = Repo 23 | 24 | 25 | class Create(Request): 26 | 27 | uri = 'orgs/{org}/repos' 28 | resource = Repo 29 | body_schema = { 30 | 'schema': ('name', 'description', 'homepage', 'private', 'has_issues', 31 | 'has_wiki', 'has_downloads', 'team_id'), 32 | 'required': ('name', ) 33 | } 34 | 35 | def clean_uri(self): 36 | if not self.org: 37 | return 'user/repos' 38 | 39 | 40 | class Get(Request): 41 | 42 | uri = 'repos/{user}/{repo}' 43 | resource = Repo 44 | 45 | 46 | class Delete(Request): 47 | 48 | uri = 'repos/{user}/{repo}' 49 | resource = Repo 50 | 51 | 52 | class Update(Request): 53 | 54 | uri = 'repos/{user}/{repo}' 55 | resource = Repo 56 | body_schema = { 57 | 'schema': ('name', 'description', 'homepage', 'private', 'has_issues', 58 | 'has_wiki', 'has_downloads', 'team_id'), 59 | 'required': ('name', ) 60 | } 61 | 62 | 63 | class List_contributors(Request): 64 | 65 | uri = 'repos/{user}/{repo}/contributors' 66 | resource = User 67 | 68 | 69 | class List_languages(Request): 70 | 71 | uri = 'repos/{user}/{repo}/languages' 72 | 73 | 74 | class List_teams(Request): 75 | 76 | uri = 'repos/{user}/{repo}/teams' 77 | resource = Team 78 | 79 | 80 | class List_tags(Request): 81 | 82 | uri = 'repos/{user}/{repo}/tags' 83 | resource = Tag 84 | 85 | 86 | class List_branches(Request): 87 | 88 | uri = 'repos/{user}/{repo}/branches' 89 | resource = Branch 90 | -------------------------------------------------------------------------------- /pygithub3/requests/repos/collaborators.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | from pygithub3.resources.users import User 6 | 7 | 8 | class List(Request): 9 | 10 | uri = 'repos/{user}/{repo}/collaborators' 11 | resource = User 12 | 13 | 14 | class Is_collaborator(Request): 15 | 16 | uri = 'repos/{user}/{repo}/collaborators/{collaborator}' 17 | 18 | 19 | class Add(Request): 20 | 21 | uri = 'repos/{user}/{repo}/collaborators/{collaborator}' 22 | 23 | 24 | class Delete(Request): 25 | 26 | uri = 'repos/{user}/{repo}/collaborators/{collaborator}' 27 | -------------------------------------------------------------------------------- /pygithub3/requests/repos/commits.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | from pygithub3.resources.repos import GitCommit, Comment, Diff 6 | 7 | 8 | class List(Request): 9 | 10 | uri = 'repos/{user}/{repo}/commits' 11 | resource = GitCommit 12 | 13 | 14 | class Get(Request): 15 | 16 | uri = 'repos/{user}/{repo}/commits/{sha}' 17 | resource = GitCommit 18 | 19 | 20 | class List_comments(Request): 21 | 22 | uri = 'repos/{user}/{repo}/comments' 23 | resource = Comment 24 | 25 | def clean_uri(self): 26 | if self.sha: 27 | return 'repos/{user}/{repo}/commits/{sha}/comments' 28 | 29 | 30 | class Create_comment(Request): 31 | 32 | uri = 'repos/{user}/{repo}/commits/{sha}/comments' 33 | resource = Comment 34 | body_schema = { 35 | 'schema': ('body', 'commit_id', 'line', 'path', 'position'), 36 | 'required': ('body', 'commit_id', 'line', 'path', 'position'), 37 | } 38 | 39 | 40 | class Get_comment(Request): 41 | 42 | uri = 'repos/{user}/{repo}/comments/{comment_id}' 43 | resource = Comment 44 | 45 | 46 | class Update_comment(Request): 47 | 48 | uri = 'repos/{user}/{repo}/comments/{comment_id}' 49 | resource = Comment 50 | body_schema = { 51 | 'schema': ('body', ), 52 | 'required': ('body', ), 53 | } 54 | 55 | 56 | class Compare(Request): 57 | 58 | uri = 'repos/{user}/{repo}/compare/{base}...{head}' 59 | resource = Diff 60 | 61 | 62 | class Delete_comment(Request): 63 | 64 | uri = 'repos/{user}/{repo}/comments/{comment_id}' 65 | -------------------------------------------------------------------------------- /pygithub3/requests/repos/downloads.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | 6 | from pygithub3.resources.repos import Download 7 | 8 | 9 | class List(Request): 10 | 11 | uri = '/repos/{user}/{repo}/downloads' 12 | resource = Download 13 | 14 | 15 | class Get(Request): 16 | 17 | uri = '/repos/{user}/{repo}/downloads/{id}' 18 | resource = Download 19 | 20 | 21 | class Create(Request): 22 | 23 | uri = '/repos/{user}/{repo}/downloads' 24 | resource = Download 25 | body_schema = { 26 | 'schema': ('name', 'size', 'description', 'content_type'), 27 | 'required': ('name', 'size') 28 | } 29 | 30 | 31 | class Delete(Request): 32 | 33 | uri = '/repos/{user}/{repo}/downloads/{id}' 34 | resource = Download 35 | -------------------------------------------------------------------------------- /pygithub3/requests/repos/forks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | 6 | from pygithub3.resources.repos import Repo 7 | 8 | 9 | class List(Request): 10 | 11 | uri = 'repos/{user}/{repo}/forks' 12 | resource = Repo 13 | 14 | 15 | class Create(Request): 16 | 17 | uri = '/repos/{user}/{repo}/forks' 18 | resource = Repo 19 | -------------------------------------------------------------------------------- /pygithub3/requests/repos/hooks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | from pygithub3.resources.repos import Hook 6 | 7 | 8 | class List(Request): 9 | 10 | uri = 'repos/{user}/{repo}/hooks' 11 | resource = Hook 12 | 13 | 14 | class Get(Request): 15 | 16 | uri = 'repos/{user}/{repo}/hooks/{id}' 17 | resource = Hook 18 | 19 | 20 | class Create(Request): 21 | 22 | uri = 'repos/{user}/{repo}/hooks' 23 | resource = Hook 24 | body_schema = { 25 | 'schema': ('name', 'config', 'events', 'active'), 26 | 'required': ('name', 'config'), 27 | } 28 | 29 | 30 | class Update(Request): 31 | 32 | uri = 'repos/{user}/{repo}/hooks/{id}' 33 | resource = Hook 34 | body_schema = { 35 | 'schema': ('name', 'config', 'events', 'add_events', 'remove_events', 36 | 'active'), 37 | 'required': (), 38 | } 39 | 40 | 41 | class Test(Request): 42 | 43 | uri = 'repos/{user}/{repo}/hooks/{id}/test' 44 | 45 | 46 | class Delete(Request): 47 | 48 | uri = 'repos/{user}/{repo}/hooks/{id}' 49 | -------------------------------------------------------------------------------- /pygithub3/requests/repos/keys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | 6 | from pygithub3.resources.users import Key 7 | 8 | 9 | class List(Request): 10 | 11 | uri = '/repos/{user}/{repo}/keys' 12 | resource = Key 13 | 14 | 15 | class Get(Request): 16 | 17 | uri = '/repos/{user}/{repo}/keys/{id}' 18 | resource = Key 19 | 20 | 21 | class Create(Request): 22 | 23 | uri = 'repos/{user}/{repo}/keys' 24 | resource = Key 25 | body_schema = { 26 | 'schema': ('title', 'key'), 27 | 'required': ('title', 'key') 28 | } 29 | 30 | 31 | class Update(Request): 32 | 33 | uri = 'repos/{user}/{repo}/keys/{id}' 34 | resource = Key 35 | body_schema = { 36 | 'schema': ('title', 'key'), 37 | 'required': (), 38 | } 39 | 40 | 41 | class Delete(Request): 42 | 43 | uri = 'repos/{user}/{repo}/keys/{id}' 44 | resource = Key 45 | -------------------------------------------------------------------------------- /pygithub3/requests/repos/watchers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | from pygithub3.resources.users import User 6 | from pygithub3.resources.repos import Repo 7 | 8 | 9 | class List(Request): 10 | 11 | uri = 'repos/{user}/{repo}/watchers' 12 | resource = User 13 | 14 | 15 | class List_repos(Request): 16 | 17 | uri = 'users/{user}/watched' 18 | resource = Repo 19 | 20 | def clean_uri(self): 21 | if not self.user: 22 | return 'user/watched' 23 | 24 | 25 | class Is_watching(Request): 26 | 27 | uri = 'user/watched/{user}/{repo}' 28 | 29 | 30 | class Watch(Request): 31 | 32 | uri = 'user/watched/{user}/{repo}' 33 | 34 | 35 | class Unwatch(Request): 36 | 37 | uri = 'user/watched/{user}/{repo}' 38 | -------------------------------------------------------------------------------- /pygithub3/requests/users/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.requests.base import Request, ValidationError 4 | from pygithub3.resources.users import User 5 | 6 | 7 | class Get(Request): 8 | 9 | resource = User 10 | uri = 'users/{user}' 11 | 12 | def clean_uri(self): 13 | if not self.user: 14 | return 'user' 15 | 16 | 17 | class Update(Request): 18 | 19 | resource = User 20 | uri = 'user' 21 | body_schema = { 22 | 'schema': ('name', 'email', 'blog', 'company', 'location', 'hireable', 23 | 'bio'), 24 | 'required': (), 25 | } 26 | 27 | def clean_body(self): 28 | if not self.body: 29 | raise ValidationError("'%s' request needs data. You can use " 30 | "'%s' keys" % (self.__class__.__name__, 31 | self.body_schema)) 32 | return self.body 33 | -------------------------------------------------------------------------------- /pygithub3/requests/users/emails.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | import re 5 | 6 | from . import Request, ValidationError 7 | 8 | # Src: http://code.djangoproject.com/svn/django/trunk/django/core/validators.py 9 | email_re = re.compile( 10 | r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 11 | # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5 12 | r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' 13 | r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$)' # domain 14 | r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3) 15 | 16 | 17 | class List(Request): 18 | 19 | uri = 'user/emails' 20 | 21 | 22 | class Add(Request): 23 | 24 | uri = 'user/emails' 25 | 26 | def clean_body(self): 27 | def is_email(email): 28 | return bool(email_re.match(email)) 29 | if not self.body: 30 | raise ValidationError("'%s' request needs emails" 31 | % (self.__class__.__name__)) 32 | 33 | return filter(is_email, self.body) 34 | 35 | 36 | class Delete(Request): 37 | 38 | uri = 'user/emails' 39 | 40 | def clean_body(self): 41 | if not self.body: 42 | raise ValidationError("'%s' request needs emails" 43 | % (self.__class__.__name__)) 44 | return self.body 45 | -------------------------------------------------------------------------------- /pygithub3/requests/users/followers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | from pygithub3.resources.users import User 6 | 7 | 8 | class List(Request): 9 | 10 | resource = User 11 | uri = 'users/{user}/followers' 12 | 13 | def clean_uri(self): 14 | if not self.user: 15 | return 'user/followers' 16 | 17 | 18 | class Listfollowing(Request): 19 | 20 | resource = User 21 | uri = 'users/{user}/following' 22 | 23 | def clean_uri(self): 24 | if not self.user: 25 | return 'user/following' 26 | 27 | 28 | class Isfollowing(Request): 29 | 30 | uri = 'user/following/{user}' 31 | 32 | 33 | class Follow(Request): 34 | 35 | uri = 'user/following/{user}' 36 | 37 | 38 | class Unfollow(Request): 39 | 40 | uri = 'user/following/{user}' 41 | -------------------------------------------------------------------------------- /pygithub3/requests/users/keys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from . import Request 5 | from pygithub3.resources.users import Key 6 | 7 | 8 | class List(Request): 9 | 10 | resource = Key 11 | uri = 'user/key' 12 | 13 | 14 | class Get(Request): 15 | 16 | resource = Key 17 | uri = 'user/keys/{key_id}' 18 | 19 | 20 | class Add(Request): 21 | 22 | resource = Key 23 | uri = 'user/keys' 24 | body_schema = { 25 | 'schema': ('title', 'key'), 26 | 'required': ('title', 'key') 27 | } 28 | 29 | 30 | class Update(Request): 31 | 32 | resource = Key 33 | body_schema = { 34 | 'schema': ('title', 'key'), 35 | 'required': ('title', 'key') 36 | } 37 | uri = 'user/keys/{key_id}' 38 | 39 | 40 | class Delete(Request): 41 | 42 | uri = 'user/keys/{key_id}' 43 | -------------------------------------------------------------------------------- /pygithub3/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /pygithub3/resources/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from pygithub3.core import json 4 | 5 | 6 | class Resource(object): 7 | 8 | _dates = () 9 | _maps = {} 10 | _collection_maps = {} 11 | 12 | def __init__(self, attrs): 13 | self._attrs = attrs 14 | self.__set_attrs() 15 | 16 | def __set_attrs(self): 17 | for attr in self._attrs: 18 | setattr(self, attr, self._attrs[attr]) 19 | 20 | def __str__(self): 21 | return "<%s>" % self.__class__.__name__ 22 | 23 | def __repr__(self): 24 | return self.__str__() 25 | 26 | @classmethod 27 | def loads(self, json_content): 28 | resource_chunk = json.loads(json_content) 29 | if not hasattr(resource_chunk, 'items'): 30 | return [self.__load(raw_resource) 31 | for raw_resource in resource_chunk] 32 | else: 33 | return self.__load(resource_chunk) 34 | 35 | @classmethod 36 | def __load(self, raw_resource): 37 | def self_resource(func): 38 | def wrapper(resource, raw_resource): 39 | if resource == 'self': 40 | resource = self 41 | return func(resource, raw_resource) 42 | return wrapper 43 | 44 | @self_resource 45 | def parse_map(resource, raw_resource): 46 | if hasattr(raw_resource, 'items'): 47 | return resource.__load(raw_resource) 48 | 49 | @self_resource 50 | def parse_collection_map(resource, raw_resources): 51 | # Dict of resources (Ex: Gist file) 52 | if hasattr(raw_resources, 'items'): 53 | dict_map = {} 54 | for key, raw_resource in raw_resources.items(): 55 | dict_map[key] = resource.__load(raw_resource) 56 | return dict_map 57 | # list of resources 58 | elif hasattr(raw_resources, '__iter__'): 59 | return [resource.__load(raw_resource) 60 | for raw_resource in raw_resources] 61 | 62 | new_resource = raw_resource.copy() 63 | new_resource.update(dict([ 64 | (attr, parse_map(resource, raw_resource[attr])) 65 | for attr, resource in self._maps.items() 66 | if attr in raw_resource])) 67 | new_resource.update(dict([ 68 | (attr, parse_collection_map(resource, raw_resource[attr])) 69 | for attr, resource in self._collection_maps.items() 70 | if attr in raw_resource])) 71 | 72 | return self(new_resource) 73 | 74 | 75 | class Raw(Resource): 76 | 77 | @classmethod 78 | def loads(self, json_content): 79 | return json.loads(json_content) 80 | -------------------------------------------------------------------------------- /pygithub3/resources/events.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from pygithub3.resources.base import Resource 4 | from pygithub3.resources import users, repos, orgs 5 | 6 | 7 | class Event(Resource): 8 | 9 | _dates = ('created_at', ) 10 | _maps = {'actor': users.User, 'repo': repos.Repo, 'org': orgs.Org} 11 | 12 | def __str__(self): 13 | return '<(%s)>' % getattr(self, 'type', '') 14 | 15 | 16 | class Repo(Resource): 17 | 18 | _dates = ('created_at', ) 19 | _maps = {'actor': users.User, 'repo': repos.Repo, 'org': orgs.Org} 20 | 21 | def __str__(self): 22 | return '<(%s)>' % getattr(self, 'type', '') 23 | 24 | 25 | class Network(Resource): 26 | 27 | _dates = ('created_at', ) 28 | _maps = {'actor': users.User, 'repo': repos.Repo, 'org': orgs.Org} 29 | 30 | def __str__(self): 31 | return '<(%s)>' % getattr(self, 'type', '') 32 | 33 | 34 | class Org(Resource): 35 | 36 | _dates = ('created_at', ) 37 | _maps = {'actor': users.User, 'repo': repos.Repo, 'org': orgs.Org} 38 | 39 | def __str__(self): 40 | return '<(%s)>' % getattr(self, 'type', '') 41 | 42 | 43 | class User(Resource): 44 | 45 | _dates = ('created_at', ) 46 | _maps = {'actor': users.User, 'repo': repos.Repo, 'org': orgs.Org} 47 | 48 | def __str__(self): 49 | return '<(%s)>' % getattr(self, 'type', '') 50 | -------------------------------------------------------------------------------- /pygithub3/resources/gists.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from .base import Resource 4 | from .users import User 5 | 6 | 7 | class File(Resource): 8 | 9 | def __str__(self): 10 | return '' % getattr(self, 'filename', '') 11 | 12 | 13 | class Fork(Resource): 14 | 15 | _dates = ('created_at', ) 16 | _maps = {'user': User} 17 | 18 | def __str__(self): 19 | return '' 20 | 21 | 22 | class History(Resource): 23 | 24 | _dates = ('committed_at', ) 25 | _maps = {'user': User} 26 | 27 | def __str__(self): 28 | return '' % getattr(self, 'version', '') 29 | 30 | 31 | class Gist(Resource): 32 | 33 | _dates = ('created_at', ) 34 | _maps = {'user': User} 35 | _collection_maps = {'files': File, 'forks': Fork, 'history': History} 36 | 37 | def __str__(self): 38 | return '' % getattr(self, 'description', '') 39 | 40 | 41 | class Comment(Resource): 42 | 43 | _dates = ('created_at', ) 44 | _maps = {'user': User} 45 | 46 | def __str__(self): 47 | return '' % getattr(self, 'user', '') 48 | -------------------------------------------------------------------------------- /pygithub3/resources/git_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from .base import Resource 5 | from .repos import Author, Commit 6 | 7 | 8 | class Blob(Resource): 9 | def __str__(self): 10 | return "" % getattr(self, 'content', '') 11 | 12 | 13 | class Reference(Resource): 14 | def __str__(self): 15 | return '' % getattr(self, 'ref', '') 16 | 17 | 18 | class Tag(Resource): 19 | _maps = {'object': Commit, 20 | 'tagger': Author} # committer? tagger? 21 | 22 | def __str__(self): 23 | return '' % getattr(self, 'tag', '') 24 | 25 | 26 | class Tree(Resource): 27 | def __str__(self): 28 | return '' % getattr(self, 'sha', '') 29 | -------------------------------------------------------------------------------- /pygithub3/resources/issues.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | import re 5 | 6 | from .base import Resource 7 | from .users import User 8 | from .pull_requests import PullRequest 9 | 10 | 11 | class Label(Resource): 12 | 13 | @staticmethod 14 | def is_valid_color(color): 15 | valid_color = re.compile(r'[0-9abcdefABCDEF]{6}') 16 | match = valid_color.match(color) 17 | if match is None: 18 | return False 19 | return match.start() == 0 and match.end() == len(color) 20 | 21 | def __str__(self): 22 | return '