apexdevkit 1.5.24__tar.gz → 1.5.25__tar.gz
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.
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/PKG-INFO +1 -1
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/http/httpx.py +13 -10
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/testing/rest.py +87 -53
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/pyproject.toml +1 -1
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/LICENSE +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/README.md +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/__init__.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/annotation/deprecate.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/error.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/builder.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/dependable.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/resource.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/response.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/router.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/schema.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/fastapi/service.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/formatter.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/http/__init__.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/http/fake.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/http/fluent.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/http/json.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/http/url.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/py.typed +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/repository/__init__.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/repository/base.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/repository/connector.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/repository/database.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/repository/in_memory.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/repository/interface.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/testing/__init__.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/testing/database.py +0 -0
- {apexdevkit-1.5.24 → apexdevkit-1.5.25}/apexdevkit/testing/fake.py +0 -0
|
@@ -4,34 +4,37 @@ from dataclasses import dataclass, field
|
|
|
4
4
|
from typing import Any, Iterator, Mapping, Self
|
|
5
5
|
|
|
6
6
|
import httpx
|
|
7
|
+
from httpx import Client
|
|
7
8
|
|
|
8
9
|
from apexdevkit.http.fluent import HttpMethod, HttpResponse
|
|
9
10
|
from apexdevkit.http.json import JsonDict
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def default_config() -> HttpxConfig:
|
|
14
|
+
return HttpxConfig()
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
@dataclass(frozen=True)
|
|
14
18
|
class Httpx:
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
client: httpx.Client
|
|
20
|
+
|
|
21
|
+
config: HttpxConfig = field(default_factory=default_config)
|
|
17
22
|
|
|
18
23
|
@classmethod
|
|
19
24
|
def create_for(cls, url: str) -> Self:
|
|
20
|
-
return cls(
|
|
25
|
+
return cls(Client(base_url=url), HttpxConfig())
|
|
21
26
|
|
|
22
27
|
def with_header(self, key: str, value: str) -> Httpx:
|
|
23
|
-
return Httpx(self.
|
|
28
|
+
return Httpx(self.client, self.config.with_header(key, value))
|
|
24
29
|
|
|
25
30
|
def with_param(self, key: str, value: str) -> Httpx:
|
|
26
|
-
return Httpx(self.
|
|
31
|
+
return Httpx(self.client, self.config.with_param(key, value))
|
|
27
32
|
|
|
28
33
|
def with_json(self, value: JsonDict) -> Httpx:
|
|
29
|
-
return Httpx(self.
|
|
34
|
+
return Httpx(self.client, self.config.with_json(value))
|
|
30
35
|
|
|
31
36
|
def request(self, method: HttpMethod, endpoint: str) -> HttpResponse:
|
|
32
|
-
return _HttpxResponse(
|
|
33
|
-
httpx.request(method.name, self.url + endpoint, **self.config)
|
|
34
|
-
)
|
|
37
|
+
return _HttpxResponse(self.client.request(method.name, endpoint, **self.config))
|
|
35
38
|
|
|
36
39
|
|
|
37
40
|
@dataclass
|
|
@@ -5,67 +5,76 @@ from dataclasses import dataclass, field
|
|
|
5
5
|
from functools import cached_property
|
|
6
6
|
from typing import Any, Iterable, Self
|
|
7
7
|
|
|
8
|
-
import httpx
|
|
9
8
|
from fastapi.testclient import TestClient
|
|
10
9
|
|
|
11
|
-
from apexdevkit.http import HttpUrl, JsonDict
|
|
10
|
+
from apexdevkit.http import Http, HttpUrl, JsonDict
|
|
11
|
+
from apexdevkit.http.fluent import HttpMethod, HttpResponse
|
|
12
|
+
from apexdevkit.http.httpx import Httpx
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
@dataclass
|
|
15
16
|
class RestResource:
|
|
16
|
-
http: TestClient
|
|
17
|
+
http: TestClient | Http
|
|
17
18
|
name: RestfulName
|
|
18
19
|
|
|
20
|
+
def __post_init__(self) -> None:
|
|
21
|
+
if isinstance(self.http, TestClient):
|
|
22
|
+
self.http = Httpx(self.http)
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def _http(self) -> Http:
|
|
26
|
+
assert not isinstance(self.http, TestClient)
|
|
27
|
+
|
|
28
|
+
return self.http
|
|
29
|
+
|
|
19
30
|
def create_one(self) -> CreateOne:
|
|
20
|
-
return CreateOne(self.name, self.
|
|
31
|
+
return CreateOne(self.name, self._http)
|
|
21
32
|
|
|
22
33
|
def create_many(self) -> CreateMany:
|
|
23
|
-
return CreateMany(self.name, self.
|
|
34
|
+
return CreateMany(self.name, self._http)
|
|
24
35
|
|
|
25
36
|
def read_one(self) -> ReadOne:
|
|
26
|
-
return ReadOne(self.name, self.
|
|
37
|
+
return ReadOne(self.name, self._http)
|
|
27
38
|
|
|
28
39
|
def read_all(self) -> ReadAll:
|
|
29
|
-
return ReadAll(self.name, self.
|
|
40
|
+
return ReadAll(self.name, self._http)
|
|
30
41
|
|
|
31
42
|
def update_one(self) -> UpdateOne:
|
|
32
|
-
return UpdateOne(self.name, self.
|
|
43
|
+
return UpdateOne(self.name, self._http)
|
|
33
44
|
|
|
34
45
|
def update_many(self) -> UpdateMany:
|
|
35
|
-
return UpdateMany(self.name, self.
|
|
46
|
+
return UpdateMany(self.name, self._http)
|
|
36
47
|
|
|
37
48
|
def replace_one(self) -> ReplaceOne:
|
|
38
|
-
return ReplaceOne(self.name, self.
|
|
49
|
+
return ReplaceOne(self.name, self._http)
|
|
39
50
|
|
|
40
51
|
def replace_many(self) -> ReplaceMany:
|
|
41
|
-
return ReplaceMany(self.name, self.
|
|
52
|
+
return ReplaceMany(self.name, self._http)
|
|
42
53
|
|
|
43
54
|
def delete_one(self) -> DeleteOne:
|
|
44
|
-
return DeleteOne(self.name, self.
|
|
55
|
+
return DeleteOne(self.name, self._http)
|
|
45
56
|
|
|
46
57
|
|
|
47
58
|
@dataclass
|
|
48
59
|
class RestCollection(RestResource):
|
|
49
60
|
def sub_resource(self, name: str) -> RestItem:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
)
|
|
61
|
+
assert isinstance(self.http, Httpx), "sub resource only works with Httpx"
|
|
62
|
+
|
|
63
|
+
client = self.http.client
|
|
64
|
+
client.base_url = client.base_url.join(self.name.plural)
|
|
65
|
+
|
|
66
|
+
return RestItem(self.http, RestfulName(name))
|
|
57
67
|
|
|
58
68
|
|
|
59
69
|
@dataclass
|
|
60
70
|
class RestItem(RestResource):
|
|
61
71
|
def sub_resource(self, name: str) -> RestItem:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
72
|
+
assert isinstance(self.http, Httpx), "sub resource only works with Httpx"
|
|
73
|
+
|
|
74
|
+
client = self.http.client
|
|
75
|
+
client.base_url = client.base_url.join(self.name.plural)
|
|
76
|
+
|
|
77
|
+
return RestItem(self.http, RestfulName(name))
|
|
69
78
|
|
|
70
79
|
|
|
71
80
|
@dataclass
|
|
@@ -103,11 +112,11 @@ def as_plural(singular: str) -> str:
|
|
|
103
112
|
@dataclass
|
|
104
113
|
class RestRequest:
|
|
105
114
|
resource: RestfulName
|
|
106
|
-
http:
|
|
115
|
+
http: Http
|
|
107
116
|
|
|
108
117
|
@abstractmethod
|
|
109
118
|
@cached_property
|
|
110
|
-
def response(self) ->
|
|
119
|
+
def response(self) -> HttpResponse: # pragma: no cover
|
|
111
120
|
pass
|
|
112
121
|
|
|
113
122
|
def unpack(self) -> JsonDict:
|
|
@@ -122,7 +131,7 @@ class RestRequest:
|
|
|
122
131
|
return RestResponse(
|
|
123
132
|
resource=self.resource,
|
|
124
133
|
json=JsonDict(self.response.json()),
|
|
125
|
-
http_code=self.response.
|
|
134
|
+
http_code=self.response.code(),
|
|
126
135
|
)
|
|
127
136
|
|
|
128
137
|
|
|
@@ -136,8 +145,11 @@ class CreateOne(RestRequest):
|
|
|
136
145
|
return self
|
|
137
146
|
|
|
138
147
|
@cached_property
|
|
139
|
-
def response(self) ->
|
|
140
|
-
return self.http.
|
|
148
|
+
def response(self) -> HttpResponse:
|
|
149
|
+
return self.http.with_json(self.data).request(
|
|
150
|
+
method=HttpMethod.post,
|
|
151
|
+
endpoint=self.resource + "",
|
|
152
|
+
)
|
|
141
153
|
|
|
142
154
|
|
|
143
155
|
@dataclass
|
|
@@ -145,8 +157,11 @@ class ReadOne(RestRequest):
|
|
|
145
157
|
item_id: str = field(init=False)
|
|
146
158
|
|
|
147
159
|
@cached_property
|
|
148
|
-
def response(self) ->
|
|
149
|
-
return self.http.
|
|
160
|
+
def response(self) -> HttpResponse:
|
|
161
|
+
return self.http.request(
|
|
162
|
+
method=HttpMethod.get,
|
|
163
|
+
endpoint=self.resource + str(self.item_id),
|
|
164
|
+
)
|
|
150
165
|
|
|
151
166
|
def with_id(self, value: Any) -> Self:
|
|
152
167
|
self.item_id = str(value)
|
|
@@ -159,8 +174,12 @@ class ReadAll(RestRequest):
|
|
|
159
174
|
params: dict[str, Any] = field(init=False, default_factory=dict)
|
|
160
175
|
|
|
161
176
|
@cached_property
|
|
162
|
-
def response(self) ->
|
|
163
|
-
|
|
177
|
+
def response(self) -> HttpResponse:
|
|
178
|
+
http = self.http
|
|
179
|
+
for param, value in self.params.items():
|
|
180
|
+
http = http.with_param(param, value)
|
|
181
|
+
|
|
182
|
+
return http.request(method=HttpMethod.get, endpoint=self.resource + "")
|
|
164
183
|
|
|
165
184
|
def with_params(self, **kwargs: Any) -> Self:
|
|
166
185
|
self.params = {**kwargs}
|
|
@@ -174,8 +193,11 @@ class UpdateOne(RestRequest):
|
|
|
174
193
|
data: JsonDict = field(init=False)
|
|
175
194
|
|
|
176
195
|
@cached_property
|
|
177
|
-
def response(self) ->
|
|
178
|
-
return self.http.
|
|
196
|
+
def response(self) -> HttpResponse:
|
|
197
|
+
return self.http.with_json(self.data).request(
|
|
198
|
+
method=HttpMethod.patch,
|
|
199
|
+
endpoint=self.resource + str(self.item_id),
|
|
200
|
+
)
|
|
179
201
|
|
|
180
202
|
def with_id(self, value: Any) -> Self:
|
|
181
203
|
self.item_id = str(value)
|
|
@@ -193,8 +215,11 @@ class ReplaceOne(RestRequest):
|
|
|
193
215
|
data: JsonDict = field(init=False)
|
|
194
216
|
|
|
195
217
|
@cached_property
|
|
196
|
-
def response(self) ->
|
|
197
|
-
return self.http.
|
|
218
|
+
def response(self) -> HttpResponse:
|
|
219
|
+
return self.http.with_json(self.data).request(
|
|
220
|
+
method=HttpMethod.put,
|
|
221
|
+
endpoint=self.resource + "",
|
|
222
|
+
)
|
|
198
223
|
|
|
199
224
|
def from_data(self, value: JsonDict) -> Self:
|
|
200
225
|
self.data = value
|
|
@@ -207,10 +232,12 @@ class CreateMany(RestRequest):
|
|
|
207
232
|
data: list[JsonDict] = field(default_factory=list)
|
|
208
233
|
|
|
209
234
|
@cached_property
|
|
210
|
-
def response(self) ->
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
235
|
+
def response(self) -> HttpResponse:
|
|
236
|
+
json = JsonDict({self.resource.plural: [dict(data) for data in self.data]})
|
|
237
|
+
|
|
238
|
+
return self.http.with_json(json).request(
|
|
239
|
+
method=HttpMethod.post,
|
|
240
|
+
endpoint=self.resource + "batch",
|
|
214
241
|
)
|
|
215
242
|
|
|
216
243
|
def from_data(self, value: JsonDict) -> Self:
|
|
@@ -227,10 +254,12 @@ class UpdateMany(RestRequest):
|
|
|
227
254
|
data: list[JsonDict] = field(default_factory=list)
|
|
228
255
|
|
|
229
256
|
@cached_property
|
|
230
|
-
def response(self) ->
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
257
|
+
def response(self) -> HttpResponse:
|
|
258
|
+
json = JsonDict({self.resource.plural: [dict(data) for data in self.data]})
|
|
259
|
+
|
|
260
|
+
return self.http.with_json(json).request(
|
|
261
|
+
method=HttpMethod.patch,
|
|
262
|
+
endpoint=self.resource + "",
|
|
234
263
|
)
|
|
235
264
|
|
|
236
265
|
def from_data(self, value: JsonDict) -> Self:
|
|
@@ -247,10 +276,12 @@ class ReplaceMany(RestRequest):
|
|
|
247
276
|
data: list[JsonDict] = field(default_factory=list)
|
|
248
277
|
|
|
249
278
|
@cached_property
|
|
250
|
-
def response(self) ->
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
279
|
+
def response(self) -> HttpResponse:
|
|
280
|
+
json = JsonDict({self.resource.plural: [dict(data) for data in self.data]})
|
|
281
|
+
|
|
282
|
+
return self.http.with_json(json).request(
|
|
283
|
+
method=HttpMethod.put,
|
|
284
|
+
endpoint=self.resource + "batch",
|
|
254
285
|
)
|
|
255
286
|
|
|
256
287
|
def from_data(self, value: JsonDict) -> Self:
|
|
@@ -267,8 +298,11 @@ class DeleteOne(RestRequest):
|
|
|
267
298
|
item_id: str = field(init=False)
|
|
268
299
|
|
|
269
300
|
@cached_property
|
|
270
|
-
def response(self) ->
|
|
271
|
-
return self.http.
|
|
301
|
+
def response(self) -> HttpResponse:
|
|
302
|
+
return self.http.request(
|
|
303
|
+
method=HttpMethod.delete,
|
|
304
|
+
endpoint=self.resource + str(self.item_id),
|
|
305
|
+
)
|
|
272
306
|
|
|
273
307
|
def with_id(self, value: Any) -> Self:
|
|
274
308
|
self.item_id = str(value)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|