{ "info": { "author": "Jonathan Paugh", "author_email": "jpaugh@gmx.us", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 3", "Topic :: Utilities" ], "description": "# The Agnostic GitHub API\n\n> It doesn't know, and you don't care!\n\n`agithub` is a REST API client with transparent syntax which facilitates\nrapid prototyping — on *any* REST API!\n\nOriginally tailored to the GitHub REST API, AGitHub has grown up to\nsupport many other REST APIs:\n\n* DigitalOcean\n* Facebook\n* GitHub\n* OpenWeatherMap\n* SalesForce\n\nAdditionally, you can add *full support* for another REST API with very\nlittle new code! To see how, check out the [Facebook client], which has\nabout 30 lines of code.\n\nThis works because AGithub knows everything it needs to about protocol\n(REST, HTTP, TCP), but assumes nothing about your upstream API.\n\n[Facebook client]: agithub/Facebook.py\n\n# Use\n\nThe most striking quality of AGitHub is how closely its syntax emulates\nHTTP. In fact, you might find it even more convenient than HTTP, and\nalmost as general (as far as REST APIs go, anyway). The examples below\ntend to use the GitHub API as a reference point, but it is no less easy to\nuse `agithub` with, say, the Facebook Graph.\n\n## Create a client\n\n```python\nfrom agithub.GitHub import GitHub\nclient = GitHub()\n```\n\n## GET\n\nHere's how to do a `GET` request, with properly-encoded url parameters:\n\n```python\nclient.issues.get(filter='subscribed')\n```\n\nThat is equivalent to the following:\n\n```http\nGET /issues/?filter=subscribed\n```\n\n## POST\n\nHere's how to send a request body along with your request:\n\n```python\nsome_object = {'foo': 'bar'}\nclient.video.upload.post(body=some_object, tags=\"social devcon\")\n```\n\nThis will send the following request, with `some_object` serialized as\nthe request body:*\n\n```http\nPOST /video/upload?tags=social+devcon\n\n{\"foo\": \"bar\"}\n```\n\nThe `body` parameter is reserved and is used to define the request body to be\nPOSTed. `tags` is an example query parameter, showing that you can pass both\nan object to send as the request body as well as query parameters.\n\n* For now, the request body is limited to JSON data; but\nwe plan to add support for other types as well\n\n## Parameters\n\n### `headers`\n\nPass custom http headers in your ruquest with the reserved parameter `headers`.\n\n```python\nfrom agithub.GitHub import GitHub\ng = GitHub()\nheaders = {'Accept': 'application/vnd.github.symmetra-preview+json'}\nstatus, data = g.search.labels.get(headers=headers, repository_id=401025, q='\u00af\\_(\u30c4)_/\u00af')\nprint(data['items'][0])\n```\n\n```text\n{u'default': False, u'name': u'\\xaf\\\\_(\\u30c4)_/\\xaf', u'url': u'https://api.github.com/repos/github/hub/labels/%C2%AF%5C_(%E3%83%84)_/%C2%AF', u'color': u'008672', u'node_id': u'MDU6TGFiZWwxMTcwNjYzNTM=', u'score': 43.937515, u'id': 117066353, u'description': u''}\n\n```\n\n### `body`\n\nIf you're using `POST`, `PUT`, or `PATCH` (`post()`, `put()`, or `patch()`), \nthen you should include the body as the `body=` argument. The body is \nserialized to JSON before sending it out on the wire.\n\n```python\nfrom agithub.GitHub import GitHub\ng = GitHub()\n# This Content-Type header is only required in this example due to a GitHub \n# requirement for this specific markdown.raw API endpoint\nheaders={'Content-Type': 'text/plain'} \nbody = '# This should be my header'\nstatus, data = g.markdown.raw.post(body=body, headers=headers)\nprint(data)\n```\n\n```text\n

\nThis should be my header

\n\n```\n\n\n\n## Example App\n\n1. First, instantiate a `GitHub` object.\n\n ```python\n from agithub.GitHub import GitHub\n g = GitHub()\n ```\n\n2. When you make a request, the status and response body are passed back\n as a tuple.\n\n ```python\n status, data = g.users.octocat.get()\n print(data['name'])\n print(status)\n ```\n\n ```text\n The Octocat\n 200\n ```\n\n3. If you forget the request method, `agithub` will complain that you\n haven't provided enough information to complete the request.\n\n ```python\n g.users\n ```\n\n ```text\n : /users\n ```\n\n4. Sometimes, it is inconvenient (or impossible) to refer to a URL as a\n chain of attributes, so indexing syntax is provided as well. It\n behaves exactly the same. In these examples we use indexing syntax because \n you can't have a python function name\n\n * starting with a digit : `1`\n * containing a dash (`-`) character : `Spoon-Knife`\n\n ```python\n g.repos.github.hub.issues[1].get()\n g.repos.octocat['Spoon-Knife'].branches.get()\n ```\n\n ```text\n (200, { 'id': '#blah', ... })\n (200, [ list, of, branches ])\n\n ```\n\n5. You can also pass query parameter to the API as function parameters to the\n method function (e.g. `get`).\n\n ```python\n status, data = g.repos.octocat['Spoon-Knife'].issues.get(\n state='all', creator='octocat')\n print(data[0].keys())\n print(status)\n ```\n\n ```text\n [u'labels', u'number', \u2026 , u'assignees']\n 200\n ```\n\n Notice the syntax here:\n `..()`\n\n * `API-object` : `g`\n * `URL-path` : `repos.octocat['Spoon-Knife'].issues`\n * `request-method` : `get`\n * `query-parameters` : `state='all', creator='octocat'`\n\n6. As a weird quirk of the implementation, you may build a partial call\n to the upstream API, and use it later.\n\n ```python\n def following(self, user):\n return self.user.following[user].get\n\n myCall = following(g, 'octocat')\n if 204 == myCall()[0]:\n print 'You are following octocat'\n ```\n\n ```text\n You are following octocat\n ```\n\n You may find this useful — or not.\n\n7. Finally, `agithub` knows nothing at all about the GitHub API, and it\n won't second-guess you.\n\n ```python\n g.funny.I.donna.remember.that.one.head()\n ```\n\n ```text\n (404, {'message': 'Not Found'})\n ```\n\n The error message you get is directly from GitHub's API. This gives\n you all of the information you need to survey the situation.\n\n7. If you need more information, the response headers of the previous\n request are available via the `getheaders()` method.\n\n ```python\n g.getheaders()\n ```\n\n ```text\n [('status', '404 Not Found'),\n ('x-ratelimit-remaining', '54'),\n \u2026\n ('server', 'GitHub.com')]\n ```\n\n Note that the headers are standardized to all lower case. So though, in this\n example, GitHub returns a header of `X-RateLimit-Remaining` the header is\n returned from `getheaders` as `x-ratelimit-remaining`\n\n## Error handling\nErrors are handled in the most transparent way possible: they are passed\non to you for further scrutiny. There are two kinds of errors that can\ncrop up:\n\n1. Networking Exceptions (from the `http` library). Catch these with\n `try .. catch` blocks, as you otherwise would.\n\n2. GitHub API errors. These mean you're doing something wrong with the\n API, and they are always evident in the response's status. The API\n considerately returns a helpful error message in the JSON body.\n\n## Specific REST APIs\n\n`agithub` includes a handful of implementations for specific REST APIs. The\nexample above uses the GitHub API but only for demonstration purposes. It\ndoesn't include any GitHub specific functionality (for example, authentication).\n\nHere is a summary of additional functionality available for each distinct REST\nAPI with support included in `agithub`. Keep in mind, `agithub` is designed\nto be extended to any REST API and these are just an initial collection of APIs.\n\n### GitHub : [`agithub/GitHub.py`](agithub/GitHub.py)\n\n#### GitHub Authentication\n\nTo initiate an authenticated `GitHub` object, pass it your username and password\nor a [token](https://github.com/settings/tokens).\n\n```python\nfrom agithub.GitHub import GitHub\ng = GitHub('user', 'pass')\n```\n\n```python\nfrom agithub.GitHub import GitHub\ng = GitHub(token='token')\n```\n\n#### GitHub Pagination\n\nWhen calling the GitHub API with a query that returns many results, GitHub will\n[paginate](https://developer.github.com/v3/#pagination) the response, requiring\nyou to request each page of results with separate API calls. If you'd like to\nautomatically fetch all pages, you can enable pagination in the `GitHub` object\nby setting `paginate` to `True`.\n\n```python\nfrom agithub.GitHub import GitHub\ng = GitHub(paginate=True)\nstatus, data = g.repos.octocat['Spoon-Knife'].issues.get()\n\nstatus, data = g.users.octocat.repos.get(per_page=1)\nprint(len(data))\n```\n\n```text\n8\n```\n\n(added in v2.2.0)\n\n#### GitHub Rate Limiting\n\nBy default, if GitHub returns a response indicating that a request was refused\ndue to [rate limiting](https://developer.github.com/v3/#rate-limiting), agithub\nwill wait until the point in time when the rate limit is lifted and attempt\nthe call again.\n\nIf you'd like to disable this behavior and instead just return the error\nresponse from GitHub set `sleep_on_ratelimit` to `False`.\n\n```python\nfrom agithub.GitHub import GitHub\ng = GitHub(sleep_on_ratelimit=False)\nstatus, data = g.repos.octocat['Spoon-Knife'].issues.get()\nprint(status)\nprint(data['message'])\n```\n\n```text\n403\nAPI rate limit exceeded for 203.0.113.2. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)\n```\n\n(added in v2.2.0)\n\n#### GitHub Logging\n\nTo see log messages related to GitHub specific features like pagination and\nrate limiting, you can use a root logger from the Python logging module.\n\n```python\nimport logging\nlogging.basicConfig()\nlogger = logging.getLogger() # The root logger\nlogger.setLevel(logging.DEBUG)\nfrom agithub.GitHub import GitHub\ng = GitHub(paginate=True)\nstatus, data = g.repos.octocat['Spoon-Knife'].issues.get()\n```\n\n```text\nDEBUG:agithub.GitHub:No GitHub ratelimit remaining. Sleeping for 676 seconds until 14:22:43 before trying API call again.\nDEBUG:agithub.GitHub:Fetching an additional paginated GitHub response page at https://api.github.com/repositories/1300192/issues?page=2\nDEBUG:agithub.GitHub:Fetching an additional paginated GitHub response page at https://api.github.com/repositories/1300192/issues?page=3\n\u2026\n```\n\n## Semantics\n\nHere's how `agithub` works, under the hood:\n\n1. It translates a sequence of attribute look-ups into a URL; The\n Python method you call at the end of the chain determines the\n HTTP method to use for the request.\n2. The Python method also receives `name=value` arguments, which it\n interprets as follows:\n * `headers=`\n * You can include custom headers as a dictionary supplied to the\n `headers=` argument. Some headers are provided by default (such as\n User-Agent). If these occur in the supplied dictionary, the default\n value will be overridden.\n\n ```python\n headers = {'Accept': 'application/vnd.github.loki-preview+json'}\n ```\n * `body=`\n * If you're using `POST`, `PUT`, or `PATCH` (`post()`, `put()`, and\n `patch()`), then you should include the body as the `body=` argument.\n The body is serialized to JSON before sending it out on the wire.\n * GET Parameters\n * Any other arguments to the Python method become GET parameters, and are\n tacked onto the end of the URL. They are, of course, url-encoded for\n you.\n3. When the response is received, `agithub` looks at its content\n type to determine how to handle it, possibly decoding it from the\n given char-set to Python's Unicode representation, then converting to\n an appropriate form, then passed to you along with the response\n status code. (A JSON object is de-serialized into a Python object.)\n\n## Extensibility\n`agithub` has been written in an extensible way. You can easily:\n\n* Add new HTTP methods by extending the `Client` class with\n new Python methods of the same name (and adding them to the\n [`http_methods` list][1]).\n\n* Add new default headers to the [`_default_headers` dictionary][2].\n Just make sure that the header names are lower case.\n\n* Add a new media-type (a.k.a. content-type a.k.a mime-type) by\n inserting a new method into the [`ResponseBody` class][3], replacing\n `'-'` and `'/'` with `'_'` in the method name. That method will then be\n responsible for converting the response body to a usable\n form — and for calling `decode_body` to do char-set\n conversion, if required. For example to create a handler for the content-type\n `application/xml` you'd extend `ResponseBody` and create a new method like this\n\n ```python\n import xml.etree.ElementTree as ET\n\n class CustomResponseBody(ResponseBody):\n def __init__(self):\n super(ChildB, self).__init__()\n\n def application_xml(self):\n # Handles Content-Type of \"application/xml\"\n return ET.fromstring(self.body)\n ```\n\nAnd if all else fails, you can strap in, and take 15 minutes to read and\nbecome an expert on the code. From there, anything's possible.\n\n[1]: https://github.com/mozilla/agithub/blob/b47661df9e62224a69216a2f11dbe574990349d2/agithub/base.py#L103-L110\n[2]: https://github.com/mozilla/agithub/blob/b47661df9e62224a69216a2f11dbe574990349d2/agithub/base.py#L22-L28\n[3]: https://github.com/mozilla/agithub/blob/b47661df9e62224a69216a2f11dbe574990349d2/agithub/base.py#L309-L332\n\n## License\nCopyright 2012–2016 Jonathan Paugh and contributors\nSee [COPYING](COPYING) for license details\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/mozilla/agithub", "keywords": "api,REST,GitHub,Facebook,SalesForce", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "agithub", "package_url": "https://pypi.org/project/agithub/", "platform": "", "project_url": "https://pypi.org/project/agithub/", "project_urls": { "Homepage": "https://github.com/mozilla/agithub" }, "release_url": "https://pypi.org/project/agithub/2.2.1/", "requires_dist": [ "setuptools-scm", "pytest ; extra == 'test'" ], "requires_python": "", "summary": "A lightweight, transparent syntax for REST clients", "version": "2.2.1" }, "last_serial": 5942085, "releases": { "1.3": [ { "comment_text": "", "digests": { "md5": "c7305c3737e2bf50bbadc5acc61b1b17", "sha256": "a29e11c4c92a68d4063663ec086b2f5ff97d713aa53748047e086c0a45429d49" }, "downloads": -1, "filename": "agithub-1.3.tar.gz", "has_sig": false, "md5_digest": "c7305c3737e2bf50bbadc5acc61b1b17", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4397, "upload_time": "2016-01-12T17:40:47", "url": "https://files.pythonhosted.org/packages/60/91/738a7b55ef2f2bd46464880eb21dc8d5fdf89aec8998fdd0caa2befb7fca/agithub-1.3.tar.gz" } ], "2.1": [ { "comment_text": "", "digests": { "md5": "9c4497866c44203759abfc4a6938c69d", "sha256": "92b736276efc232c78e4f1705458a5bd82397d3035af31dba13141129fddd413" }, "downloads": -1, "filename": "agithub-2.1.tar.gz", "has_sig": false, "md5_digest": "9c4497866c44203759abfc4a6938c69d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8603, "upload_time": "2016-06-27T15:18:50", "url": "https://files.pythonhosted.org/packages/e0/e8/784ce6010abebd0f57983ab620707139b8125fb8ce4209c75849c2a0b69a/agithub-2.1.tar.gz" } ], "2.2.0": [ { "comment_text": "", "digests": { "md5": "b991470cd1ecf0c10b35564304d680a8", "sha256": "8eb75b6428a19b62028af15cab5b1a2eae2ae9fa4dba67ba793aa87fa58b0939" }, "downloads": -1, "filename": "agithub-2.2.0-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "b991470cd1ecf0c10b35564304d680a8", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14812, "upload_time": "2019-01-28T17:51:37", "url": "https://files.pythonhosted.org/packages/a4/79/e5cb3249b0321122857db6096459eb41eb3f523422e99c963bc5b9548264/agithub-2.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "95f228bae479c33c0e584bfa17c97e37", "sha256": "067fd3a980a7d5519302752828798eb36ff7e3fd3c47d88fc3b102c730a1ac60" }, "downloads": -1, "filename": "agithub-2.2.0.tar.gz", "has_sig": true, "md5_digest": "95f228bae479c33c0e584bfa17c97e37", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14842, "upload_time": "2019-01-28T17:51:39", "url": "https://files.pythonhosted.org/packages/28/a4/e49b47963884964df61cebfd8dc0374e1dea0da713c0c0dc6b8b16da433c/agithub-2.2.0.tar.gz" } ], "2.2.1": [ { "comment_text": "", "digests": { "md5": "6bd1b27cbe20d0b7c183fe13cb725ab0", "sha256": "b5c4d761f6c71e2e5593a853cca1c06edb3a966856f776a0575e3e7544f62e65" }, "downloads": -1, "filename": "agithub-2.2.1-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "6bd1b27cbe20d0b7c183fe13cb725ab0", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 20883, "upload_time": "2019-10-08T00:12:50", "url": "https://files.pythonhosted.org/packages/f2/ec/6dc58ba37bc5a33788af83551908ba4c626d0865af5edbdc970b9d793680/agithub-2.2.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ed36dbf57c0e91bdfcddfa7b5532e32b", "sha256": "e687da347388344c79659b541b55eecd528da4a2ba36065b3c648107b30571fb" }, "downloads": -1, "filename": "agithub-2.2.1.tar.gz", "has_sig": true, "md5_digest": "ed36dbf57c0e91bdfcddfa7b5532e32b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23214, "upload_time": "2019-10-08T00:12:52", "url": "https://files.pythonhosted.org/packages/8b/f2/eedd0d4279292203eee5eb7a6023d4e23ffcdd91f94deb78eee39f2e6689/agithub-2.2.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "6bd1b27cbe20d0b7c183fe13cb725ab0", "sha256": "b5c4d761f6c71e2e5593a853cca1c06edb3a966856f776a0575e3e7544f62e65" }, "downloads": -1, "filename": "agithub-2.2.1-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "6bd1b27cbe20d0b7c183fe13cb725ab0", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 20883, "upload_time": "2019-10-08T00:12:50", "url": "https://files.pythonhosted.org/packages/f2/ec/6dc58ba37bc5a33788af83551908ba4c626d0865af5edbdc970b9d793680/agithub-2.2.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ed36dbf57c0e91bdfcddfa7b5532e32b", "sha256": "e687da347388344c79659b541b55eecd528da4a2ba36065b3c648107b30571fb" }, "downloads": -1, "filename": "agithub-2.2.1.tar.gz", "has_sig": true, "md5_digest": "ed36dbf57c0e91bdfcddfa7b5532e32b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23214, "upload_time": "2019-10-08T00:12:52", "url": "https://files.pythonhosted.org/packages/8b/f2/eedd0d4279292203eee5eb7a6023d4e23ffcdd91f94deb78eee39f2e6689/agithub-2.2.1.tar.gz" } ] }