apexdevkit 1.22.2__tar.gz → 1.23.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.22.2 → apexdevkit-1.23.1}/PKG-INFO +2 -2
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/annotation/deprecate.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/error.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/builder.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/dependable.py +3 -2
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/resource.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/response.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/schema.py +6 -5
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/service.py +4 -4
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fluent.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/formatter.py +2 -3
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/http/fluent.py +5 -5
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/http/httpx/client.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/query/generator.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/query/query.py +1 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/base.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/connector.py +5 -5
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/database.py +4 -2
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/decorator.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/in_memory.py +6 -5
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/interface.py +2 -2
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/mssql.py +9 -10
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/repository.py +18 -5
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/sql.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/sqlite.py +6 -5
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/server.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/synchronization.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/testing/database.py +3 -3
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/testing/fake.py +13 -13
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/testing/rest.py +2 -1
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/pyproject.toml +18 -12
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/LICENSE +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/README.md +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/__init__.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/annotation/__init__.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/environment.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/__init__.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/docs.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/name.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/request.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/fastapi/router.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/http/__init__.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/http/fake.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/http/httpx/__init__.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/http/httpx/hooks.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/http/json.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/http/url.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/id.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/key_fn.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/py.typed +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/query/__init__.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/repository/__init__.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/testing/__init__.py +0 -0
- {apexdevkit-1.22.2 → apexdevkit-1.23.1}/apexdevkit/value.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: apexdevkit
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.23.1
|
|
4
4
|
Summary: Apex Development Tools for python.
|
|
5
5
|
Author: Apex Dev
|
|
6
6
|
Author-email: dev@apex.ge
|
|
7
|
-
Requires-Python: >=3.11
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
+
from collections.abc import Mapping
|
|
4
5
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Self
|
|
6
7
|
|
|
7
8
|
from fastapi import APIRouter, FastAPI
|
|
8
9
|
from starlette.middleware.cors import CORSMiddleware
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
1
2
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Annotated, Any,
|
|
3
|
+
from typing import Annotated, Any, Protocol
|
|
3
4
|
|
|
4
5
|
from fastapi import Depends, Path
|
|
5
6
|
from fastapi.requests import Request
|
|
@@ -52,7 +53,7 @@ class ParentDependency:
|
|
|
52
53
|
try:
|
|
53
54
|
return builder.with_parent(parent_id)
|
|
54
55
|
except DoesNotExistError as e:
|
|
55
|
-
raise ApiError(404, RestfulResponse(self.parent).not_found(e))
|
|
56
|
+
raise ApiError(404, RestfulResponse(self.parent).not_found(e)) from e
|
|
56
57
|
|
|
57
58
|
return Annotated[RestfulServiceBuilder, Depends(_)]
|
|
58
59
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
+
from collections.abc import Callable, Iterable
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from functools import cached_property
|
|
4
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
5
6
|
|
|
6
7
|
from pydantic import BaseModel, create_model
|
|
7
8
|
|
|
@@ -39,10 +40,10 @@ class RestfulSchema:
|
|
|
39
40
|
)
|
|
40
41
|
|
|
41
42
|
self._schema_for("Item", {self.name.singular: schema})
|
|
42
|
-
self._schema_for("Collection", {self.name.plural:
|
|
43
|
-
self._schema_for("CreateMany", {self.name.plural:
|
|
44
|
-
self._schema_for("UpdateMany", {self.name.plural:
|
|
45
|
-
self._schema_for("ReplaceMany", {self.name.plural:
|
|
43
|
+
self._schema_for("Collection", {self.name.plural: list[schema], "count": int})
|
|
44
|
+
self._schema_for("CreateMany", {self.name.plural: list[create_schema]})
|
|
45
|
+
self._schema_for("UpdateMany", {self.name.plural: list[update_many_item]})
|
|
46
|
+
self._schema_for("ReplaceMany", {self.name.plural: list[replace_schema]})
|
|
46
47
|
|
|
47
48
|
def _schema_for(self, action: str, fields: dict[str, Any]) -> type[BaseModel]:
|
|
48
49
|
if action not in self.schemas:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from abc import
|
|
3
|
+
from collections.abc import Iterable, Mapping
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from functools import cached_property
|
|
6
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Generic, TypeVar
|
|
7
7
|
|
|
8
8
|
from apexdevkit.formatter import Formatter
|
|
9
9
|
from apexdevkit.query.query import FooterOptions, QueryOptions, Summary
|
|
@@ -14,7 +14,7 @@ RawItem = Mapping[str, Any]
|
|
|
14
14
|
RawCollection = Iterable[RawItem]
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class _RawItemWithId(
|
|
17
|
+
class _RawItemWithId(dict[str, Any]):
|
|
18
18
|
def __post_init__(self) -> None:
|
|
19
19
|
assert "id" in self
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ class _RawItemWithId(Dict[str, Any]):
|
|
|
22
22
|
RawCollectionWithId = Iterable[_RawItemWithId]
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
class RestfulService
|
|
25
|
+
class RestfulService: # pragma: no cover
|
|
26
26
|
def create_one(self, item: RawItem) -> RawItem:
|
|
27
27
|
raise NotImplementedError(self.create_one.__name__)
|
|
28
28
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import pickle
|
|
4
|
+
from collections.abc import Mapping
|
|
4
5
|
from copy import deepcopy
|
|
5
6
|
from dataclasses import asdict, dataclass, field, fields, is_dataclass
|
|
6
|
-
from typing import Any, Generic,
|
|
7
|
-
|
|
8
|
-
from typing_extensions import get_type_hints
|
|
7
|
+
from typing import Any, Generic, Protocol, Self, TypeVar, get_args, get_type_hints
|
|
9
8
|
|
|
10
9
|
from apexdevkit.fluent import FluentDict
|
|
11
10
|
from apexdevkit.value import Value
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from enum import Enum, auto
|
|
5
|
-
from typing import Any, Protocol
|
|
5
|
+
from typing import Any, Protocol
|
|
6
6
|
|
|
7
7
|
from apexdevkit.http.json import JsonDict
|
|
8
8
|
|
|
@@ -103,25 +103,25 @@ class FluentHttpRequest:
|
|
|
103
103
|
class FluentHttpResponse:
|
|
104
104
|
response: HttpResponse
|
|
105
105
|
|
|
106
|
-
def on_bad_request(self, raises: Exception |
|
|
106
|
+
def on_bad_request(self, raises: Exception | type[Exception]) -> FluentHttpResponse:
|
|
107
107
|
if self.response.code() == 400:
|
|
108
108
|
raise raises
|
|
109
109
|
|
|
110
110
|
return self
|
|
111
111
|
|
|
112
|
-
def on_conflict(self, raises: Exception |
|
|
112
|
+
def on_conflict(self, raises: Exception | type[Exception]) -> FluentHttpResponse:
|
|
113
113
|
if self.response.code() == 409:
|
|
114
114
|
raise raises
|
|
115
115
|
|
|
116
116
|
return self
|
|
117
117
|
|
|
118
|
-
def on_not_found(self, raises: Exception |
|
|
118
|
+
def on_not_found(self, raises: Exception | type[Exception]) -> FluentHttpResponse:
|
|
119
119
|
if self.response.code() == 404:
|
|
120
120
|
raise raises
|
|
121
121
|
|
|
122
122
|
return self
|
|
123
123
|
|
|
124
|
-
def on_failure(self, raises:
|
|
124
|
+
def on_failure(self, raises: type[Exception]) -> FluentHttpResponse:
|
|
125
125
|
if self.response.code() < 200 or self.response.code() > 299:
|
|
126
126
|
raise raises(self.response.raw(), self.response.code())
|
|
127
127
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections import defaultdict
|
|
4
|
+
from collections.abc import Iterable, Mapping
|
|
4
5
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Any, ClassVar, Generic,
|
|
6
|
+
from typing import Any, ClassVar, Generic, Protocol, TypeVar
|
|
6
7
|
|
|
7
8
|
from apexdevkit.annotation import deprecated
|
|
8
9
|
from apexdevkit.error import ForbiddenError
|
|
@@ -59,7 +59,7 @@ class SummaryExtractor:
|
|
|
59
59
|
def _value(self, value: Any) -> NumericValue | DateValue | StringValue | NullValue:
|
|
60
60
|
if value is None:
|
|
61
61
|
return NullValue()
|
|
62
|
-
if isinstance(value,
|
|
62
|
+
if isinstance(value, int | float | Decimal):
|
|
63
63
|
return NumericValue.from_decimal(Decimal(value))
|
|
64
64
|
if self.aggregation.name and (
|
|
65
65
|
"date" in self.aggregation.name.lower()
|
|
@@ -4,7 +4,7 @@ import sqlite3
|
|
|
4
4
|
from contextlib import AbstractContextManager
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from functools import cached_property
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
8
8
|
|
|
9
9
|
import pymssql
|
|
10
10
|
from pymssql import Connection as _Connection
|
|
@@ -17,7 +17,7 @@ from apexdevkit.repository import Connection
|
|
|
17
17
|
class SqliteFileConnector:
|
|
18
18
|
dsn: str
|
|
19
19
|
|
|
20
|
-
def connect(self) ->
|
|
20
|
+
def connect(self) -> AbstractContextManager[Connection]:
|
|
21
21
|
connection = sqlite3.connect(self.dsn)
|
|
22
22
|
connection.row_factory = sqlite3.Row
|
|
23
23
|
|
|
@@ -28,11 +28,11 @@ class SqliteFileConnector:
|
|
|
28
28
|
class SqliteInMemoryConnector:
|
|
29
29
|
dsn: str = ":memory:"
|
|
30
30
|
|
|
31
|
-
def connect(self) ->
|
|
31
|
+
def connect(self) -> AbstractContextManager[Connection]:
|
|
32
32
|
return self._connection
|
|
33
33
|
|
|
34
34
|
@cached_property
|
|
35
|
-
def _connection(self) ->
|
|
35
|
+
def _connection(self) -> AbstractContextManager[Connection]:
|
|
36
36
|
connection = sqlite3.connect(self.dsn, check_same_thread=False)
|
|
37
37
|
connection.row_factory = sqlite3.Row
|
|
38
38
|
|
|
@@ -48,7 +48,7 @@ class MsSqlConnector:
|
|
|
48
48
|
db_tds_version = "7.0"
|
|
49
49
|
db_port: str | None = None
|
|
50
50
|
|
|
51
|
-
def connect(self) ->
|
|
51
|
+
def connect(self) -> AbstractContextManager[Connection]:
|
|
52
52
|
return ConnectionContextManager(self._connection())
|
|
53
53
|
|
|
54
54
|
def _connection(self) -> Connection:
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Iterable, Mapping
|
|
4
|
+
from contextlib import AbstractContextManager
|
|
3
5
|
from copy import deepcopy
|
|
4
6
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Any,
|
|
7
|
+
from typing import Any, Protocol
|
|
6
8
|
|
|
7
9
|
_RawData = Mapping[str, Any]
|
|
8
10
|
|
|
@@ -45,7 +47,7 @@ class Database:
|
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
class Connector(Protocol): # pragma: no cover
|
|
48
|
-
def connect(self) ->
|
|
50
|
+
def connect(self) -> AbstractContextManager[Connection]:
|
|
49
51
|
pass
|
|
50
52
|
|
|
51
53
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
3
4
|
from contextlib import suppress
|
|
4
5
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Generic, Protocol, Self
|
|
6
7
|
|
|
7
8
|
from apexdevkit.error import DoesNotExistError, ExistsError
|
|
8
9
|
from apexdevkit.formatter import Formatter, PickleFormatter
|
|
@@ -131,14 +132,14 @@ class _SingleKeyRepository(RepositoryBase[ItemT]):
|
|
|
131
132
|
def delete(self, item_id: str) -> None:
|
|
132
133
|
try:
|
|
133
134
|
self.store.drop(item_id)
|
|
134
|
-
except KeyError:
|
|
135
|
-
raise DoesNotExistError(item_id)
|
|
135
|
+
except KeyError as e:
|
|
136
|
+
raise DoesNotExistError(item_id) from e
|
|
136
137
|
|
|
137
138
|
def read(self, item_id: str) -> ItemT:
|
|
138
139
|
try:
|
|
139
140
|
return self.store.get(item_id)
|
|
140
|
-
except KeyError:
|
|
141
|
-
raise DoesNotExistError(item_id)
|
|
141
|
+
except KeyError as e:
|
|
142
|
+
raise DoesNotExistError(item_id) from e
|
|
142
143
|
|
|
143
144
|
def __iter__(self) -> Iterator[ItemT]:
|
|
144
145
|
return iter(self.store.values())
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Iterable, Iterator, Mapping
|
|
3
4
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any, Generic,
|
|
5
|
+
from typing import Any, Generic, TypeVar
|
|
5
6
|
|
|
6
7
|
from pymssql.exceptions import DatabaseError, OperationalError
|
|
7
8
|
|
|
@@ -27,8 +28,8 @@ class MsSqlRepository(RepositoryBase[ItemT]):
|
|
|
27
28
|
|
|
28
29
|
try:
|
|
29
30
|
return int(raw["n_items"])
|
|
30
|
-
except KeyError:
|
|
31
|
-
raise UnknownError(raw)
|
|
31
|
+
except KeyError as e:
|
|
32
|
+
raise UnknownError(raw) from e
|
|
32
33
|
|
|
33
34
|
def delete(self, item_id: str) -> None:
|
|
34
35
|
self.db.execute(self.table.delete(item_id)).fetch_none()
|
|
@@ -40,19 +41,17 @@ class MsSqlRepository(RepositoryBase[ItemT]):
|
|
|
40
41
|
try:
|
|
41
42
|
return self.table.load(self.db.execute(self.table.insert(item)).fetch_one())
|
|
42
43
|
except DatabaseError as e:
|
|
43
|
-
|
|
44
|
+
if MssqlException(e).is_duplication():
|
|
45
|
+
raise self.table.exists(item) from e
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
raise self.table.exists(item)
|
|
47
|
-
|
|
48
|
-
raise UnknownError(e.message)
|
|
47
|
+
raise UnknownError(MssqlException(e).message) from e
|
|
49
48
|
|
|
50
49
|
def read(self, item_id: str) -> ItemT:
|
|
51
50
|
try:
|
|
52
51
|
raw = self.db.execute(self.table.select(item_id)).fetch_one()
|
|
53
52
|
except OperationalError as e:
|
|
54
53
|
if "Conversion failed" in str(e):
|
|
55
|
-
raise DoesNotExistError(item_id)
|
|
54
|
+
raise DoesNotExistError(item_id) from e
|
|
56
55
|
else:
|
|
57
56
|
raise e
|
|
58
57
|
|
|
@@ -273,7 +272,7 @@ class DefaultSqlTable(SqlTable[ItemT]):
|
|
|
273
272
|
[f"%({key.name})s" for key in self.fields if key.include_in_insert]
|
|
274
273
|
)
|
|
275
274
|
try:
|
|
276
|
-
self.fields.id
|
|
275
|
+
_ = self.fields.id
|
|
277
276
|
output = ", ".join(
|
|
278
277
|
["[" + field.name + "] AS " + field.name for field in self.fields]
|
|
279
278
|
)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Callable, Iterator
|
|
3
4
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import
|
|
5
|
+
from typing import Generic, TypeVar
|
|
5
6
|
|
|
6
7
|
from apexdevkit.error import DoesNotExistError
|
|
7
8
|
from apexdevkit.formatter import Formatter
|
|
@@ -75,22 +76,34 @@ class MultipleRepositoryBuilder(Generic[ItemT]):
|
|
|
75
76
|
self,
|
|
76
77
|
repository: Repository[ItemT],
|
|
77
78
|
condition: Callable[[ItemT], bool] = lambda item: True,
|
|
78
|
-
formatter: Formatter[ItemT, ItemT] =
|
|
79
|
+
formatter: Formatter[ItemT, ItemT] | None = None,
|
|
79
80
|
id_prefix: str = "",
|
|
80
81
|
) -> MultipleRepositoryBuilder[ItemT]:
|
|
81
82
|
return MultipleRepositoryBuilder[ItemT](
|
|
82
83
|
self.repositories
|
|
83
|
-
+ [
|
|
84
|
+
+ [
|
|
85
|
+
_InnerRepository(
|
|
86
|
+
repository,
|
|
87
|
+
condition,
|
|
88
|
+
formatter or NoFormatter[ItemT](),
|
|
89
|
+
id_prefix,
|
|
90
|
+
)
|
|
91
|
+
]
|
|
84
92
|
)
|
|
85
93
|
|
|
86
94
|
def and_repository(
|
|
87
95
|
self,
|
|
88
96
|
repository: Repository[ItemT],
|
|
89
97
|
condition: Callable[[ItemT], bool] = lambda item: True,
|
|
90
|
-
formatter: Formatter[ItemT, ItemT] =
|
|
98
|
+
formatter: Formatter[ItemT, ItemT] | None = None,
|
|
91
99
|
id_prefix: str = "",
|
|
92
100
|
) -> MultipleRepositoryBuilder[ItemT]:
|
|
93
|
-
return self.with_repository(
|
|
101
|
+
return self.with_repository(
|
|
102
|
+
repository,
|
|
103
|
+
condition,
|
|
104
|
+
formatter or NoFormatter[ItemT](),
|
|
105
|
+
id_prefix,
|
|
106
|
+
)
|
|
94
107
|
|
|
95
108
|
def build(self) -> MultipleRepository[ItemT]:
|
|
96
109
|
return MultipleRepository[ItemT](self.repositories)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Iterable, Iterator, Mapping
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
from sqlite3 import IntegrityError
|
|
5
|
-
from typing import Any, Generic
|
|
6
|
+
from typing import Any, Generic
|
|
6
7
|
|
|
7
8
|
from apexdevkit.error import DoesNotExistError, ExistsError
|
|
8
9
|
from apexdevkit.formatter import Formatter
|
|
@@ -28,8 +29,8 @@ class SqliteRepository(RepositoryBase[ItemT]):
|
|
|
28
29
|
|
|
29
30
|
try:
|
|
30
31
|
return int(raw["n_items"])
|
|
31
|
-
except KeyError:
|
|
32
|
-
raise UnknownError(raw)
|
|
32
|
+
except KeyError as e:
|
|
33
|
+
raise UnknownError(raw) from e
|
|
33
34
|
|
|
34
35
|
def create(self, item: ItemT) -> ItemT:
|
|
35
36
|
try:
|
|
@@ -183,7 +184,7 @@ class _DefaultSqlTable(SqlTable[ItemT]):
|
|
|
183
184
|
|
|
184
185
|
return DatabaseCommand(f"""
|
|
185
186
|
SELECT
|
|
186
|
-
{columns}
|
|
187
|
+
{columns}
|
|
187
188
|
FROM {self.table_name.upper()}
|
|
188
189
|
{self.fields.where_statement(include_id=True)};
|
|
189
190
|
""").with_data(self.fields.with_fixed({self.fields.id: item_id}))
|
|
@@ -198,7 +199,7 @@ class _DefaultSqlTable(SqlTable[ItemT]):
|
|
|
198
199
|
|
|
199
200
|
return DatabaseCommand(f"""
|
|
200
201
|
SELECT
|
|
201
|
-
{columns}
|
|
202
|
+
{columns}
|
|
202
203
|
FROM {self.table_name.upper()}
|
|
203
204
|
WHERE {duplicates};
|
|
204
205
|
""").with_data({key: raw[key] for key in raw if key in self.fields.composite})
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Iterable, Iterator
|
|
3
4
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Generic,
|
|
5
|
+
from typing import Generic, Protocol, TypeVar
|
|
5
6
|
|
|
6
7
|
ItemT = TypeVar("ItemT")
|
|
7
8
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from contextlib import nullcontext
|
|
3
|
+
from contextlib import AbstractContextManager, nullcontext
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, Self
|
|
6
6
|
|
|
7
7
|
from apexdevkit.repository import DatabaseCommand
|
|
8
8
|
|
|
@@ -27,7 +27,7 @@ class FakeConnector:
|
|
|
27
27
|
def fetchall(self) -> list[dict[str, Any]]:
|
|
28
28
|
return self.results.pop() # type: ignore
|
|
29
29
|
|
|
30
|
-
def connect(self) ->
|
|
30
|
+
def connect(self) -> AbstractContextManager[Self]:
|
|
31
31
|
return nullcontext(self)
|
|
32
32
|
|
|
33
33
|
def cursor(self) -> Self:
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import random
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from functools import cached_property
|
|
6
|
-
from typing import Any, Generic,
|
|
6
|
+
from typing import Any, Generic, TypeVar
|
|
7
7
|
|
|
8
8
|
from faker import Faker
|
|
9
9
|
|
|
@@ -70,7 +70,7 @@ class Fake:
|
|
|
70
70
|
|
|
71
71
|
@dataclass(frozen=True)
|
|
72
72
|
class FakeResource(Generic[ItemT]):
|
|
73
|
-
item_type:
|
|
73
|
+
item_type: type[ItemT] = field()
|
|
74
74
|
fake: Fake = field(default_factory=Fake)
|
|
75
75
|
|
|
76
76
|
@cached_property
|
|
@@ -89,7 +89,7 @@ class FakeResource(Generic[ItemT]):
|
|
|
89
89
|
|
|
90
90
|
@dataclass(frozen=True)
|
|
91
91
|
class FakeValue(FakeResource[Value]):
|
|
92
|
-
item_type:
|
|
92
|
+
item_type: type[Value] = field(default=Value)
|
|
93
93
|
|
|
94
94
|
@cached_property
|
|
95
95
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -101,7 +101,7 @@ class FakeValue(FakeResource[Value]):
|
|
|
101
101
|
|
|
102
102
|
@dataclass(frozen=True)
|
|
103
103
|
class FakeNumericValue(FakeResource[NumericValue]):
|
|
104
|
-
item_type:
|
|
104
|
+
item_type: type[NumericValue] = field(default=NumericValue)
|
|
105
105
|
|
|
106
106
|
@cached_property
|
|
107
107
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -113,7 +113,7 @@ class FakeNumericValue(FakeResource[NumericValue]):
|
|
|
113
113
|
|
|
114
114
|
@dataclass(frozen=True)
|
|
115
115
|
class FakeStringValue(FakeResource[StringValue]):
|
|
116
|
-
item_type:
|
|
116
|
+
item_type: type[StringValue] = field(default=StringValue)
|
|
117
117
|
|
|
118
118
|
@cached_property
|
|
119
119
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -124,7 +124,7 @@ class FakeStringValue(FakeResource[StringValue]):
|
|
|
124
124
|
|
|
125
125
|
@dataclass(frozen=True)
|
|
126
126
|
class FakeDateValue(FakeResource[DateValue]):
|
|
127
|
-
item_type:
|
|
127
|
+
item_type: type[DateValue] = field(default=DateValue)
|
|
128
128
|
|
|
129
129
|
@cached_property
|
|
130
130
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -134,7 +134,7 @@ class FakeDateValue(FakeResource[DateValue]):
|
|
|
134
134
|
@dataclass(frozen=True)
|
|
135
135
|
class FakeLeaf(FakeResource[Leaf]):
|
|
136
136
|
values: list[NumericValue | StringValue | DateValue] = field(default_factory=list)
|
|
137
|
-
item_type:
|
|
137
|
+
item_type: type[Leaf] = field(default=Leaf)
|
|
138
138
|
|
|
139
139
|
@cached_property
|
|
140
140
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -147,7 +147,7 @@ class FakeLeaf(FakeResource[Leaf]):
|
|
|
147
147
|
@dataclass(frozen=True)
|
|
148
148
|
class FakeOperator(FakeResource[Operator]):
|
|
149
149
|
operands: list[Operator | Leaf] = field(default_factory=list)
|
|
150
|
-
item_type:
|
|
150
|
+
item_type: type[Operator] = field(default=Operator)
|
|
151
151
|
|
|
152
152
|
@cached_property
|
|
153
153
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -160,7 +160,7 @@ class FakeOperator(FakeResource[Operator]):
|
|
|
160
160
|
@dataclass(frozen=True)
|
|
161
161
|
class FakeSort(FakeResource[Sort]):
|
|
162
162
|
is_descending: bool | None = None
|
|
163
|
-
item_type:
|
|
163
|
+
item_type: type[Sort] = field(default=Sort)
|
|
164
164
|
|
|
165
165
|
@cached_property
|
|
166
166
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -174,7 +174,7 @@ class FakeSort(FakeResource[Sort]):
|
|
|
174
174
|
|
|
175
175
|
@dataclass(frozen=True)
|
|
176
176
|
class FakePage(FakeResource[Page]):
|
|
177
|
-
item_type:
|
|
177
|
+
item_type: type[Page] = field(default=Page)
|
|
178
178
|
|
|
179
179
|
@cached_property
|
|
180
180
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -188,7 +188,7 @@ class FakePage(FakeResource[Page]):
|
|
|
188
188
|
@dataclass(frozen=True)
|
|
189
189
|
class FakeFilter(FakeResource[Filter]):
|
|
190
190
|
args: list[NumericValue | StringValue] = field(default_factory=list)
|
|
191
|
-
item_type:
|
|
191
|
+
item_type: type[Filter] = field(default=Filter)
|
|
192
192
|
|
|
193
193
|
@cached_property
|
|
194
194
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -203,7 +203,7 @@ class FakeQueryOptions(FakeResource[QueryOptions]):
|
|
|
203
203
|
condition: Operator | None = None
|
|
204
204
|
ordering: list[Sort] = field(default_factory=list)
|
|
205
205
|
paging: Page | None = None
|
|
206
|
-
item_type:
|
|
206
|
+
item_type: type[QueryOptions] = field(default=QueryOptions)
|
|
207
207
|
|
|
208
208
|
@cached_property
|
|
209
209
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -217,7 +217,7 @@ class FakeQueryOptions(FakeResource[QueryOptions]):
|
|
|
217
217
|
|
|
218
218
|
@dataclass(frozen=True)
|
|
219
219
|
class FakeAggregationOption(FakeResource[AggregationOption]):
|
|
220
|
-
item_type:
|
|
220
|
+
item_type: type[AggregationOption] = field(default=AggregationOption)
|
|
221
221
|
|
|
222
222
|
@cached_property
|
|
223
223
|
def _raw(self) -> dict[str, Any]:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Iterable
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
from functools import cached_property
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Self
|
|
6
7
|
|
|
7
8
|
from apexdevkit.fastapi.name import RestfulName
|
|
8
9
|
from apexdevkit.fastapi.request import HttpRequest
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
[
|
|
1
|
+
[project]
|
|
2
2
|
name = "apexdevkit"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.23.1"
|
|
4
4
|
description = "Apex Development Tools for python."
|
|
5
|
-
authors = ["Apex Dev <dev@apex.ge>"]
|
|
6
5
|
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Apex Dev", email = "dev@apex.ge" }
|
|
8
|
+
]
|
|
9
|
+
dynamic = ["dependencies"]
|
|
10
|
+
requires-python = ">=3.11"
|
|
7
11
|
|
|
8
12
|
[tool.poetry.dependencies]
|
|
9
|
-
python = "^3.11"
|
|
10
13
|
httpx = "*"
|
|
11
14
|
fastapi = "*"
|
|
12
15
|
uvicorn = "*"
|
|
13
|
-
sentry-sdk = {extras = ["fastapi"], version = "*"}
|
|
16
|
+
sentry-sdk = { extras = ["fastapi"], version = "*" }
|
|
14
17
|
python-dotenv = "*"
|
|
15
18
|
pymssql = "2.3.2"
|
|
16
19
|
|
|
@@ -22,14 +25,12 @@ pytest-cov = "*"
|
|
|
22
25
|
pytest-recording = "*"
|
|
23
26
|
coverage = "*"
|
|
24
27
|
faker = "*"
|
|
25
|
-
mongomock = "*"
|
|
26
28
|
|
|
27
29
|
[tool.poetry.group.lint.dependencies]
|
|
28
30
|
mypy = "*"
|
|
29
31
|
ruff = "*"
|
|
30
32
|
|
|
31
33
|
[tool.mypy]
|
|
32
|
-
python_version = "3.11"
|
|
33
34
|
ignore_missing_imports = true
|
|
34
35
|
strict = true
|
|
35
36
|
exclude = [
|
|
@@ -38,7 +39,6 @@ exclude = [
|
|
|
38
39
|
]
|
|
39
40
|
|
|
40
41
|
[tool.ruff]
|
|
41
|
-
target-version = "py311"
|
|
42
42
|
line-length = 88
|
|
43
43
|
|
|
44
44
|
exclude = [
|
|
@@ -48,10 +48,16 @@ exclude = [
|
|
|
48
48
|
"venv",
|
|
49
49
|
]
|
|
50
50
|
|
|
51
|
-
lint
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
[tool.ruff.lint]
|
|
52
|
+
select = [
|
|
53
|
+
"B", # flake8-bugbear
|
|
54
|
+
"C4", # flake8-comprehensions
|
|
55
|
+
"E", # pycodestyle errors
|
|
56
|
+
"F", # pyflakes
|
|
57
|
+
"I", # isort
|
|
58
|
+
"UP", # pyupgrade
|
|
59
|
+
"W", # pycodestyle warnings
|
|
60
|
+
]
|
|
55
61
|
|
|
56
62
|
[tool.ruff.lint.mccabe]
|
|
57
63
|
max-complexity = 10
|
|
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
|