gitcode-api 1.1.1__py3-none-any.whl → 1.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@ payload cleanup, and response parsing for both sync and async clients.
5
5
  """
6
6
 
7
7
  import os
8
- from typing import Any, Dict, Optional, Tuple, Union
8
+ from typing import Any, Callable, Dict, Optional, Tuple, Union
9
9
  from urllib.parse import quote
10
10
 
11
11
  import httpx
@@ -30,6 +30,7 @@ class BaseGitCodeClient:
30
30
  :param repo: Default repository name for repository-scoped calls.
31
31
  :param base_url: Base URL for the GitCode REST API.
32
32
  :param timeout: Request timeout in seconds.
33
+ :param decrypt: Optional decryption function for encrypted access token.
33
34
  """
34
35
 
35
36
  def __init__(
@@ -40,20 +41,23 @@ class BaseGitCodeClient:
40
41
  repo: Optional[str] = None,
41
42
  base_url: str = DEFAULT_BASE_URL,
42
43
  timeout: Optional[float] = None,
44
+ decrypt: Optional[Callable] = None,
43
45
  ) -> None:
44
46
  """Store client configuration and resolve authentication."""
45
- self.api_key = self._resolve_api_key(api_key)
47
+ self.api_key = self._resolve_api_key(api_key, decrypt)
46
48
  self.owner = owner
47
49
  self.repo = repo
48
50
  self.base_url = base_url.rstrip("/")
49
51
  self.timeout = timeout if timeout is not None else DEFAULT_TIMEOUT
50
52
 
51
- def _resolve_api_key(self, api_key: Optional[str]) -> str:
53
+ def _resolve_api_key(self, api_key: Optional[str], decrypt: Optional[Callable] = None) -> str:
52
54
  """Resolve the access token from an argument or environment variable."""
53
55
  token = api_key or os.getenv(DEFAULT_TOKEN_ENV)
56
+ if callable(decrypt):
57
+ token = decrypt(token)
54
58
  if not token:
55
59
  raise GitCodeConfigurationError("No API key provided. Pass api_key=... or set GITCODE_ACCESS_TOKEN.")
56
- return token
60
+ return str(token)
57
61
 
58
62
  def _resolve_repo_context(
59
63
  self,
@@ -187,6 +191,7 @@ class SyncAPIClient(BaseGitCodeClient):
187
191
  :param base_url: Base URL for the GitCode REST API.
188
192
  :param timeout: Request timeout in seconds.
189
193
  :param http_client: Optional pre-configured ``httpx.Client`` instance.
194
+ :param decrypt: Optional decryption function for encrypted access token.
190
195
  """
191
196
 
192
197
  def __init__(
@@ -198,9 +203,10 @@ class SyncAPIClient(BaseGitCodeClient):
198
203
  base_url: str = DEFAULT_BASE_URL,
199
204
  timeout: Optional[float] = None,
200
205
  http_client: Optional[httpx.Client] = None,
206
+ decrypt: Optional[Callable] = None,
201
207
  ) -> None:
202
208
  """Create or reuse an ``httpx.Client`` for synchronous requests."""
203
- super().__init__(api_key=api_key, owner=owner, repo=repo, base_url=base_url, timeout=timeout)
209
+ super().__init__(api_key=api_key, owner=owner, repo=repo, base_url=base_url, timeout=timeout, decrypt=decrypt)
204
210
  self._owns_client = http_client is None
205
211
  self._client = http_client or httpx.Client(timeout=self.timeout)
206
212
 
@@ -238,9 +244,8 @@ class SyncAPIClient(BaseGitCodeClient):
238
244
  return self._parse_response(response, raw=raw)
239
245
 
240
246
  def close(self) -> None:
241
- """Close the underlying HTTP client if this instance created it."""
242
- if self._owns_client:
243
- self._client.close()
247
+ """Close the underlying HTTP client."""
248
+ self._client.close()
244
249
 
245
250
  def __enter__(self) -> "SyncAPIClient":
246
251
  """Enter a context manager and return the client instance."""
@@ -260,6 +265,7 @@ class AsyncAPIClient(BaseGitCodeClient):
260
265
  :param base_url: Base URL for the GitCode REST API.
261
266
  :param timeout: Request timeout in seconds.
262
267
  :param http_client: Optional pre-configured ``httpx.AsyncClient`` instance.
268
+ :param decrypt: Optional decryption function for encrypted access token.
263
269
  """
264
270
 
265
271
  def __init__(
@@ -271,9 +277,10 @@ class AsyncAPIClient(BaseGitCodeClient):
271
277
  base_url: str = DEFAULT_BASE_URL,
272
278
  timeout: Optional[float] = None,
273
279
  http_client: Optional[httpx.AsyncClient] = None,
280
+ decrypt: Optional[Callable] = None,
274
281
  ) -> None:
275
282
  """Create or reuse an ``httpx.AsyncClient`` for asynchronous requests."""
276
- super().__init__(api_key=api_key, owner=owner, repo=repo, base_url=base_url, timeout=timeout)
283
+ super().__init__(api_key=api_key, owner=owner, repo=repo, base_url=base_url, timeout=timeout, decrypt=decrypt)
277
284
  self._owns_client = http_client is None
278
285
  self._client = http_client or httpx.AsyncClient(timeout=self.timeout)
279
286
 
@@ -311,9 +318,8 @@ class AsyncAPIClient(BaseGitCodeClient):
311
318
  return self._parse_response(response, raw=raw)
312
319
 
313
320
  async def close(self) -> None:
314
- """Close the underlying async HTTP client if this instance created it."""
315
- if self._owns_client:
316
- await self._client.aclose()
321
+ """Close the underlying async HTTP client."""
322
+ await self._client.aclose()
317
323
 
318
324
  async def __aenter__(self) -> "AsyncAPIClient":
319
325
  """Enter an async context manager and return the client instance."""
gitcode_api/_client.py CHANGED
@@ -4,7 +4,7 @@ These client classes expose grouped resource helpers that mirror the
4
4
  published GitCode REST API documentation.
5
5
  """
6
6
 
7
- from typing import Optional
7
+ from typing import Callable, Optional
8
8
 
9
9
  import httpx
10
10
 
@@ -54,6 +54,7 @@ class GitCode(SyncAPIClient):
54
54
  :param base_url: Base URL for the GitCode REST API.
55
55
  :param timeout: Request timeout in seconds.
56
56
  :param http_client: Optional pre-configured ``httpx.Client`` instance.
57
+ :param decrypt: Optional decryption function for encrypted access token.
57
58
  """
58
59
 
59
60
  repos: ReposResource
@@ -113,6 +114,7 @@ class GitCode(SyncAPIClient):
113
114
  base_url: str = DEFAULT_BASE_URL,
114
115
  timeout: Optional[float] = None,
115
116
  http_client: Optional[httpx.Client] = None,
117
+ decrypt: Optional[Callable] = None,
116
118
  ) -> None:
117
119
  """Create a synchronous client and attach resource groups."""
118
120
  super().__init__(
@@ -122,6 +124,7 @@ class GitCode(SyncAPIClient):
122
124
  base_url=base_url,
123
125
  timeout=timeout,
124
126
  http_client=http_client,
127
+ decrypt=decrypt,
125
128
  )
126
129
  self.repos = ReposResource(self)
127
130
  self.contents = RepoContentsResource(self)
@@ -153,6 +156,7 @@ class AsyncGitCode(AsyncAPIClient):
153
156
  :param base_url: Base URL for the GitCode REST API.
154
157
  :param timeout: Request timeout in seconds.
155
158
  :param http_client: Optional pre-configured ``httpx.AsyncClient`` instance.
159
+ :param decrypt: Optional decryption function for encrypted access token.
156
160
  """
157
161
 
158
162
  repos: AsyncReposResource
@@ -212,6 +216,7 @@ class AsyncGitCode(AsyncAPIClient):
212
216
  base_url: str = DEFAULT_BASE_URL,
213
217
  timeout: Optional[float] = None,
214
218
  http_client: Optional[httpx.AsyncClient] = None,
219
+ decrypt: Optional[Callable] = None,
215
220
  ) -> None:
216
221
  """Create an asynchronous client and attach resource groups."""
217
222
  super().__init__(
@@ -221,6 +226,7 @@ class AsyncGitCode(AsyncAPIClient):
221
226
  base_url=base_url,
222
227
  timeout=timeout,
223
228
  http_client=http_client,
229
+ decrypt=decrypt,
224
230
  )
225
231
  self.repos = AsyncReposResource(self)
226
232
  self.contents = AsyncRepoContentsResource(self)
@@ -0,0 +1 @@
1
+ 1.1.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitcode-api
3
- Version: 1.1.1
3
+ Version: 1.1.2
4
4
  Summary: Easy to use Python SDK for the GitCode REST API, community-maintained.
5
5
  Author-email: Hugo Huang <hugo@hugohuang.com>
6
6
  License-Expression: MIT
@@ -27,9 +27,9 @@ Dynamic: license-file
27
27
 
28
28
  # GitCode-API
29
29
 
30
- ![PyPI - Version](https://img.shields.io/pypi/v/gitcode-api?link=https%3A%2F%2Fpypi.org%2Fproject%2Fgitcode-api%2F) ![GitHub Badge](https://img.shields.io/badge/github-repo-blue?logo=github&link=https%3A%2F%2Fgithub.com%2FTrenza1ore%2FGitCode-API) ![GitCode Badge](https://img.shields.io/badge/gitcode-repo-brown?logo=gitcode&link=https%3A%2F%2Fgitcode.com%2FSushiNinja%2FGitCode-API) ![PyPI - License](https://img.shields.io/pypi/l/gitcode-api)
30
+ [![PyPI - Version](https://img.shields.io/pypi/v/gitcode-api?link=https%3A%2F%2Fpypi.org%2Fproject%2Fgitcode-api%2F)](https://pypi.org/project/gitcode-api) [![GitHub Badge](https://img.shields.io/badge/github-repo-blue?logo=github&link=https%3A%2F%2Fgithub.com%2FTrenza1ore%2FGitCode-API)](https://github.com/Trenza1ore/GitCode-API) [![GitCode Badge](https://img.shields.io/badge/gitcode-repo-brown?logo=gitcode&link=https%3A%2F%2Fgitcode.com%2FSushiNinja%2FGitCode-API)](https://gitcode.com/SushiNinja/GitCode-API) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/gitcode-api?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=RED&left_text=downloads)](https://pepy.tech/projects/gitcode-api)
31
31
 
32
- ![Docs](https://img.shields.io/badge/%E6%96%87%E6%A1%A3-Docs-cyan?style=for-the-badge&logo=readthedocs&link=https%3A%2F%2Fgitcode-api.readthedocs.io%2Fen%2Flatest%2Findex.html) ![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-brown?style=for-the-badge&logo=googledocs&link=README.zh.md) ![English README](https://img.shields.io/badge/English-README-blue?style=for-the-badge&logo=googledocs&link=README.md)
32
+ [![Docs](https://img.shields.io/badge/%E6%96%87%E6%A1%A3-Docs-cyan?style=for-the-badge&logo=readthedocs&link=https%3A%2F%2Fgitcode-api.readthedocs.io%2Fen%2Flatest%2Findex.html)](https://gitcode-api.readthedocs.io) [![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-brown?style=for-the-badge&logo=googledocs&link=README.zh.md)](README.zh.md) [![English README](https://img.shields.io/badge/English-README-blue?style=for-the-badge&logo=googledocs&link=README.md)](README.md)
33
33
 
34
34
  `gitcode-api` is a community-maintained Python SDK for the GitCode REST API. It provides easy-to-use synchronous and asynchronous clients, repository-scoped helpers, and lightweight response models so you can work with GitCode from Python without hand-writing raw HTTP requests.
35
35
 
@@ -57,6 +57,20 @@ Pass `api_key=` directly, or set `GITCODE_ACCESS_TOKEN` in your environment:
57
57
  export GITCODE_ACCESS_TOKEN="your-token"
58
58
  ```
59
59
 
60
+ If your token is stored in encrypted form, pass `decrypt=` to decode either an
61
+ encrypted `api_key=` value or an encrypted `GITCODE_ACCESS_TOKEN` value before
62
+ the client uses it.
63
+
64
+ ```python
65
+ from gitcode_api import GitCode
66
+ from trusted_library import decrypt_token
67
+
68
+ client = GitCode(
69
+ api_key="encrypted-token",
70
+ decrypt=decrypt_token,
71
+ )
72
+ ```
73
+
60
74
  ## Quick Start
61
75
 
62
76
  ### Sync client
@@ -69,40 +83,31 @@ client = GitCode(
69
83
  repo="GitCode-API",
70
84
  )
71
85
 
72
- try:
73
- repo = client.repos.get()
74
- branches = client.branches.list(per_page=5)
86
+ repo = client.repos.get()
87
+ branches = client.branches.list(per_page=5)
75
88
 
76
- print(repo.full_name)
77
- for branch in branches:
78
- print(branch.name)
79
- finally:
80
- client.close()
89
+ print(repo.full_name)
90
+ for branch in branches:
91
+ print(branch.name)
81
92
  ```
82
93
 
83
94
  ### Async client
84
95
 
85
96
  ```python
86
97
  import asyncio
87
-
88
98
  from gitcode_api import AsyncGitCode
89
99
 
90
-
91
100
  async def main() -> None:
92
101
  client = AsyncGitCode(owner="SushiNinja", repo="GitCode-API")
93
- try:
94
- pulls = await client.pulls.list(state="open", per_page=20)
95
- print(len(pulls))
96
- finally:
97
- await client.close()
98
-
102
+ pulls = await client.pulls.list(state="open", per_page=20)
103
+ print(len(pulls))
99
104
 
100
105
  asyncio.run(main())
101
106
  ```
102
107
 
103
108
  ### Context managers
104
109
 
105
- `GitCode` and `AsyncGitCode` (and the lower-level `SyncAPIClient` / `AsyncAPIClient`) support `with` / `async with`. When the SDK creates the underlying httpx client for you, leaving the block calls `close()` / `await close()` on that client automatically.
110
+ `GitCode` and `AsyncGitCode` (and the lower-level `SyncAPIClient` / `AsyncAPIClient`) support `with` / `async with`. Leaving the block calls `close()` / `await close()` on the underlying client automatically, including a custom `http_client=` you passed in.
106
111
 
107
112
  ```python
108
113
  from gitcode_api import GitCode
@@ -114,21 +119,16 @@ with GitCode(owner="SushiNinja", repo="GitCode-API") as client:
114
119
 
115
120
  ```python
116
121
  import asyncio
117
-
118
122
  from gitcode_api import AsyncGitCode
119
123
 
120
-
121
124
  async def main() -> None:
122
125
  async with AsyncGitCode(owner="SushiNinja", repo="GitCode-API") as client:
123
126
  pulls = await client.pulls.list(state="open", per_page=20)
124
127
  print(len(pulls))
125
128
 
126
-
127
129
  asyncio.run(main())
128
130
  ```
129
131
 
130
- If you pass a custom `http_client=`, the SDK does not close it; you still own that client’s lifecycle (for example `async with httpx.AsyncClient(...) as http:` plus `AsyncGitCode(http_client=http)`).
131
-
132
132
  ## Common Workflows
133
133
 
134
134
  Create a pull request:
@@ -1,16 +1,17 @@
1
1
  gitcode_api/__init__.py,sha256=NvLp28D9brVbmv2ROSZ8mxKDuIamE9xeutBKGl9pra8,497
2
- gitcode_api/_base_client.py,sha256=KWe-gP7CGLhG_DtxPclbbJQVXOj6hjtQgAjoCzoUCmo,12496
3
- gitcode_api/_client.py,sha256=1bVngWEkjKoOOODIpvJNlrKS3x1dj-WAUrBW4xncjWY,7819
2
+ gitcode_api/_base_client.py,sha256=1COCZXzSiCe_LNawsOsTNvh0WMh1JW4A5yYgX56HwjY,12894
3
+ gitcode_api/_client.py,sha256=AOpp1P7vdSlMcn0XP3JMPnAKbQMftMO9WMubBGw2LZc,8129
4
4
  gitcode_api/_exceptions.py,sha256=T5N8gBGmPSktDkLP5P_hxbzOHw3W378TzxN1xja40pA,1140
5
5
  gitcode_api/_models.py,sha256=2bR6Wxc3Ie7iM3UFNY0ThWeNjxFHzDAC-8QFgcgcT_0,108599
6
+ gitcode_api/version.txt,sha256=g9DE-d3AiatY4yLimLYZDyv1kdwiX_XN130F5qhCBhk,5
6
7
  gitcode_api/resources/__init__.py,sha256=nsCKW0bFDZ5ombJZxLThmO82sOuF7o4OKUMRkAmwbwk,1725
7
8
  gitcode_api/resources/_shared.py,sha256=EB9fr4eQUc9IOdZCn4AoI946SJYCNVAtOOHEo_OzJAQ,5317
8
9
  gitcode_api/resources/account.py,sha256=mnc2p7wI-nBnHFNdWPNiHfmZpT6d3RDQC777gewtm4M,38801
9
10
  gitcode_api/resources/collaboration.py,sha256=26rQCeayZfUQ_6dIdl5HOGXnYkMLx8V7XsF_Wi-4Qt4,101417
10
11
  gitcode_api/resources/misc.py,sha256=guDwh4cxbTVsSa7EivaYM3bKMJ8_Op4KucGbKEoayKE,22412
11
12
  gitcode_api/resources/repositories.py,sha256=EAK2znZhEsgVUu-NDEQslSEEYJzvb-kHuh4mW57y6sc,78178
12
- gitcode_api-1.1.1.dist-info/licenses/LICENSE,sha256=gOACXuWhMu6PJKVLr9RQbxX3HULnZIGNXCaMFJIXhoA,1067
13
- gitcode_api-1.1.1.dist-info/METADATA,sha256=FXeDlnMlvn12FHZV7jYTkAYNjG34aCVBMwhhSNWh7Ug,6778
14
- gitcode_api-1.1.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
15
- gitcode_api-1.1.1.dist-info/top_level.txt,sha256=gIlg0ptyOUHJT64ajOjWIhRPYgIQnMIvnhhnesw9fxU,12
16
- gitcode_api-1.1.1.dist-info/RECORD,,
13
+ gitcode_api-1.1.2.dist-info/licenses/LICENSE,sha256=gOACXuWhMu6PJKVLr9RQbxX3HULnZIGNXCaMFJIXhoA,1067
14
+ gitcode_api-1.1.2.dist-info/METADATA,sha256=0N2qnZGKbZf_4jxrfQwWDd2daaRhdA3GRw0OqC75C0o,7151
15
+ gitcode_api-1.1.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
16
+ gitcode_api-1.1.2.dist-info/top_level.txt,sha256=gIlg0ptyOUHJT64ajOjWIhRPYgIQnMIvnhhnesw9fxU,12
17
+ gitcode_api-1.1.2.dist-info/RECORD,,