nadeshiko-sdk 0.1.0__py3-none-any.whl → 0.2.0__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.
nadeshiko/__init__.py CHANGED
@@ -1,10 +1,9 @@
1
1
  """A client library for accessing Nadeshiko API"""
2
2
 
3
3
  from ._version import __version__
4
- from .client import Environment, Nadeshiko
4
+ from .client import AuthenticatedClient as Nadeshiko
5
5
 
6
6
  __all__ = (
7
7
  "Nadeshiko",
8
- "Environment",
9
8
  "__version__",
10
9
  )
nadeshiko/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.0"
1
+ __version__ = "0.2.0"
nadeshiko/client.py CHANGED
@@ -1,103 +1,226 @@
1
1
  import ssl
2
- from enum import Enum
3
2
  from typing import Any
4
3
 
5
4
  import httpx
6
5
  from attrs import define, evolve, field
7
6
 
8
7
 
9
- class Environment(Enum):
10
- """API environment presets."""
8
+ @define
9
+ class Client:
10
+ """A class for keeping track of data related to the API
11
+
12
+ The following are accepted as keyword arguments and will be used to construct httpx Clients internally:
13
+
14
+ ``base_url``: The base URL for the API, all requests are made to a relative path to this URL
15
+
16
+ ``cookies``: A dictionary of cookies to be sent with every request
17
+
18
+ ``headers``: A dictionary of headers to be sent with every request
19
+
20
+ ``timeout``: The maximum amount of a time a request can take. API functions will raise
21
+ httpx.TimeoutException if this is exceeded.
22
+
23
+ ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production,
24
+ but can be set to False for testing purposes.
25
+
26
+ ``follow_redirects``: Whether or not to follow redirects. Default value is False.
27
+
28
+ ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor.
29
+
30
+
31
+ Attributes:
32
+ raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a
33
+ status code that was not documented in the source OpenAPI document. Can also be provided as a keyword
34
+ argument to the constructor.
35
+ """
36
+
37
+ raise_on_unexpected_status: bool = field(default=False, kw_only=True)
38
+ _base_url: str = field(alias="base_url")
39
+ _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies")
40
+ _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers")
41
+ _timeout: httpx.Timeout | None = field(default=None, kw_only=True, alias="timeout")
42
+ _verify_ssl: str | bool | ssl.SSLContext = field(default=True, kw_only=True, alias="verify_ssl")
43
+ _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects")
44
+ _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args")
45
+ _client: httpx.Client | None = field(default=None, init=False)
46
+ _async_client: httpx.AsyncClient | None = field(default=None, init=False)
47
+
48
+ def with_headers(self, headers: dict[str, str]) -> "Client":
49
+ """Get a new client matching this one with additional headers"""
50
+ if self._client is not None:
51
+ self._client.headers.update(headers)
52
+ if self._async_client is not None:
53
+ self._async_client.headers.update(headers)
54
+ return evolve(self, headers={**self._headers, **headers})
11
55
 
12
- LOCAL = "http://localhost:5000"
13
- PRODUCTION = "https://api.nadeshiko.co"
56
+ def with_cookies(self, cookies: dict[str, str]) -> "Client":
57
+ """Get a new client matching this one with additional cookies"""
58
+ if self._client is not None:
59
+ self._client.cookies.update(cookies)
60
+ if self._async_client is not None:
61
+ self._async_client.cookies.update(cookies)
62
+ return evolve(self, cookies={**self._cookies, **cookies})
14
63
 
64
+ def with_timeout(self, timeout: httpx.Timeout) -> "Client":
65
+ """Get a new client matching this one with a new timeout configuration"""
66
+ if self._client is not None:
67
+ self._client.timeout = timeout
68
+ if self._async_client is not None:
69
+ self._async_client.timeout = timeout
70
+ return evolve(self, timeout=timeout)
15
71
 
16
- def _resolve_base_url(base_url: str | Environment) -> str:
17
- """Resolve environment enum to URL, or return URL string as-is."""
18
- if isinstance(base_url, Environment):
19
- return base_url.value
20
- return base_url
72
+ def set_httpx_client(self, client: httpx.Client) -> "Client":
73
+ """Manually set the underlying httpx.Client
74
+
75
+ **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout.
76
+ """
77
+ self._client = client
78
+ return self
79
+
80
+ def get_httpx_client(self) -> httpx.Client:
81
+ """Get the underlying httpx.Client, constructing a new one if not previously set"""
82
+ if self._client is None:
83
+ self._client = httpx.Client(
84
+ base_url=self._base_url,
85
+ cookies=self._cookies,
86
+ headers=self._headers,
87
+ timeout=self._timeout,
88
+ verify=self._verify_ssl,
89
+ follow_redirects=self._follow_redirects,
90
+ **self._httpx_args,
91
+ )
92
+ return self._client
93
+
94
+ def __enter__(self) -> "Client":
95
+ """Enter a context manager for self.client—you cannot enter twice (see httpx docs)"""
96
+ self.get_httpx_client().__enter__()
97
+ return self
98
+
99
+ def __exit__(self, *args: Any, **kwargs: Any) -> None:
100
+ """Exit a context manager for internal httpx.Client (see httpx docs)"""
101
+ self.get_httpx_client().__exit__(*args, **kwargs)
102
+
103
+ def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client":
104
+ """Manually set the underlying httpx.AsyncClient
105
+
106
+ **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout.
107
+ """
108
+ self._async_client = async_client
109
+ return self
110
+
111
+ def get_async_httpx_client(self) -> httpx.AsyncClient:
112
+ """Get the underlying httpx.AsyncClient, constructing a new one if not previously set"""
113
+ if self._async_client is None:
114
+ self._async_client = httpx.AsyncClient(
115
+ base_url=self._base_url,
116
+ cookies=self._cookies,
117
+ headers=self._headers,
118
+ timeout=self._timeout,
119
+ verify=self._verify_ssl,
120
+ follow_redirects=self._follow_redirects,
121
+ **self._httpx_args,
122
+ )
123
+ return self._async_client
124
+
125
+ async def __aenter__(self) -> "Client":
126
+ """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)"""
127
+ await self.get_async_httpx_client().__aenter__()
128
+ return self
129
+
130
+ async def __aexit__(self, *args: Any, **kwargs: Any) -> None:
131
+ """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)"""
132
+ await self.get_async_httpx_client().__aexit__(*args, **kwargs)
21
133
 
22
134
 
23
135
  @define
24
- class Nadeshiko:
25
- """Nadeshiko API client.
26
-
27
- Example:
28
- >>> from nadeshiko import Nadeshiko, Environment
29
- >>> from nadeshiko.api.search import search
30
- >>>
31
- >>> client = Nadeshiko(api_key="your-key")
32
- >>> result = search.sync(client=client, body={"query": "..."})
33
-
34
- Args:
35
- api_key: Your Nadeshiko API key
36
- base_url: API environment (Environment.PRODUCTION, Environment.LOCAL) or custom URL string
37
- timeout: Request timeout
38
- verify_ssl: Whether to verify SSL certificates
39
- follow_redirects: Whether to follow redirects
40
- raise_on_unexpected_status: Whether to raise on unexpected status codes
41
- httpx_args: Additional arguments for httpx.Client
136
+ class AuthenticatedClient:
137
+ """A Client which has been authenticated for use on secured endpoints
138
+
139
+ The following are accepted as keyword arguments and will be used to construct httpx Clients internally:
140
+
141
+ ``base_url``: The base URL for the API, all requests are made to a relative path to this URL
142
+
143
+ ``cookies``: A dictionary of cookies to be sent with every request
144
+
145
+ ``headers``: A dictionary of headers to be sent with every request
146
+
147
+ ``timeout``: The maximum amount of a time a request can take. API functions will raise
148
+ httpx.TimeoutException if this is exceeded.
149
+
150
+ ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production,
151
+ but can be set to False for testing purposes.
152
+
153
+ ``follow_redirects``: Whether or not to follow redirects. Default value is False.
154
+
155
+ ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor.
156
+
157
+
158
+ Attributes:
159
+ raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a
160
+ status code that was not documented in the source OpenAPI document. Can also be provided as a keyword
161
+ argument to the constructor.
162
+ token: The token to use for authentication
163
+ prefix: The prefix to use for the Authorization header
164
+ auth_header_name: The name of the Authorization header
42
165
  """
43
166
 
44
- _api_key: str = field(alias="api_key")
45
- _base_url: str | Environment = field(default=Environment.PRODUCTION, alias="base_url")
167
+ raise_on_unexpected_status: bool = field(default=False, kw_only=True)
168
+ _base_url: str = field(alias="base_url")
46
169
  _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies")
47
170
  _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers")
48
171
  _timeout: httpx.Timeout | None = field(default=None, kw_only=True, alias="timeout")
49
172
  _verify_ssl: str | bool | ssl.SSLContext = field(default=True, kw_only=True, alias="verify_ssl")
50
173
  _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects")
51
174
  _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args")
52
- _raise_on_unexpected_status: bool = field(
53
- default=False, kw_only=True, alias="raise_on_unexpected_status"
54
- )
55
175
  _client: httpx.Client | None = field(default=None, init=False)
56
176
  _async_client: httpx.AsyncClient | None = field(default=None, init=False)
57
177
 
58
- @property
59
- def raise_on_unexpected_status(self) -> bool:
60
- """Whether to raise on unexpected status codes."""
61
- return self._raise_on_unexpected_status
178
+ token: str
179
+ prefix: str = "Bearer"
180
+ auth_header_name: str = "Authorization"
62
181
 
63
- def with_headers(self, headers: dict[str, str]) -> "Nadeshiko":
64
- """Get a new client matching this one with additional headers."""
182
+ def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient":
183
+ """Get a new client matching this one with additional headers"""
65
184
  if self._client is not None:
66
185
  self._client.headers.update(headers)
67
186
  if self._async_client is not None:
68
187
  self._async_client.headers.update(headers)
69
188
  return evolve(self, headers={**self._headers, **headers})
70
189
 
71
- def with_cookies(self, cookies: dict[str, str]) -> "Nadeshiko":
72
- """Get a new client matching this one with additional cookies."""
190
+ def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient":
191
+ """Get a new client matching this one with additional cookies"""
73
192
  if self._client is not None:
74
193
  self._client.cookies.update(cookies)
75
194
  if self._async_client is not None:
76
195
  self._async_client.cookies.update(cookies)
77
196
  return evolve(self, cookies={**self._cookies, **cookies})
78
197
 
79
- def with_timeout(self, timeout: httpx.Timeout) -> "Nadeshiko":
80
- """Get a new client matching this one with a new timeout configuration."""
198
+ def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient":
199
+ """Get a new client matching this one with a new timeout configuration"""
81
200
  if self._client is not None:
82
201
  self._client.timeout = timeout
83
202
  if self._async_client is not None:
84
203
  self._async_client.timeout = timeout
85
204
  return evolve(self, timeout=timeout)
86
205
 
87
- # Internal methods required by generated API functions
88
- # These are not part of the public API
206
+ def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient":
207
+ """Manually set the underlying httpx.Client
89
208
 
90
- def set_httpx_client(self, client: httpx.Client) -> "Nadeshiko":
209
+ **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout.
210
+ """
91
211
  self._client = client
92
212
  return self
93
213
 
94
214
  def get_httpx_client(self) -> httpx.Client:
215
+ """Get the underlying httpx.Client, constructing a new one if not previously set"""
95
216
  if self._client is None:
96
- headers = {**self._headers, "X-API-Key": self._api_key}
217
+ self._headers[self.auth_header_name] = (
218
+ f"{self.prefix} {self.token}" if self.prefix else self.token
219
+ )
97
220
  self._client = httpx.Client(
98
- base_url=_resolve_base_url(self._base_url),
221
+ base_url=self._base_url,
99
222
  cookies=self._cookies,
100
- headers=headers,
223
+ headers=self._headers,
101
224
  timeout=self._timeout,
102
225
  verify=self._verify_ssl,
103
226
  follow_redirects=self._follow_redirects,
@@ -105,24 +228,33 @@ class Nadeshiko:
105
228
  )
106
229
  return self._client
107
230
 
108
- def __enter__(self) -> "Nadeshiko":
231
+ def __enter__(self) -> "AuthenticatedClient":
232
+ """Enter a context manager for self.client—you cannot enter twice (see httpx docs)"""
109
233
  self.get_httpx_client().__enter__()
110
234
  return self
111
235
 
112
236
  def __exit__(self, *args: Any, **kwargs: Any) -> None:
237
+ """Exit a context manager for internal httpx.Client (see httpx docs)"""
113
238
  self.get_httpx_client().__exit__(*args, **kwargs)
114
239
 
115
- def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Nadeshiko":
240
+ def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient":
241
+ """Manually set the underlying httpx.AsyncClient
242
+
243
+ **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout.
244
+ """
116
245
  self._async_client = async_client
117
246
  return self
118
247
 
119
248
  def get_async_httpx_client(self) -> httpx.AsyncClient:
249
+ """Get the underlying httpx.AsyncClient, constructing a new one if not previously set"""
120
250
  if self._async_client is None:
121
- headers = {**self._headers, "X-API-Key": self._api_key}
251
+ self._headers[self.auth_header_name] = (
252
+ f"{self.prefix} {self.token}" if self.prefix else self.token
253
+ )
122
254
  self._async_client = httpx.AsyncClient(
123
- base_url=_resolve_base_url(self._base_url),
255
+ base_url=self._base_url,
124
256
  cookies=self._cookies,
125
- headers=headers,
257
+ headers=self._headers,
126
258
  timeout=self._timeout,
127
259
  verify=self._verify_ssl,
128
260
  follow_redirects=self._follow_redirects,
@@ -130,9 +262,11 @@ class Nadeshiko:
130
262
  )
131
263
  return self._async_client
132
264
 
133
- async def __aenter__(self) -> "Nadeshiko":
265
+ async def __aenter__(self) -> "AuthenticatedClient":
266
+ """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)"""
134
267
  await self.get_async_httpx_client().__aenter__()
135
268
  return self
136
269
 
137
270
  async def __aexit__(self, *args: Any, **kwargs: Any) -> None:
271
+ """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)"""
138
272
  await self.get_async_httpx_client().__aexit__(*args, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nadeshiko-sdk
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Python SDK for Nadeshiko API
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: attrs>=23.0
@@ -17,6 +17,9 @@ Description-Content-Type: text/markdown
17
17
 
18
18
  # Nadeshiko Python SDK
19
19
 
20
+ [![PyPI](https://img.shields.io/pypi/v/nadeshiko-sdk)](https://pypi.org/project/nadeshiko-sdk/)
21
+
22
+
20
23
  Python SDK for the [Nadeshiko API](https://nadeshiko.co)
21
24
 
22
25
  ## Quick Start
@@ -1,6 +1,6 @@
1
- nadeshiko/__init__.py,sha256=jjn5gWMKhcaeM-4U-7o8U612jfmBraHdqYzRqMDUvEE,199
2
- nadeshiko/_version.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
3
- nadeshiko/client.py,sha256=23sewMBgxMhjbI1-pob_dMqO5ZzP1fl_dkGCEaZSi48,5459
1
+ nadeshiko/__init__.py,sha256=aeAjSMM5BYro2XyF18xzV3c0AlWyPLxr2iJijsB7Tks,190
2
+ nadeshiko/_version.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
3
+ nadeshiko/client.py,sha256=KI0gSZL9TUd9vfpb6T01eliMBmRbqGv_-Gbmp-E--pg,12448
4
4
  nadeshiko/errors.py,sha256=gO8GBmKqmSNgAg-E5oT-oOyxztvp7V_6XG7OUTT15q0,546
5
5
  nadeshiko/types.py,sha256=0We4NPvhIYASRpQ3le41nmJeEAVm42-2VKdzlJ4Ogok,1343
6
6
  nadeshiko/api/__init__.py,sha256=zTSiG_ujSjAqWPyc435YXaX9XTlpMjiJWBbV-f-YtdA,45
@@ -162,6 +162,6 @@ nadeshiko/models/user_info_response_user.py,sha256=JTCD9BMIcH1ygWcyB8VfYZjcQwi-w
162
162
  nadeshiko/models/user_role.py,sha256=je_tlp39e-2jlzwBnmjkr6ymhJ6olWKTPEtFExEsHGE,1811
163
163
  nadeshiko/models/word_match.py,sha256=Yaf5_bSK4Dk93EHqOesb9jQ8BlQlX4NUU39GpupEl7A,3285
164
164
  nadeshiko/models/word_match_media.py,sha256=6eKrsm3fQHe2mLYNQ4aRQCU7JrMaIoJqw7NTA2o_2-Y,3094
165
- nadeshiko_sdk-0.1.0.dist-info/METADATA,sha256=ZdEJglmBYua2njxdOHzba94kEjSy91l1_p-sVXysW4g,3946
166
- nadeshiko_sdk-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
167
- nadeshiko_sdk-0.1.0.dist-info/RECORD,,
165
+ nadeshiko_sdk-0.2.0.dist-info/METADATA,sha256=gq-rQIr6hh7L4XVDlx1JYweeTCmPNOx5MjOleQUzcl0,4044
166
+ nadeshiko_sdk-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
167
+ nadeshiko_sdk-0.2.0.dist-info/RECORD,,