From 0d3c391646d0e1855860d3b3b13b8bb64fe342ca Mon Sep 17 00:00:00 2001 From: Olivier Mehani Date: Fri, 24 Jul 2026 18:56:19 +1000 Subject: [PATCH] feat(ApiClient): provide convenience get_token() method --- README.md | 10 ++++++++++ src/simple_github/client.py | 10 ++++++++-- test/test_simple_github.py | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8f568e6..e1abd53 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,10 @@ async with AppClient(app_id, privkey, owner=owner, repositories=["simple-github" resp = await session.get("/octocat") ``` +The `AppClient` can be used in both sync and async contexts. If a running async +loop is found, an object with `await`able method will be returned, otherwise a +normal synchronous object with the same methods will be provided. + ### Authenticate as a Github App You can also authenticate as the app itself. This is mainly only useful for @@ -126,6 +130,12 @@ easily be called from synchronous code with return asyncio.run(inst_auth.get_token()) ``` +For convenience, the `AppClient` provides a `get_token()` methods hiding those details. + +```python +token = await AppClient(app_id, privkey, owner=owner, repositories=["simple-github"]).get_token() +``` + The returned token (`ghs_XXX`) can be used directly to authenticate git+http operations as the `git` user. diff --git a/src/simple_github/client.py b/src/simple_github/client.py index f49edd8..16650e7 100644 --- a/src/simple_github/client.py +++ b/src/simple_github/client.py @@ -94,6 +94,9 @@ def close(self) -> None: if self._gql_client: self._gql_client.close_sync() + def get_token(self) -> str: + return asyncio.run(self.auth.get_token()) + def _get_gql_session(self) -> SyncClientSession: """Return an AIOHTTP session. @@ -103,7 +106,7 @@ def _get_gql_session(self) -> SyncClientSession: Returns: aiohttp.ClientSession: An AIOHTTP session object. """ - token = asyncio.run(self.auth.get_token()) + token = self.get_token() if token == self._prev_token: assert isinstance(self._gql_session, SyncClientSession) @@ -250,6 +253,9 @@ async def close(self) -> None: if self._gql_client: await self._gql_client.close_async() + async def get_token(self) -> str: + return await self.auth.get_token() + async def _get_gql_session(self) -> ReconnectingAsyncClientSession: """Return an AIOHTTP session. @@ -259,7 +265,7 @@ async def _get_gql_session(self) -> ReconnectingAsyncClientSession: Returns: aiohttp.ClientSession: An AIOHTTP session object. """ - token = await self.auth.get_token() + token = await self.get_token() if token == self._prev_token: assert isinstance(self._gql_session, ReconnectingAsyncClientSession) return self._gql_session diff --git a/test/test_simple_github.py b/test/test_simple_github.py index 925aae8..713e814 100644 --- a/test/test_simple_github.py +++ b/test/test_simple_github.py @@ -65,6 +65,25 @@ async def test_app_installation_client(aioresponses, privkey): assert result == {"foo": "bar"} +@pytest.mark.asyncio +async def test_app_installation_client_get_token(aioresponses, privkey): + owner = "owner" + inst_id = 1 + + aioresponses.get( + f"{GITHUB_API_ENDPOINT}/app/installations", + status=200, + payload=[{"id": inst_id, "account": {"login": owner}}], + ) + aioresponses.post( + f"{GITHUB_API_ENDPOINT}/app/installations/{inst_id}/access_tokens", + status=200, + payload={"token": "789"}, + ) + + assert await AppClient(id=123, privkey=privkey, owner=owner).get_token() == "789" + + @pytest.mark.parametrize( "env,expected_client", (