apexdevkit 2.0.1__tar.gz → 2.0.2__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-2.0.1 → apexdevkit-2.0.2}/PKG-INFO +2 -2
- apexdevkit-2.0.2/apexdevkit/testing.py +157 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/pyproject.toml +2 -2
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/LICENSE +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/README.md +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/annotation/deprecate.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/date.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/error.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/builder.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/dependable.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/name.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/resource.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/response.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/router.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/schema.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/fastapi/service.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/formatter.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/key_fn.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/py.typed +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/query/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/query/generator.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/query/query.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/database.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/decorator.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/interface.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/core/mixin.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/in_memory/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/in_memory/mixin.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/in_memory/repository.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/in_memory/store.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/connector.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/field.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/mssql/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/mssql/repository.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/mssql/table.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/sqlite/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/sqlite/repository.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/repository/sql/sqlite/table.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/server.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/sync/__init__.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/sync/observer.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/sync/source.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/sync/sync.py +0 -0
- {apexdevkit-2.0.1 → apexdevkit-2.0.2}/apexdevkit/sync/target.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apexdevkit
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Apex Development Tools for python.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Author: Apex Dev
|
|
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
13
13
|
Requires-Dist: fastapi
|
|
14
14
|
Requires-Dist: pydantic
|
|
15
15
|
Requires-Dist: pymssql (==2.*)
|
|
16
|
-
Requires-Dist: pypebbles (==0.
|
|
16
|
+
Requires-Dist: pypebbles (==0.3.*)
|
|
17
17
|
Requires-Dist: python-dotenv
|
|
18
18
|
Requires-Dist: sentry-sdk[fastapi]
|
|
19
19
|
Requires-Dist: uvicorn
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Collection
|
|
4
|
+
from dataclasses import dataclass, field, replace
|
|
5
|
+
from typing import Any, Self
|
|
6
|
+
|
|
7
|
+
from pypebbles import JsonDict
|
|
8
|
+
from pypebbles.http import (
|
|
9
|
+
HttpDispatcher,
|
|
10
|
+
HttpMethod,
|
|
11
|
+
HttpRequest,
|
|
12
|
+
HttpResponse,
|
|
13
|
+
HttpTransport,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from apexdevkit.fastapi.name import RestfulName
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class RestRequest:
|
|
21
|
+
request: HttpRequest = HttpRequest()
|
|
22
|
+
|
|
23
|
+
def with_params(self, **params: Any) -> RestRequest:
|
|
24
|
+
return replace(self, request=self.request.with_params(params))
|
|
25
|
+
|
|
26
|
+
def with_data(self, value: JsonDict) -> RestRequest:
|
|
27
|
+
return replace(self, request=self.request.with_json(value))
|
|
28
|
+
|
|
29
|
+
def sub_resource(self, name: RestfulName) -> RestRequest:
|
|
30
|
+
return replace(self, request=self.request.with_endpoint(name.plural))
|
|
31
|
+
|
|
32
|
+
def item(self, with_id: Any) -> RestRequest:
|
|
33
|
+
return replace(self, request=self.request.with_endpoint(str(with_id)))
|
|
34
|
+
|
|
35
|
+
def using(self, transport: RestTransport) -> RestDispatcher:
|
|
36
|
+
return RestDispatcher(request=self.request, transport=transport)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class RestTransport:
|
|
41
|
+
resource: RestfulName
|
|
42
|
+
transport: HttpTransport[HttpResponse]
|
|
43
|
+
|
|
44
|
+
def deliver(self, request: HttpRequest, using: HttpMethod) -> StatusProbe:
|
|
45
|
+
return StatusProbe(
|
|
46
|
+
resource=self.resource,
|
|
47
|
+
response=self.transport.deliver(request, using),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(frozen=True)
|
|
52
|
+
class RestResponse:
|
|
53
|
+
resource: RestfulName
|
|
54
|
+
|
|
55
|
+
raw: JsonDict = field(default_factory=JsonDict)
|
|
56
|
+
|
|
57
|
+
def __call__(self, raw: JsonDict) -> RestResponse:
|
|
58
|
+
return replace(self, raw=raw)
|
|
59
|
+
|
|
60
|
+
def status(self) -> str:
|
|
61
|
+
return self.raw.value_of("status").to(str)
|
|
62
|
+
|
|
63
|
+
def code(self) -> int:
|
|
64
|
+
return self.raw.value_of("code").to(int)
|
|
65
|
+
|
|
66
|
+
def message(self) -> str:
|
|
67
|
+
return self.error().value_of("message").to(str)
|
|
68
|
+
|
|
69
|
+
def error(self) -> JsonDict:
|
|
70
|
+
return self.raw.value_of("error").to(JsonDict)
|
|
71
|
+
|
|
72
|
+
def item(self) -> JsonDict:
|
|
73
|
+
return self.data().value_of(self.resource.singular).to(JsonDict)
|
|
74
|
+
|
|
75
|
+
def collection(self) -> Collection[JsonDict]:
|
|
76
|
+
return self.data().value_of(self.resource.plural).to(list)
|
|
77
|
+
|
|
78
|
+
def count(self) -> int:
|
|
79
|
+
return self.data().value_of("count").to(int)
|
|
80
|
+
|
|
81
|
+
def data(self) -> JsonDict:
|
|
82
|
+
return self.raw.value_of("data").to(JsonDict)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass(frozen=True)
|
|
86
|
+
class StatusProbe:
|
|
87
|
+
resource: RestfulName
|
|
88
|
+
response: HttpResponse
|
|
89
|
+
|
|
90
|
+
def ensure(self, http_code: int) -> ResponseProbe:
|
|
91
|
+
assert self.response.status == http_code
|
|
92
|
+
|
|
93
|
+
return ResponseProbe(self.response.load(RestResponse(self.resource)))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass(frozen=True)
|
|
97
|
+
class ResponseProbe:
|
|
98
|
+
response: RestResponse
|
|
99
|
+
|
|
100
|
+
def and_api_fail(self) -> Self:
|
|
101
|
+
return self.with_status("fail")
|
|
102
|
+
|
|
103
|
+
def and_api_success(self) -> Self:
|
|
104
|
+
return self.with_status("success")
|
|
105
|
+
|
|
106
|
+
def with_status(self, value: str) -> Self:
|
|
107
|
+
assert self.response.status() == value
|
|
108
|
+
|
|
109
|
+
return self
|
|
110
|
+
|
|
111
|
+
def with_code(self, value: int) -> Self:
|
|
112
|
+
assert self.response.code() == value
|
|
113
|
+
|
|
114
|
+
return self
|
|
115
|
+
|
|
116
|
+
def and_message(self, value: str) -> Self:
|
|
117
|
+
return self.with_message(value)
|
|
118
|
+
|
|
119
|
+
def with_message(self, value: str) -> Self:
|
|
120
|
+
assert self.response.message() == value, self.response.raw
|
|
121
|
+
|
|
122
|
+
return self
|
|
123
|
+
|
|
124
|
+
def and_item(self, value: Any) -> Self:
|
|
125
|
+
return self.with_item(value)
|
|
126
|
+
|
|
127
|
+
def with_item(self, value: Any) -> Self:
|
|
128
|
+
assert self.response.item() == value, self.response.raw
|
|
129
|
+
|
|
130
|
+
return self
|
|
131
|
+
|
|
132
|
+
def and_collection(self, values: Collection[Any]) -> Self:
|
|
133
|
+
return self.with_collection(values)
|
|
134
|
+
|
|
135
|
+
def with_collection(self, values: Collection[Any]) -> Self:
|
|
136
|
+
assert self.response.collection() == values, self.response.raw
|
|
137
|
+
assert self.response.count() == len(values)
|
|
138
|
+
|
|
139
|
+
return self
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@dataclass(frozen=True)
|
|
143
|
+
class RestDispatcher(HttpDispatcher[StatusProbe]):
|
|
144
|
+
def create(self) -> StatusProbe:
|
|
145
|
+
return self.dispatch(HttpMethod.post)
|
|
146
|
+
|
|
147
|
+
def read(self) -> StatusProbe:
|
|
148
|
+
return self.dispatch(HttpMethod.get)
|
|
149
|
+
|
|
150
|
+
def update(self) -> StatusProbe:
|
|
151
|
+
return self.dispatch(HttpMethod.patch)
|
|
152
|
+
|
|
153
|
+
def delete(self) -> StatusProbe:
|
|
154
|
+
return self.dispatch(HttpMethod.delete)
|
|
155
|
+
|
|
156
|
+
def replace(self) -> StatusProbe:
|
|
157
|
+
return self.dispatch(HttpMethod.put)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "apexdevkit"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.2"
|
|
4
4
|
description = "Apex Development Tools for python."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -16,7 +16,7 @@ pymssql = "2.*"
|
|
|
16
16
|
pydantic = "*"
|
|
17
17
|
sentry-sdk = { extras = ["fastapi"], version = "*" }
|
|
18
18
|
uvicorn = "*"
|
|
19
|
-
pypebbles = "0.
|
|
19
|
+
pypebbles = "0.3.*"
|
|
20
20
|
|
|
21
21
|
[tool.poetry.group.dev.dependencies]
|
|
22
22
|
apexcodexpy = "0.7.1"
|
|
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
|
|
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
|