apexdevkit 1.25.3__tar.gz → 1.26.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.25.3 → apexdevkit-1.26.1}/PKG-INFO +1 -1
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/builder.py +4 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/dependable.py +23 -18
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/schema.py +23 -20
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/pyproject.toml +2 -2
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/LICENSE +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/README.md +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/__init__.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/annotation/deprecate.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/date.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/environment.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/error.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/name.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/resource.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/response.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/router.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fastapi/service.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/fluent.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/formatter.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/http/__init__.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/http/fake.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/http/fluent.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/http/httpx/__init__.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/http/httpx/client.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/http/httpx/hooks.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/http/json.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/http/url.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/id.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/key_fn.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/py.typed +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/query/__init__.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/query/generator.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/query/query.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/__init__.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/base.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/connector.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/database.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/decorator.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/in_memory.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/interface.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/mssql.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/repository.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/sql.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/repository/sqlite.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/server.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/synchronization.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/testing/__init__.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/testing/database.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/testing/fake.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/testing/rest.py +0 -0
- {apexdevkit-1.25.3 → apexdevkit-1.26.1}/apexdevkit/value.py +0 -0
|
@@ -10,6 +10,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
|
10
10
|
from fastapi.responses import JSONResponse
|
|
11
11
|
|
|
12
12
|
from apexdevkit.error import ApiError
|
|
13
|
+
from apexdevkit.fastapi.dependable import DependableBuilder
|
|
13
14
|
from apexdevkit.fastapi.service import RestfulService
|
|
14
15
|
|
|
15
16
|
|
|
@@ -86,6 +87,9 @@ class RestfulServiceBuilder(ABC):
|
|
|
86
87
|
parent_id: str = field(init=False)
|
|
87
88
|
user: Any = field(init=False)
|
|
88
89
|
|
|
90
|
+
def as_dependable(self) -> DependableBuilder:
|
|
91
|
+
return DependableBuilder.from_builder(self)
|
|
92
|
+
|
|
89
93
|
def with_user(self, user: Any) -> RestfulServiceBuilder:
|
|
90
94
|
self.user = user
|
|
91
95
|
|
|
@@ -6,8 +6,6 @@ from fastapi import Depends, Path
|
|
|
6
6
|
from fastapi.requests import Request
|
|
7
7
|
|
|
8
8
|
from apexdevkit.error import ApiError, DoesNotExistError, ForbiddenError
|
|
9
|
-
from apexdevkit.fastapi import RestfulServiceBuilder
|
|
10
|
-
from apexdevkit.fastapi.builder import PreBuilt
|
|
11
9
|
from apexdevkit.fastapi.name import RestfulName
|
|
12
10
|
from apexdevkit.fastapi.response import RestfulResponse
|
|
13
11
|
from apexdevkit.fastapi.service import RestfulService
|
|
@@ -20,8 +18,19 @@ def inject(dependency: str) -> Any: # pragma: no cover
|
|
|
20
18
|
return Depends(get)
|
|
21
19
|
|
|
22
20
|
|
|
21
|
+
class _ServiceBuilder(Protocol):
|
|
22
|
+
def with_user(self, user: Any) -> "_ServiceBuilder":
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def with_parent(self, identity: str) -> "_ServiceBuilder":
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
def build(self) -> RestfulService: # pragma: no cover
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
23
32
|
class _Dependency(Protocol):
|
|
24
|
-
def as_dependable(self) -> type[
|
|
33
|
+
def as_dependable(self) -> type[_ServiceBuilder]:
|
|
25
34
|
pass
|
|
26
35
|
|
|
27
36
|
|
|
@@ -48,19 +57,19 @@ class ParentDependency:
|
|
|
48
57
|
parent: RestfulName
|
|
49
58
|
dependency: _Dependency
|
|
50
59
|
|
|
51
|
-
def as_dependable(self) -> type[
|
|
60
|
+
def as_dependable(self) -> type[_ServiceBuilder]:
|
|
52
61
|
Builder = self.dependency.as_dependable()
|
|
53
62
|
ParentId = Annotated[
|
|
54
63
|
str, Path(alias=self.parent.singular.replace("-", "_") + "_id")
|
|
55
64
|
]
|
|
56
65
|
|
|
57
|
-
def _(builder: Builder, parent_id: ParentId) ->
|
|
66
|
+
def _(builder: Builder, parent_id: ParentId) -> _ServiceBuilder:
|
|
58
67
|
try:
|
|
59
68
|
return builder.with_parent(parent_id)
|
|
60
69
|
except DoesNotExistError as e:
|
|
61
70
|
raise ApiError(404, RestfulResponse(self.parent).not_found(e)) from e
|
|
62
71
|
|
|
63
|
-
return Annotated[
|
|
72
|
+
return Annotated[_ServiceBuilder, Depends(_)]
|
|
64
73
|
|
|
65
74
|
|
|
66
75
|
@dataclass(frozen=True)
|
|
@@ -68,28 +77,28 @@ class UserDependency:
|
|
|
68
77
|
extract_user: Callable[..., Any]
|
|
69
78
|
dependency: _Dependency
|
|
70
79
|
|
|
71
|
-
def as_dependable(self) -> type[
|
|
80
|
+
def as_dependable(self) -> type[_ServiceBuilder]:
|
|
72
81
|
Builder = self.dependency.as_dependable()
|
|
73
82
|
User = Annotated[Any, Depends(self.extract_user)]
|
|
74
83
|
|
|
75
|
-
def _(builder: Builder, user: User) ->
|
|
84
|
+
def _(builder: Builder, user: User) -> _ServiceBuilder:
|
|
76
85
|
return builder.with_user(user)
|
|
77
86
|
|
|
78
|
-
return Annotated[
|
|
87
|
+
return Annotated[_ServiceBuilder, Depends(_)]
|
|
79
88
|
|
|
80
89
|
|
|
81
|
-
_BuilderCallable = Callable[...,
|
|
90
|
+
_BuilderCallable = Callable[..., _ServiceBuilder]
|
|
82
91
|
|
|
83
92
|
|
|
84
93
|
@dataclass(frozen=True)
|
|
85
94
|
class BuilderCallableDependency:
|
|
86
95
|
create_builder: _BuilderCallable
|
|
87
96
|
|
|
88
|
-
def as_dependable(self) -> type[
|
|
89
|
-
def _() ->
|
|
97
|
+
def as_dependable(self) -> type[_ServiceBuilder]:
|
|
98
|
+
def _() -> _ServiceBuilder:
|
|
90
99
|
return self.create_builder()
|
|
91
100
|
|
|
92
|
-
return Annotated[
|
|
101
|
+
return Annotated[_ServiceBuilder, Depends(_)]
|
|
93
102
|
|
|
94
103
|
|
|
95
104
|
@dataclass(frozen=True)
|
|
@@ -101,13 +110,9 @@ class DependableBuilder:
|
|
|
101
110
|
return cls(BuilderCallableDependency(value))
|
|
102
111
|
|
|
103
112
|
@classmethod
|
|
104
|
-
def from_builder(cls, value:
|
|
113
|
+
def from_builder(cls, value: _ServiceBuilder) -> "DependableBuilder":
|
|
105
114
|
return cls(BuilderCallableDependency(lambda: value))
|
|
106
115
|
|
|
107
|
-
@classmethod
|
|
108
|
-
def from_service(cls, value: RestfulService) -> "DependableBuilder":
|
|
109
|
-
return cls(BuilderCallableDependency(lambda: PreBuilt(value)))
|
|
110
|
-
|
|
111
116
|
def with_parent(self, value: RestfulName) -> "DependableBuilder":
|
|
112
117
|
return DependableBuilder(ParentDependency(value, self.dependency))
|
|
113
118
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from collections.abc import Callable, Iterable
|
|
2
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from functools import cached_property
|
|
5
5
|
from typing import Any
|
|
@@ -66,15 +66,18 @@ class RestfulSchema:
|
|
|
66
66
|
self._schema_for("ReplaceMany", {self.name.plural: list[replace_schema]})
|
|
67
67
|
|
|
68
68
|
def _schema_for(self, action: str, fields: dict[str, Any]) -> type[BaseModel]:
|
|
69
|
-
if action not in self.
|
|
70
|
-
self.
|
|
69
|
+
if action not in self._models:
|
|
70
|
+
self._models[action] = self.generator.schema_for(action, fields)
|
|
71
71
|
|
|
72
|
-
return self.
|
|
72
|
+
return self._models[action]
|
|
73
73
|
|
|
74
74
|
@cached_property
|
|
75
|
-
def
|
|
75
|
+
def _models(self) -> dict[str, type[BaseModel]]:
|
|
76
76
|
return {}
|
|
77
77
|
|
|
78
|
+
def __iter__(self) -> Iterator[type[BaseModel]]:
|
|
79
|
+
return iter(self._models.values())
|
|
80
|
+
|
|
78
81
|
def for_no_data(self) -> type[BaseModel]:
|
|
79
82
|
class NoData(BaseModel):
|
|
80
83
|
pass
|
|
@@ -90,7 +93,7 @@ class RestfulSchema:
|
|
|
90
93
|
FluentDict[type]()
|
|
91
94
|
.with_a(status=str)
|
|
92
95
|
.and_a(code=int)
|
|
93
|
-
.and_a(data=self.
|
|
96
|
+
.and_a(data=self._models["Item"]),
|
|
94
97
|
)
|
|
95
98
|
|
|
96
99
|
def for_collection(self) -> type[BaseModel]:
|
|
@@ -99,11 +102,11 @@ class RestfulSchema:
|
|
|
99
102
|
FluentDict[type]()
|
|
100
103
|
.with_a(status=str)
|
|
101
104
|
.and_a(code=int)
|
|
102
|
-
.and_a(data=self.
|
|
105
|
+
.and_a(data=self._models["Collection"]),
|
|
103
106
|
)
|
|
104
107
|
|
|
105
108
|
def for_create_one(self) -> Callable[[BaseModel], dict[str, Any]]:
|
|
106
|
-
schema = self.
|
|
109
|
+
schema = self._models["Create"]
|
|
107
110
|
|
|
108
111
|
def _(request: schema) -> dict[str, Any]:
|
|
109
112
|
return request.model_dump()
|
|
@@ -111,7 +114,7 @@ class RestfulSchema:
|
|
|
111
114
|
return _
|
|
112
115
|
|
|
113
116
|
def for_create_many(self) -> Callable[[BaseModel], Iterable[dict[str, Any]]]:
|
|
114
|
-
schema = self.
|
|
117
|
+
schema = self._models["CreateMany"]
|
|
115
118
|
|
|
116
119
|
def _(request: schema) -> Iterable[dict[str, Any]]:
|
|
117
120
|
return [dict(item) for item in request.model_dump()[self.name.plural]]
|
|
@@ -119,7 +122,7 @@ class RestfulSchema:
|
|
|
119
122
|
return _
|
|
120
123
|
|
|
121
124
|
def for_update_one(self) -> Callable[[BaseModel], dict[str, Any]]:
|
|
122
|
-
schema = self.
|
|
125
|
+
schema = self._models["Update"]
|
|
123
126
|
|
|
124
127
|
def _(request: schema):
|
|
125
128
|
return request.model_dump()
|
|
@@ -127,7 +130,7 @@ class RestfulSchema:
|
|
|
127
130
|
return _
|
|
128
131
|
|
|
129
132
|
def for_update_many(self) -> Callable[[BaseModel], Iterable[dict[str, Any]]]:
|
|
130
|
-
schema = self.
|
|
133
|
+
schema = self._models["UpdateMany"]
|
|
131
134
|
|
|
132
135
|
def _(request: schema) -> Iterable[dict[str, Any]]:
|
|
133
136
|
return [dict(item) for item in request.model_dump()[self.name.plural]]
|
|
@@ -135,7 +138,7 @@ class RestfulSchema:
|
|
|
135
138
|
return _
|
|
136
139
|
|
|
137
140
|
def for_replace_one(self) -> Callable[[BaseModel], dict[str, Any]]:
|
|
138
|
-
schema = self.
|
|
141
|
+
schema = self._models["Replace"]
|
|
139
142
|
|
|
140
143
|
def _(request: schema) -> dict[str, Any]:
|
|
141
144
|
return request.model_dump()
|
|
@@ -143,7 +146,7 @@ class RestfulSchema:
|
|
|
143
146
|
return _
|
|
144
147
|
|
|
145
148
|
def for_replace_many(self) -> Callable[[BaseModel], Iterable[dict[str, Any]]]:
|
|
146
|
-
schema = self.
|
|
149
|
+
schema = self._models["ReplaceMany"]
|
|
147
150
|
|
|
148
151
|
def _(request: schema) -> Iterable[dict[str, Any]]:
|
|
149
152
|
return [dict(item) for item in request.model_dump()[self.name.plural]]
|
|
@@ -151,7 +154,7 @@ class RestfulSchema:
|
|
|
151
154
|
return _
|
|
152
155
|
|
|
153
156
|
def for_filters(self) -> Callable[[BaseModel], dict[str, Any]]:
|
|
154
|
-
schema = self.
|
|
157
|
+
schema = self._models["Filter"]
|
|
155
158
|
|
|
156
159
|
def _(request: schema) -> dict[str, Any]:
|
|
157
160
|
return request.model_dump()
|
|
@@ -159,7 +162,7 @@ class RestfulSchema:
|
|
|
159
162
|
return _
|
|
160
163
|
|
|
161
164
|
def for_aggregation(self) -> Callable[[BaseModel], dict[str, Any]]:
|
|
162
|
-
schema = self.
|
|
165
|
+
schema = self._models["Aggregation"]
|
|
163
166
|
|
|
164
167
|
def _(request: schema) -> dict[str, Any]:
|
|
165
168
|
return request.model_dump()
|
|
@@ -172,7 +175,7 @@ class RestfulSchema:
|
|
|
172
175
|
FluentDict[type]()
|
|
173
176
|
.with_a(status=str)
|
|
174
177
|
.and_a(code=int)
|
|
175
|
-
.and_a(aggregations=self.
|
|
178
|
+
.and_a(aggregations=self._models["AggregationResult"]),
|
|
176
179
|
)
|
|
177
180
|
|
|
178
181
|
|
|
@@ -199,11 +202,11 @@ class Schema:
|
|
|
199
202
|
|
|
200
203
|
for field_name, field_type in fields.items():
|
|
201
204
|
if isinstance(field_type, dict):
|
|
202
|
-
model_fields[field_name] = (
|
|
203
|
-
|
|
204
|
-
|
|
205
|
+
model_fields[field_name] = self._nested_schema_for(
|
|
206
|
+
name + field_name.capitalize(),
|
|
207
|
+
field_type,
|
|
205
208
|
)
|
|
206
209
|
else:
|
|
207
|
-
model_fields[field_name] =
|
|
210
|
+
model_fields[field_name] = field_type
|
|
208
211
|
|
|
209
212
|
return create_model(name, **model_fields)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "apexdevkit"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.26.1"
|
|
4
4
|
description = "Apex Development Tools for python."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -18,7 +18,7 @@ python-dotenv = "*"
|
|
|
18
18
|
pymssql = "2.3.2"
|
|
19
19
|
|
|
20
20
|
[tool.poetry.group.dev.dependencies]
|
|
21
|
-
approvaltests = "
|
|
21
|
+
approvaltests = "17.3.0" # pinned because later version has a bug.
|
|
22
22
|
pytest = "*"
|
|
23
23
|
pytest-approvaltests = "*"
|
|
24
24
|
pytest-cov = "*"
|
|
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
|
|
File without changes
|