apexdevkit 1.15.7__tar.gz → 1.16.1__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.15.7 → apexdevkit-1.16.1}/PKG-INFO +1 -1
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/dependable.py +1 -1
- apexdevkit-1.16.1/apexdevkit/fastapi/name.py +37 -0
- apexdevkit-1.16.1/apexdevkit/fastapi/request.py +88 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/response.py +66 -2
- apexdevkit-1.16.1/apexdevkit/fastapi/rest.py +92 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/router.py +1 -1
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/schema.py +1 -1
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/testing/__init__.py +1 -3
- apexdevkit-1.16.1/apexdevkit/testing/rest.py +18 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/pyproject.toml +1 -1
- apexdevkit-1.15.7/apexdevkit/testing/rest.py +0 -280
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/LICENSE +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/README.md +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/__init__.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/annotation/deprecate.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/environment.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/error.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/builder.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/resource.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fastapi/service.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/fluent.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/formatter.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/http/__init__.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/http/fake.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/http/fluent.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/http/httpx.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/http/json.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/http/url.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/key_fn.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/py.typed +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/__init__.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/base.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/connector.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/database.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/decorator.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/in_memory.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/interface.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/mongo.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/mssql.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/repository/sqlite.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/server.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/synchronization.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/testing/database.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/testing/fake.py +0 -0
- {apexdevkit-1.15.7 → apexdevkit-1.16.1}/apexdevkit/value.py +0 -0
|
@@ -6,9 +6,9 @@ from fastapi.requests import Request
|
|
|
6
6
|
|
|
7
7
|
from apexdevkit.error import ApiError, DoesNotExistError
|
|
8
8
|
from apexdevkit.fastapi import RestfulServiceBuilder
|
|
9
|
+
from apexdevkit.fastapi.name import RestfulName
|
|
9
10
|
from apexdevkit.fastapi.response import RestfulResponse
|
|
10
11
|
from apexdevkit.fastapi.service import RestfulService
|
|
11
|
-
from apexdevkit.testing import RestfulName
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def inject(dependency: str) -> Any: # pragma: no cover
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from apexdevkit.http import HttpUrl
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class RestfulName:
|
|
10
|
+
singular: str
|
|
11
|
+
|
|
12
|
+
plural: str = ""
|
|
13
|
+
|
|
14
|
+
def __post_init__(self) -> None:
|
|
15
|
+
self.plural = self.plural or as_plural(self.singular)
|
|
16
|
+
|
|
17
|
+
def __add__(self, other: str) -> str:
|
|
18
|
+
return HttpUrl(self.plural) + other
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def as_plural(singular: str) -> str:
|
|
22
|
+
suffixes = {
|
|
23
|
+
"y": "ies",
|
|
24
|
+
"ch": "ches",
|
|
25
|
+
"sh": "shes",
|
|
26
|
+
"s": "ses",
|
|
27
|
+
"z": "zes",
|
|
28
|
+
"x": "xes",
|
|
29
|
+
"fe": "ves",
|
|
30
|
+
"f": "ves",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for singular_suffix, plural_suffix in suffixes.items():
|
|
34
|
+
if singular.endswith(singular_suffix):
|
|
35
|
+
return singular.removesuffix(singular_suffix) + plural_suffix
|
|
36
|
+
|
|
37
|
+
return singular + "s"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from functools import cached_property
|
|
5
|
+
from typing import Any, Iterable, Self
|
|
6
|
+
|
|
7
|
+
from apexdevkit.fastapi.name import RestfulName
|
|
8
|
+
from apexdevkit.fastapi.response import RestResponse
|
|
9
|
+
from apexdevkit.http import Http, HttpMethod, JsonDict
|
|
10
|
+
from apexdevkit.http.fluent import HttpResponse
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class HttpRequest:
|
|
15
|
+
method: HttpMethod
|
|
16
|
+
http: Http
|
|
17
|
+
|
|
18
|
+
def with_endpoint(self, value: Any) -> HttpRequest:
|
|
19
|
+
self.http = self.http.with_endpoint(str(value))
|
|
20
|
+
|
|
21
|
+
return self
|
|
22
|
+
|
|
23
|
+
def with_param(self, name: str, value: Any) -> HttpRequest:
|
|
24
|
+
self.http = self.http.with_param(name, value)
|
|
25
|
+
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def with_json(self, value: JsonDict) -> HttpRequest:
|
|
29
|
+
self.http = self.http.with_json(value)
|
|
30
|
+
|
|
31
|
+
return self
|
|
32
|
+
|
|
33
|
+
def __call__(self) -> HttpResponse:
|
|
34
|
+
return self.http.request(self.method)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class RestRequest:
|
|
39
|
+
resource: RestfulName
|
|
40
|
+
request: HttpRequest
|
|
41
|
+
|
|
42
|
+
def with_id(self, value: Any) -> Self:
|
|
43
|
+
self.request = self.request.with_endpoint(value)
|
|
44
|
+
|
|
45
|
+
return self
|
|
46
|
+
|
|
47
|
+
def from_collection(self, value: list[JsonDict]) -> Self:
|
|
48
|
+
return self.with_data(
|
|
49
|
+
JsonDict({self.resource.plural: [dict(item) for item in value]})
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def and_data(self, value: JsonDict) -> Self:
|
|
53
|
+
return self.with_data(value)
|
|
54
|
+
|
|
55
|
+
def from_data(self, value: JsonDict) -> Self:
|
|
56
|
+
return self.with_data(value)
|
|
57
|
+
|
|
58
|
+
def with_data(self, value: JsonDict) -> Self:
|
|
59
|
+
self.request = self.request.with_json(value)
|
|
60
|
+
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
def and_param(self, name: str, value: Any) -> Self:
|
|
64
|
+
return self.with_param(name, value)
|
|
65
|
+
|
|
66
|
+
def with_param(self, name: str, value: Any) -> Self:
|
|
67
|
+
self.request = self.request.with_param(name, str(value))
|
|
68
|
+
|
|
69
|
+
return self
|
|
70
|
+
|
|
71
|
+
@cached_property
|
|
72
|
+
def response(self) -> HttpResponse:
|
|
73
|
+
return self.request()
|
|
74
|
+
|
|
75
|
+
def unpack(self) -> JsonDict:
|
|
76
|
+
return JsonDict(self.response.json()["data"][self.resource.singular])
|
|
77
|
+
|
|
78
|
+
def unpack_many(self) -> Iterable[JsonDict]:
|
|
79
|
+
items = self.response.json()["data"][self.resource.plural]
|
|
80
|
+
|
|
81
|
+
return [JsonDict(item) for item in items]
|
|
82
|
+
|
|
83
|
+
def ensure(self) -> RestResponse:
|
|
84
|
+
return RestResponse(
|
|
85
|
+
resource=self.resource,
|
|
86
|
+
json=JsonDict(self.response.json()),
|
|
87
|
+
http_code=self.response.code(),
|
|
88
|
+
)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any, Iterable
|
|
4
|
+
from typing import Any, Iterable, Self
|
|
5
5
|
|
|
6
6
|
from apexdevkit.error import DoesNotExistError, ExistsError, ForbiddenError
|
|
7
|
-
from apexdevkit.
|
|
7
|
+
from apexdevkit.fastapi.name import RestfulName
|
|
8
|
+
from apexdevkit.http import JsonDict
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@dataclass(frozen=True)
|
|
@@ -67,3 +68,66 @@ class RestfulResponse:
|
|
|
67
68
|
content["data"] = {self.name.singular: data}
|
|
68
69
|
|
|
69
70
|
return content
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass
|
|
74
|
+
class RestResponse:
|
|
75
|
+
resource: RestfulName
|
|
76
|
+
json: JsonDict
|
|
77
|
+
http_code: int
|
|
78
|
+
|
|
79
|
+
def fail(self) -> Self:
|
|
80
|
+
if self.http_code == 422:
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
return self.with_status("fail")
|
|
84
|
+
|
|
85
|
+
def success(self) -> Self:
|
|
86
|
+
return self.with_status("success")
|
|
87
|
+
|
|
88
|
+
def with_status(self, value: str) -> Self:
|
|
89
|
+
assert self.json.value_of("status").to(str) == value
|
|
90
|
+
|
|
91
|
+
return self
|
|
92
|
+
|
|
93
|
+
def with_code(self, value: int) -> Self:
|
|
94
|
+
assert self.http_code == value
|
|
95
|
+
|
|
96
|
+
if self.http_code != 422:
|
|
97
|
+
assert self.json.value_of("code").to(int) == value
|
|
98
|
+
|
|
99
|
+
return self
|
|
100
|
+
|
|
101
|
+
def message(self, value: str) -> Self:
|
|
102
|
+
return self.with_message(value)
|
|
103
|
+
|
|
104
|
+
def and_message(self, value: str) -> Self:
|
|
105
|
+
return self.with_message(value)
|
|
106
|
+
|
|
107
|
+
def with_message(self, value: str) -> Self:
|
|
108
|
+
assert self.json.value_of("error").to(dict) == {"message": value}, self.json
|
|
109
|
+
|
|
110
|
+
return self
|
|
111
|
+
|
|
112
|
+
def and_item(self, value: Any) -> Self:
|
|
113
|
+
return self.with_item(value)
|
|
114
|
+
|
|
115
|
+
def with_item(self, value: Any) -> Self:
|
|
116
|
+
return self.with_data(**{self.resource.singular: value})
|
|
117
|
+
|
|
118
|
+
def and_collection(self, value: list[Any]) -> Self:
|
|
119
|
+
return self.with_collection(value)
|
|
120
|
+
|
|
121
|
+
def with_collection(self, values: list[Any]) -> Self:
|
|
122
|
+
return self.with_data(**{self.resource.plural: values}, count=len(values))
|
|
123
|
+
|
|
124
|
+
def and_no_data(self) -> Self:
|
|
125
|
+
return self.no_data()
|
|
126
|
+
|
|
127
|
+
def no_data(self) -> Self:
|
|
128
|
+
return self.with_data()
|
|
129
|
+
|
|
130
|
+
def with_data(self, **kwargs: Any) -> Self:
|
|
131
|
+
assert self.json.value_of("data").to(dict) == {**kwargs}, self.json
|
|
132
|
+
|
|
133
|
+
return self
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from apexdevkit.fastapi.name import RestfulName
|
|
4
|
+
from apexdevkit.fastapi.request import HttpRequest, RestRequest
|
|
5
|
+
from apexdevkit.http import Http, HttpMethod
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class RestResource:
|
|
10
|
+
http: Http
|
|
11
|
+
name: RestfulName
|
|
12
|
+
|
|
13
|
+
def create_one(self) -> RestRequest:
|
|
14
|
+
return RestRequest(
|
|
15
|
+
self.name,
|
|
16
|
+
HttpRequest(
|
|
17
|
+
HttpMethod.post,
|
|
18
|
+
self.http.with_endpoint(self.name.plural),
|
|
19
|
+
),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
def create_many(self) -> RestRequest:
|
|
23
|
+
return RestRequest(
|
|
24
|
+
self.name,
|
|
25
|
+
HttpRequest(
|
|
26
|
+
HttpMethod.post,
|
|
27
|
+
self.http.with_endpoint(self.name.plural).with_endpoint("batch"),
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def read_one(self) -> RestRequest:
|
|
32
|
+
return RestRequest(
|
|
33
|
+
self.name,
|
|
34
|
+
HttpRequest(
|
|
35
|
+
HttpMethod.get,
|
|
36
|
+
self.http.with_endpoint(self.name.plural),
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def read_all(self) -> RestRequest:
|
|
41
|
+
return RestRequest(
|
|
42
|
+
self.name,
|
|
43
|
+
HttpRequest(
|
|
44
|
+
HttpMethod.get,
|
|
45
|
+
self.http.with_endpoint(self.name.plural),
|
|
46
|
+
),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def update_one(self) -> RestRequest:
|
|
50
|
+
return RestRequest(
|
|
51
|
+
self.name,
|
|
52
|
+
HttpRequest(
|
|
53
|
+
HttpMethod.patch,
|
|
54
|
+
self.http.with_endpoint(self.name.plural),
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def update_many(self) -> RestRequest:
|
|
59
|
+
return RestRequest(
|
|
60
|
+
self.name,
|
|
61
|
+
HttpRequest(
|
|
62
|
+
HttpMethod.patch,
|
|
63
|
+
self.http.with_endpoint(self.name.plural),
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def replace_one(self) -> RestRequest:
|
|
68
|
+
return RestRequest(
|
|
69
|
+
self.name,
|
|
70
|
+
HttpRequest(
|
|
71
|
+
HttpMethod.put,
|
|
72
|
+
self.http.with_endpoint(self.name.plural),
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def replace_many(self) -> RestRequest:
|
|
77
|
+
return RestRequest(
|
|
78
|
+
self.name,
|
|
79
|
+
HttpRequest(
|
|
80
|
+
HttpMethod.put,
|
|
81
|
+
self.http.with_endpoint(self.name.plural).with_endpoint("batch"),
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def delete_one(self) -> RestRequest:
|
|
86
|
+
return RestRequest(
|
|
87
|
+
self.name,
|
|
88
|
+
HttpRequest(
|
|
89
|
+
HttpMethod.delete,
|
|
90
|
+
self.http.with_endpoint(self.name.plural),
|
|
91
|
+
),
|
|
92
|
+
)
|
|
@@ -6,11 +6,11 @@ from fastapi import APIRouter, Depends, Path
|
|
|
6
6
|
from fastapi.responses import JSONResponse
|
|
7
7
|
|
|
8
8
|
from apexdevkit.fastapi.builder import RestfulServiceBuilder
|
|
9
|
+
from apexdevkit.fastapi.name import RestfulName
|
|
9
10
|
from apexdevkit.fastapi.resource import RestfulResource
|
|
10
11
|
from apexdevkit.fastapi.response import RestfulResponse
|
|
11
12
|
from apexdevkit.fastapi.schema import RestfulSchema, SchemaFields
|
|
12
13
|
from apexdevkit.fastapi.service import RawCollection, RawItem, RestfulService
|
|
13
|
-
from apexdevkit.testing import RestfulName
|
|
14
14
|
|
|
15
15
|
_Response = JSONResponse | dict[str, Any]
|
|
16
16
|
|
|
@@ -5,8 +5,8 @@ from typing import Any, Callable, Iterable, List
|
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel, create_model
|
|
7
7
|
|
|
8
|
+
from apexdevkit.fastapi.name import RestfulName
|
|
8
9
|
from apexdevkit.fluent import FluentDict
|
|
9
|
-
from apexdevkit.testing import RestfulName
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class SchemaFields(ABC):
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
from apexdevkit.testing.database import FakeConnector
|
|
2
2
|
from apexdevkit.testing.fake import FakeValue
|
|
3
|
-
from apexdevkit.testing.rest import RestCollection
|
|
3
|
+
from apexdevkit.testing.rest import RestCollection
|
|
4
4
|
|
|
5
5
|
__all__ = [
|
|
6
6
|
"FakeConnector",
|
|
7
7
|
"RestCollection",
|
|
8
|
-
"RestfulName",
|
|
9
|
-
"RestResource",
|
|
10
8
|
"FakeValue",
|
|
11
9
|
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from apexdevkit.fastapi.name import RestfulName
|
|
6
|
+
from apexdevkit.fastapi.rest import RestResource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class RestCollection(RestResource):
|
|
11
|
+
def sub_resource(self, name: str) -> RestItem:
|
|
12
|
+
return RestItem(self.http.with_endpoint(self.name.plural), RestfulName(name))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class RestItem(RestResource):
|
|
17
|
+
def sub_resource(self, name: str) -> RestItem:
|
|
18
|
+
return RestItem(self.http.with_endpoint(self.name.singular), RestfulName(name))
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from functools import cached_property
|
|
5
|
-
from typing import Any, Iterable, Self
|
|
6
|
-
|
|
7
|
-
from apexdevkit.http import Http, HttpUrl, JsonDict
|
|
8
|
-
from apexdevkit.http.fluent import HttpMethod, HttpResponse
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass(frozen=True)
|
|
12
|
-
class RestResource:
|
|
13
|
-
http: Http
|
|
14
|
-
name: RestfulName
|
|
15
|
-
|
|
16
|
-
def create_one(self) -> RestRequest:
|
|
17
|
-
return RestRequest(
|
|
18
|
-
self.name,
|
|
19
|
-
HttpRequest(
|
|
20
|
-
HttpMethod.post,
|
|
21
|
-
self.http.with_endpoint(self.name.plural),
|
|
22
|
-
),
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
def create_many(self) -> RestRequest:
|
|
26
|
-
return RestRequest(
|
|
27
|
-
self.name,
|
|
28
|
-
HttpRequest(
|
|
29
|
-
HttpMethod.post,
|
|
30
|
-
self.http.with_endpoint(self.name.plural).with_endpoint("batch"),
|
|
31
|
-
),
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
def read_one(self) -> RestRequest:
|
|
35
|
-
return RestRequest(
|
|
36
|
-
self.name,
|
|
37
|
-
HttpRequest(
|
|
38
|
-
HttpMethod.get,
|
|
39
|
-
self.http.with_endpoint(self.name.plural),
|
|
40
|
-
),
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
def read_all(self) -> RestRequest:
|
|
44
|
-
return RestRequest(
|
|
45
|
-
self.name,
|
|
46
|
-
HttpRequest(
|
|
47
|
-
HttpMethod.get,
|
|
48
|
-
self.http.with_endpoint(self.name.plural),
|
|
49
|
-
),
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
def update_one(self) -> RestRequest:
|
|
53
|
-
return RestRequest(
|
|
54
|
-
self.name,
|
|
55
|
-
HttpRequest(
|
|
56
|
-
HttpMethod.patch,
|
|
57
|
-
self.http.with_endpoint(self.name.plural),
|
|
58
|
-
),
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
def update_many(self) -> RestRequest:
|
|
62
|
-
return RestRequest(
|
|
63
|
-
self.name,
|
|
64
|
-
HttpRequest(
|
|
65
|
-
HttpMethod.patch,
|
|
66
|
-
self.http.with_endpoint(self.name.plural),
|
|
67
|
-
),
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
def replace_one(self) -> RestRequest:
|
|
71
|
-
return RestRequest(
|
|
72
|
-
self.name,
|
|
73
|
-
HttpRequest(
|
|
74
|
-
HttpMethod.put,
|
|
75
|
-
self.http.with_endpoint(self.name.plural),
|
|
76
|
-
),
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
def replace_many(self) -> RestRequest:
|
|
80
|
-
return RestRequest(
|
|
81
|
-
self.name,
|
|
82
|
-
HttpRequest(
|
|
83
|
-
HttpMethod.put,
|
|
84
|
-
self.http.with_endpoint(self.name.plural).with_endpoint("batch"),
|
|
85
|
-
),
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
def delete_one(self) -> RestRequest:
|
|
89
|
-
return RestRequest(
|
|
90
|
-
self.name,
|
|
91
|
-
HttpRequest(
|
|
92
|
-
HttpMethod.delete,
|
|
93
|
-
self.http.with_endpoint(self.name.plural),
|
|
94
|
-
),
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
@dataclass(frozen=True)
|
|
99
|
-
class RestCollection(RestResource):
|
|
100
|
-
def sub_resource(self, name: str) -> RestItem:
|
|
101
|
-
return RestItem(self.http.with_endpoint(self.name.plural), RestfulName(name))
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
@dataclass(frozen=True)
|
|
105
|
-
class RestItem(RestResource):
|
|
106
|
-
def sub_resource(self, name: str) -> RestItem:
|
|
107
|
-
return RestItem(self.http.with_endpoint(self.name.singular), RestfulName(name))
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
@dataclass
|
|
111
|
-
class RestfulName:
|
|
112
|
-
singular: str
|
|
113
|
-
|
|
114
|
-
plural: str = ""
|
|
115
|
-
|
|
116
|
-
def __post_init__(self) -> None:
|
|
117
|
-
self.plural = self.plural or as_plural(self.singular)
|
|
118
|
-
|
|
119
|
-
def __add__(self, other: str) -> str:
|
|
120
|
-
return HttpUrl(self.plural) + other
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def as_plural(singular: str) -> str:
|
|
124
|
-
suffixes = {
|
|
125
|
-
"y": "ies",
|
|
126
|
-
"ch": "ches",
|
|
127
|
-
"sh": "shes",
|
|
128
|
-
"s": "ses",
|
|
129
|
-
"z": "zes",
|
|
130
|
-
"x": "xes",
|
|
131
|
-
"fe": "ves",
|
|
132
|
-
"f": "ves",
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
for singular_suffix, plural_suffix in suffixes.items():
|
|
136
|
-
if singular.endswith(singular_suffix):
|
|
137
|
-
return singular.removesuffix(singular_suffix) + plural_suffix
|
|
138
|
-
|
|
139
|
-
return singular + "s"
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
@dataclass
|
|
143
|
-
class HttpRequest:
|
|
144
|
-
method: HttpMethod
|
|
145
|
-
http: Http
|
|
146
|
-
|
|
147
|
-
def with_endpoint(self, value: Any) -> HttpRequest:
|
|
148
|
-
self.http = self.http.with_endpoint(str(value))
|
|
149
|
-
|
|
150
|
-
return self
|
|
151
|
-
|
|
152
|
-
def with_param(self, name: str, value: Any) -> HttpRequest:
|
|
153
|
-
self.http = self.http.with_param(name, value)
|
|
154
|
-
|
|
155
|
-
return self
|
|
156
|
-
|
|
157
|
-
def with_json(self, value: JsonDict) -> HttpRequest:
|
|
158
|
-
self.http = self.http.with_json(value)
|
|
159
|
-
|
|
160
|
-
return self
|
|
161
|
-
|
|
162
|
-
def __call__(self) -> HttpResponse:
|
|
163
|
-
return self.http.request(self.method)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
@dataclass
|
|
167
|
-
class RestRequest:
|
|
168
|
-
resource: RestfulName
|
|
169
|
-
request: HttpRequest
|
|
170
|
-
|
|
171
|
-
def with_id(self, value: Any) -> Self:
|
|
172
|
-
self.request = self.request.with_endpoint(value)
|
|
173
|
-
|
|
174
|
-
return self
|
|
175
|
-
|
|
176
|
-
def from_collection(self, value: list[JsonDict]) -> Self:
|
|
177
|
-
return self.with_data(
|
|
178
|
-
JsonDict({self.resource.plural: [dict(item) for item in value]})
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
def and_data(self, value: JsonDict) -> Self:
|
|
182
|
-
return self.with_data(value)
|
|
183
|
-
|
|
184
|
-
def from_data(self, value: JsonDict) -> Self:
|
|
185
|
-
return self.with_data(value)
|
|
186
|
-
|
|
187
|
-
def with_data(self, value: JsonDict) -> Self:
|
|
188
|
-
self.request = self.request.with_json(value)
|
|
189
|
-
|
|
190
|
-
return self
|
|
191
|
-
|
|
192
|
-
def and_param(self, name: str, value: Any) -> Self:
|
|
193
|
-
return self.with_param(name, value)
|
|
194
|
-
|
|
195
|
-
def with_param(self, name: str, value: Any) -> Self:
|
|
196
|
-
self.request = self.request.with_param(name, str(value))
|
|
197
|
-
|
|
198
|
-
return self
|
|
199
|
-
|
|
200
|
-
@cached_property
|
|
201
|
-
def response(self) -> HttpResponse:
|
|
202
|
-
return self.request()
|
|
203
|
-
|
|
204
|
-
def unpack(self) -> JsonDict:
|
|
205
|
-
return JsonDict(self.response.json()["data"][self.resource.singular])
|
|
206
|
-
|
|
207
|
-
def unpack_many(self) -> Iterable[JsonDict]:
|
|
208
|
-
items = self.response.json()["data"][self.resource.plural]
|
|
209
|
-
|
|
210
|
-
return [JsonDict(item) for item in items]
|
|
211
|
-
|
|
212
|
-
def ensure(self) -> RestResponse:
|
|
213
|
-
return RestResponse(
|
|
214
|
-
resource=self.resource,
|
|
215
|
-
json=JsonDict(self.response.json()),
|
|
216
|
-
http_code=self.response.code(),
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
@dataclass
|
|
221
|
-
class RestResponse:
|
|
222
|
-
resource: RestfulName
|
|
223
|
-
json: JsonDict
|
|
224
|
-
http_code: int
|
|
225
|
-
|
|
226
|
-
def fail(self) -> Self:
|
|
227
|
-
if self.http_code == 422:
|
|
228
|
-
return self
|
|
229
|
-
|
|
230
|
-
return self.with_status("fail")
|
|
231
|
-
|
|
232
|
-
def success(self) -> Self:
|
|
233
|
-
return self.with_status("success")
|
|
234
|
-
|
|
235
|
-
def with_status(self, value: str) -> Self:
|
|
236
|
-
assert self.json.value_of("status").to(str) == value
|
|
237
|
-
|
|
238
|
-
return self
|
|
239
|
-
|
|
240
|
-
def with_code(self, value: int) -> Self:
|
|
241
|
-
assert self.http_code == value
|
|
242
|
-
|
|
243
|
-
if self.http_code != 422:
|
|
244
|
-
assert self.json.value_of("code").to(int) == value
|
|
245
|
-
|
|
246
|
-
return self
|
|
247
|
-
|
|
248
|
-
def message(self, value: str) -> Self:
|
|
249
|
-
return self.with_message(value)
|
|
250
|
-
|
|
251
|
-
def and_message(self, value: str) -> Self:
|
|
252
|
-
return self.with_message(value)
|
|
253
|
-
|
|
254
|
-
def with_message(self, value: str) -> Self:
|
|
255
|
-
assert self.json.value_of("error").to(dict) == {"message": value}, self.json
|
|
256
|
-
|
|
257
|
-
return self
|
|
258
|
-
|
|
259
|
-
def and_item(self, value: Any) -> Self:
|
|
260
|
-
return self.with_item(value)
|
|
261
|
-
|
|
262
|
-
def with_item(self, value: Any) -> Self:
|
|
263
|
-
return self.with_data(**{self.resource.singular: value})
|
|
264
|
-
|
|
265
|
-
def and_collection(self, value: list[Any]) -> Self:
|
|
266
|
-
return self.with_collection(value)
|
|
267
|
-
|
|
268
|
-
def with_collection(self, values: list[Any]) -> Self:
|
|
269
|
-
return self.with_data(**{self.resource.plural: values}, count=len(values))
|
|
270
|
-
|
|
271
|
-
def and_no_data(self) -> Self:
|
|
272
|
-
return self.no_data()
|
|
273
|
-
|
|
274
|
-
def no_data(self) -> Self:
|
|
275
|
-
return self.with_data()
|
|
276
|
-
|
|
277
|
-
def with_data(self, **kwargs: Any) -> Self:
|
|
278
|
-
assert self.json.value_of("data").to(dict) == {**kwargs}, self.json
|
|
279
|
-
|
|
280
|
-
return self
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|