Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ version: 2
sphinx:
configuration: docs/conf.py

# Optionally set the version of Python and requirements required to build your docs
build:
os: ubuntu-22.04
tools:
python: "3.11"

python:
version: 3.7
install:
- requirements: docs_requirements.txt
- requirements: docs_requirements.txt
16 changes: 9 additions & 7 deletions docs/abc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ experimental APIs without issue.
methods that send data to GitHub, there is a *data* argument which
accepts an object which can be serialized to JSON (because
``None`` is a legitimate JSON value, ``""`` is used to represent
no data).
no data). The *extra_headers* argument optionally is ``dict[str, str]``,
and allows passing extra headers to the request specifying extra
options that the GitHub API allows.

The returned value for GitHub requests is the decoded body of the
response according to :func:`gidgethub.sansio.decipher_response`.
Expand Down Expand Up @@ -119,7 +121,7 @@ experimental APIs without issue.
Renamed from ``_sleep()``.


.. py:method:: getitem(url, url_vars={}, *, accept=sansio.accept_format(), jwt=None, oauth_token=None)
.. py:method:: getitem(url, url_vars={}, *, accept=sansio.accept_format(), jwt=None, oauth_token=None, extra_headers=None)
:async:

Get a single item from GitHub.
Expand Down Expand Up @@ -162,7 +164,7 @@ experimental APIs without issue.
on API endpoints like /orgs/{org}/members/{username} where the
HTTP response code is the relevant answer.

.. py:method:: getiter(url, url_vars={}, *, accept=sansio.accept_format(), jwt=None, oauth_token=None, iterable_key="items")
.. py:method:: getiter(url, url_vars={}, *, accept=sansio.accept_format(), jwt=None, oauth_token=None, iterable_key="items", extra_headers=None)
:async:

Get all items from a GitHub API endpoint.
Expand Down Expand Up @@ -203,7 +205,7 @@ experimental APIs without issue.
:meth:`getitem`.


.. py:method:: post(url, url_vars={}, *, data, accept=sansio.accept_format(), jwt=None, oauth_token=None, content_type="application/json")
.. py:method:: post(url, url_vars={}, *, data, accept=sansio.accept_format(), jwt=None, oauth_token=None, content_type="application/json", extra_headers=None)
:async:

Send a ``POST`` request to GitHub.
Expand Down Expand Up @@ -237,7 +239,7 @@ experimental APIs without issue.
Added *jwt* and *oauth_token*.


.. py:method:: patch(url, url_vars={}, *, data, accept=sansio.accept_format(), jwt=None, oauth_token=None)
.. py:method:: patch(url, url_vars={}, *, data, accept=sansio.accept_format(), jwt=None, oauth_token=None, extra_headers=None)
:async:

Send a ``PATCH`` request to GitHub.
Expand All @@ -257,7 +259,7 @@ experimental APIs without issue.
Added *jwt* and *oauth_token*.


.. py:method:: put(url, url_vars={}, *, data=b"", accept=sansio.accept_format(), jwt=None, oauth_token=None)
.. py:method:: put(url, url_vars={}, *, data=b"", accept=sansio.accept_format(), jwt=None, oauth_token=None, extra_headers=None)
:async:

Send a ``PUT`` request to GitHub.
Expand All @@ -281,7 +283,7 @@ experimental APIs without issue.
Added *jwt* and *oauth_token*.


.. py:method:: delete(url, url_vars={}, *, data=b"", accept=sansio.accept_format(), jwt=None, oauth_token=None)
.. py:method:: delete(url, url_vars={}, *, data=b"", accept=sansio.accept_format(), jwt=None, oauth_token=None, extra_headers=None)
:async:

Send a ``DELETE`` request to GitHub.
Expand Down
6 changes: 6 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ Changelog
5.3.0
-----

- Add extra_headers option to HTTP methods in GitHubAPI
(`Issue #193 <https://github.com/brettcannon/gidgethub/pull/193>_`)

- Add support passing ``extra_headers`` when making requests
(`PR #192 <https://github.com/brettcannon/gidgethub/pull/192>_`)

- Add a getstatus() method for APIs that do not return content.
(`PR #194 <https://github.com/brettcannon/gidgethub/pull/194>_`)

Expand Down
56 changes: 51 additions & 5 deletions gidgethub/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ async def _make_request(
jwt: Opt[str] = None,
oauth_token: Opt[str] = None,
content_type: str = JSON_CONTENT_TYPE,
extra_headers: Optional[Dict[str, str]] = None,
) -> Tuple[bytes, Opt[str], int]:
"""Construct and make an HTTP request."""
if oauth_token is not None and jwt is not None:
Expand All @@ -84,6 +85,8 @@ async def _make_request(
request_headers = sansio.create_headers(
self.requester, accept=accept, oauth_token=self.oauth_token
)
if extra_headers is not None:
request_headers.update(extra_headers)
cached = cacheable = False
# Can't use None as a "no body" sentinel as it's a legitimate JSON type.
if data == b"":
Expand Down Expand Up @@ -131,11 +134,19 @@ async def getitem(
accept: str = sansio.accept_format(),
jwt: Opt[str] = None,
oauth_token: Opt[str] = None,
extra_headers: Optional[Dict[str, str]] = None,
) -> Any:
"""Send a GET request for a single item to the specified endpoint."""

data, _, _ = await self._make_request(
"GET", url, url_vars, b"", accept, jwt=jwt, oauth_token=oauth_token
"GET",
url,
url_vars,
b"",
accept,
jwt=jwt,
oauth_token=oauth_token,
extra_headers=extra_headers,
)
return data

Expand Down Expand Up @@ -167,11 +178,19 @@ async def getiter(
accept: str = sansio.accept_format(),
jwt: Opt[str] = None,
oauth_token: Opt[str] = None,
extra_headers: Optional[Dict[str, str]] = None,
iterable_key: Opt[str] = ITERABLE_KEY,
) -> AsyncGenerator[Any, None]:
"""Return an async iterable for all the items at a specified endpoint."""
data, more, _ = await self._make_request(
"GET", url, url_vars, b"", accept, jwt=jwt, oauth_token=oauth_token
"GET",
url,
url_vars,
b"",
accept,
jwt=jwt,
oauth_token=oauth_token,
extra_headers=extra_headers,
)

if isinstance(data, dict) and iterable_key in data:
Expand All @@ -187,6 +206,7 @@ async def getiter(
jwt=jwt,
oauth_token=oauth_token,
iterable_key=iterable_key,
extra_headers=extra_headers,
):
yield item # pragma: nocover

Expand All @@ -199,6 +219,7 @@ async def post(
accept: str = sansio.accept_format(),
jwt: Opt[str] = None,
oauth_token: Opt[str] = None,
extra_headers: Optional[Dict[str, str]] = None,
content_type: str = JSON_CONTENT_TYPE,
) -> Any:
data, _, _ = await self._make_request(
Expand All @@ -210,6 +231,7 @@ async def post(
jwt=jwt,
oauth_token=oauth_token,
content_type=content_type,
extra_headers=extra_headers,
)
return data

Expand All @@ -222,9 +244,17 @@ async def patch(
accept: str = sansio.accept_format(),
jwt: Opt[str] = None,
oauth_token: Opt[str] = None,
extra_headers: Optional[Dict[str, str]] = None,
) -> Any:
data, _, _ = await self._make_request(
"PATCH", url, url_vars, data, accept, jwt=jwt, oauth_token=oauth_token
"PATCH",
url,
url_vars,
data,
accept,
jwt=jwt,
oauth_token=oauth_token,
extra_headers=extra_headers,
)
return data

Expand All @@ -237,9 +267,17 @@ async def put(
accept: str = sansio.accept_format(),
jwt: Opt[str] = None,
oauth_token: Opt[str] = None,
extra_headers: Optional[Dict[str, str]] = None,
) -> Any:
data, _, _ = await self._make_request(
"PUT", url, url_vars, data, accept, jwt=jwt, oauth_token=oauth_token
"PUT",
url,
url_vars,
data,
accept,
jwt=jwt,
oauth_token=oauth_token,
extra_headers=extra_headers,
)
return data

Expand All @@ -252,9 +290,17 @@ async def delete(
accept: str = sansio.accept_format(),
jwt: Opt[str] = None,
oauth_token: Opt[str] = None,
extra_headers: Optional[Dict[str, str]] = None,
) -> None:
await self._make_request(
"DELETE", url, url_vars, data, accept, jwt=jwt, oauth_token=oauth_token
"DELETE",
url,
url_vars,
data,
accept,
jwt=jwt,
oauth_token=oauth_token,
extra_headers=extra_headers,
)

async def graphql(
Expand Down
39 changes: 39 additions & 0 deletions tests/test_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,31 @@ async def test_getiter(self):
assert data[2] == 1
assert data[3] == 2

@pytest.mark.asyncio
async def test_getiter_with_extra_headers(self):
"""Test that getiter() sends extra headers correctly."""
original_data = [1, 2]
next_url = "https://api.github.com/fake{/extra}?page=2"
headers = MockGitHubAPI.DEFAULT_HEADERS.copy()
headers["content-type"] = "application/json; charset=UTF-8"
headers["link"] = f'<{next_url}>; rel="next"'
gh = MockGitHubAPI(
headers=headers, body=json.dumps(original_data).encode("utf8")
)
extra_headers = {"X-Custom-Header": "custom_value"}
data = []
async for item in gh.getiter(
"/fake", {"extra": "stuff"}, extra_headers=extra_headers
):
data.append(item)
assert gh.method == "GET"
assert gh.headers["X-Custom-Header"] == "custom_value"
assert len(data) == 4
assert data[0] == 1
assert data[1] == 2
assert data[2] == 1
assert data[3] == 2

@pytest.mark.asyncio
async def test_with_passed_jwt(self):
original_data = [1, 2]
Expand Down Expand Up @@ -401,6 +426,20 @@ async def test_checks_api(self):
assert data[2] == 1
assert data[3] == 2

@pytest.mark.asyncio
async def test_extra_headers(self):
"""Test that extra headers are passed correctly."""
accept = sansio.accept_format()
extra_headers = {"X-Custom-Header": "custom_value"}
gh = MockGitHubAPI()
await gh._make_request(
"GET", "/rate_limit", {}, "", accept, extra_headers=extra_headers
)
assert gh.headers["user-agent"] == "test_abc"
assert gh.headers["accept"] == accept
assert "X-Custom-Header" in gh.headers
assert gh.headers["X-Custom-Header"] == "custom_value"


class TestGitHubAPIPost:
@pytest.mark.asyncio
Expand Down