apexdevkit 1.30.4__tar.gz → 1.32.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.
Files changed (65) hide show
  1. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/PKG-INFO +3 -4
  2. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/__init__.py +3 -0
  3. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/resource.py +1 -1
  4. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/router.py +34 -1
  5. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/key_fn.py +3 -0
  6. apexdevkit-1.32.1/apexdevkit/sync/__init__.py +19 -0
  7. apexdevkit-1.32.1/apexdevkit/sync/observer.py +89 -0
  8. apexdevkit-1.32.1/apexdevkit/sync/source.py +122 -0
  9. apexdevkit-1.32.1/apexdevkit/sync/sync.py +78 -0
  10. apexdevkit-1.32.1/apexdevkit/sync/target.py +82 -0
  11. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/pyproject.toml +13 -13
  12. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/LICENSE +0 -0
  13. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/README.md +0 -0
  14. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/__init__.py +0 -0
  15. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/annotation/__init__.py +0 -0
  16. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/annotation/deprecate.py +0 -0
  17. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/date.py +0 -0
  18. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/environment.py +0 -0
  19. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/error.py +0 -0
  20. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/builder.py +0 -0
  21. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/dependable.py +0 -0
  22. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/docs.py +0 -0
  23. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/name.py +0 -0
  24. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/response.py +0 -0
  25. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/schema.py +0 -0
  26. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fastapi/service.py +0 -0
  27. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/fluent.py +0 -0
  28. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/formatter.py +0 -0
  29. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/http/__init__.py +0 -0
  30. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/http/fake.py +0 -0
  31. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/http/fluent.py +0 -0
  32. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/http/httpx/__init__.py +0 -0
  33. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/http/httpx/client.py +0 -0
  34. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/http/httpx/hooks.py +0 -0
  35. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/http/json.py +0 -0
  36. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/http/url.py +0 -0
  37. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/py.typed +0 -0
  38. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/query/__init__.py +0 -0
  39. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/query/generator.py +0 -0
  40. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/query/query.py +0 -0
  41. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/__init__.py +0 -0
  42. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/core/__init__.py +0 -0
  43. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/core/database.py +0 -0
  44. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/core/decorator.py +0 -0
  45. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/core/interface.py +0 -0
  46. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/core/mixin.py +0 -0
  47. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/core/multi.py +0 -0
  48. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/in_memory/__init__.py +0 -0
  49. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/in_memory/mixin.py +0 -0
  50. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/in_memory/repository.py +0 -0
  51. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/in_memory/store.py +0 -0
  52. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/sql/__init__.py +0 -0
  53. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/sql/connector.py +0 -0
  54. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/sql/field.py +0 -0
  55. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/sql/mssql.py +0 -0
  56. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/repository/sql/sqlite.py +0 -0
  57. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/security/__init__.py +0 -0
  58. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/security/core.py +0 -0
  59. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/security/hashing.py +0 -0
  60. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/server.py +0 -0
  61. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/testing/__init__.py +0 -0
  62. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/testing/database.py +0 -0
  63. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/testing/fake.py +0 -0
  64. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/testing/rest.py +0 -0
  65. {apexdevkit-1.30.4 → apexdevkit-1.32.1}/apexdevkit/value.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apexdevkit
3
- Version: 1.30.4
3
+ Version: 1.32.1
4
4
  Summary: Apex Development Tools for python.
5
5
  License-File: LICENSE
6
6
  Author: Apex Dev
7
7
  Author-email: dev@apex.ge
8
- Requires-Python: >=3.11
8
+ Requires-Python: >=3.11,<4
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
@@ -13,11 +13,10 @@ Classifier: Programming Language :: Python :: 3.13
13
13
  Classifier: Programming Language :: Python :: 3.14
14
14
  Requires-Dist: fastapi
15
15
  Requires-Dist: httpx
16
+ Requires-Dist: pydantic
16
17
  Requires-Dist: pymssql (==2.*)
17
18
  Requires-Dist: python-dotenv
18
19
  Requires-Dist: sentry-sdk[fastapi]
19
- Requires-Dist: tomlkit
20
- Requires-Dist: typer
21
20
  Requires-Dist: uvicorn
22
21
  Description-Content-Type: text/markdown
23
22
 
@@ -1,5 +1,6 @@
1
1
  from apexdevkit.fastapi.builder import FastApiBuilder, RestfulServiceBuilder
2
2
  from apexdevkit.fastapi.dependable import inject
3
+ from apexdevkit.fastapi.router import RestfulRouter, RouterWithHiddenUnderscoreRoutes
3
4
  from apexdevkit.fastapi.service import RestfulRepository
4
5
 
5
6
  __all__ = [
@@ -7,4 +8,6 @@ __all__ = [
7
8
  "RestfulServiceBuilder",
8
9
  "inject",
9
10
  "RestfulRepository",
11
+ "RestfulRouter",
12
+ "RouterWithHiddenUnderscoreRoutes",
10
13
  ]
@@ -3,8 +3,8 @@ from collections.abc import Callable
3
3
  from dataclasses import dataclass
4
4
  from typing import Any, Union
5
5
 
6
+ from fastapi.responses import JSONResponse
6
7
  from pydantic import BaseModel
7
- from starlette.responses import JSONResponse
8
8
 
9
9
  from apexdevkit.error import DoesNotExistError, ExistsError, ForbiddenError
10
10
  from apexdevkit.fastapi.response import RestfulResponse
@@ -1,3 +1,4 @@
1
+ from collections.abc import Callable
1
2
  from dataclasses import dataclass, field
2
3
  from enum import Enum
3
4
  from typing import Annotated, Any, Protocol, Self, TypeVar
@@ -12,6 +13,38 @@ from apexdevkit.fastapi.schema import RestfulSchema, Schema, SchemaFields
12
13
  from apexdevkit.fastapi.service import RawCollection, RawItem, RestfulService
13
14
  from apexdevkit.fluent import FluentDict
14
15
 
16
+
17
+ class RouterWithHiddenUnderscoreRoutes(APIRouter):
18
+ def add_api_route(
19
+ self,
20
+ path: str,
21
+ endpoint: Callable[..., Any],
22
+ **kwargs: Any,
23
+ ) -> None:
24
+ super().add_api_route(path, endpoint, **kwargs)
25
+ self._add_underscored_api_route(path, endpoint, kwargs.copy())
26
+
27
+ def _add_underscored_api_route(
28
+ self,
29
+ path: str,
30
+ endpoint: Callable[..., Any],
31
+ kwargs: dict[str, Any],
32
+ ) -> None:
33
+ if "-" not in path:
34
+ return
35
+
36
+ op_id = kwargs.get("operation_id", endpoint.__name__) or endpoint.__name__
37
+ kwargs["operation_id"] = f"{op_id}_alias"
38
+ kwargs["include_in_schema"] = False
39
+
40
+ # Register the underscored route pointing to the same endpoint
41
+ super().add_api_route(
42
+ path=path.replace("-", "_"),
43
+ endpoint=endpoint,
44
+ **kwargs,
45
+ )
46
+
47
+
15
48
  _Response = JSONResponse | dict[str, Any]
16
49
 
17
50
  T = TypeVar("T")
@@ -27,7 +60,7 @@ class RestfulRouter:
27
60
  name: RestfulName
28
61
 
29
62
  parent: RestfulName | None = None
30
- router: APIRouter = field(default_factory=APIRouter)
63
+ router: APIRouter = field(default_factory=RouterWithHiddenUnderscoreRoutes)
31
64
 
32
65
  _schema: RestfulSchema = field(init=False)
33
66
  _dependency: Dependency | None = field(init=False, default=None)
@@ -1,8 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Callable
3
4
  from dataclasses import dataclass
4
5
  from typing import Any
5
6
 
7
+ KeyFn = Callable[[Any], str]
8
+
6
9
 
7
10
  @dataclass(frozen=True)
8
11
  class AttributeKey:
@@ -0,0 +1,19 @@
1
+ from .observer import SyncObserver
2
+ from .source import EmptySource, Source, SourceDecorator, SourceFailing, SourcePreSet
3
+ from .sync import Sync, SyncProbe
4
+ from .target import NoTarget, Target, TargetDecorator, TargetFailing
5
+
6
+ __all__ = [
7
+ "Sync",
8
+ "SyncObserver",
9
+ "SyncProbe",
10
+ "EmptySource",
11
+ "Source",
12
+ "SourceDecorator",
13
+ "SourceFailing",
14
+ "SourcePreSet",
15
+ "NoTarget",
16
+ "Target",
17
+ "TargetDecorator",
18
+ "TargetFailing",
19
+ ]
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from dataclasses import dataclass, field
5
+ from typing import Protocol, Self
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class ObservableSync:
10
+ observers: list[SyncObserver] = field(default_factory=list)
11
+
12
+ def attach(self, observer: SyncObserver, when: bool = True) -> Self:
13
+ if when:
14
+ self.observers.append(observer)
15
+
16
+ return self
17
+
18
+ def before_prune(self, n_items: int) -> None:
19
+ for observer in self.observers:
20
+ observer.before_prune(n_items)
21
+
22
+ def after_prune(self, n_items: int) -> None:
23
+ _ = n_items
24
+
25
+ for observer in self.observers:
26
+ observer.after_prune()
27
+
28
+ def before_load(self, n_items: int) -> None:
29
+ for observer in self.observers:
30
+ observer.before_load(n_items)
31
+
32
+ def after_load(self, n_items: int) -> None:
33
+ _ = n_items
34
+
35
+ for observer in self.observers:
36
+ observer.after_load()
37
+
38
+ def before_update(self, n_items: int) -> None:
39
+ for observer in self.observers:
40
+ observer.before_update(n_items)
41
+
42
+ def after_update(self, n_items: int) -> None:
43
+ _ = n_items
44
+
45
+ for observer in self.observers:
46
+ observer.after_update()
47
+
48
+
49
+ class SyncObserver(Protocol): # pragma: no cover
50
+ def before_prune(self, n_items: int) -> None:
51
+ pass
52
+
53
+ def after_prune(self) -> None:
54
+ pass
55
+
56
+ def before_load(self, n_items: int) -> None:
57
+ pass
58
+
59
+ def after_load(self) -> None:
60
+ pass
61
+
62
+ def before_update(self, n_items: int) -> None:
63
+ pass
64
+
65
+ def after_update(self) -> None:
66
+ pass
67
+
68
+
69
+ @dataclass(frozen=True)
70
+ class DefaultLog:
71
+ echo: Callable[[str], None] = print
72
+
73
+ def before_prune(self, n_items: int) -> None:
74
+ self.echo(f"Total # of absent items: {n_items}")
75
+
76
+ def after_prune(self) -> None:
77
+ self.echo("Pruning completed")
78
+
79
+ def before_load(self, n_items: int) -> None:
80
+ self.echo(f"Total # of new items: {n_items}")
81
+
82
+ def after_load(self) -> None:
83
+ self.echo("Loading completed")
84
+
85
+ def before_update(self, n_items: int) -> None:
86
+ self.echo(f"Total # of updates: {n_items}")
87
+
88
+ def after_update(self) -> None:
89
+ self.echo("Updating completed")
@@ -0,0 +1,122 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable
4
+ from dataclasses import dataclass, field
5
+ from typing import Generic, Protocol, TypeVar
6
+
7
+ from apexdevkit.key_fn import AttributeKey, KeyFn
8
+
9
+ T = TypeVar("T")
10
+
11
+
12
+ class Source(Protocol): # pragma: no cover
13
+ def absent(self) -> Iterable[T]:
14
+ pass
15
+
16
+ def new(self) -> Iterable[T]:
17
+ pass
18
+
19
+ def updates(self) -> Iterable[T]:
20
+ pass
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class EmptySource: # pragma: no cover
25
+ def absent(self) -> Iterable[T]:
26
+ return []
27
+
28
+ def new(self) -> Iterable[T]:
29
+ return []
30
+
31
+ def updates(self) -> Iterable[T]:
32
+ return []
33
+
34
+
35
+ @dataclass(frozen=True, kw_only=True)
36
+ class SourceDecorator: # pragma: no cover
37
+ inner: Source = field(default_factory=EmptySource)
38
+
39
+ def absent(self) -> Iterable[T]:
40
+ return self.inner.absent()
41
+
42
+ def new(self) -> Iterable[T]:
43
+ return self.inner.new()
44
+
45
+ def updates(self) -> Iterable[T]:
46
+ return self.inner.updates()
47
+
48
+
49
+ @dataclass(frozen=True, kw_only=True)
50
+ class SourcePreSet(Generic[T]):
51
+ removals: Iterable[T]
52
+ additions: Iterable[T]
53
+ changes: Iterable[T]
54
+
55
+ def absent(self) -> Iterable[T]:
56
+ return self.removals
57
+
58
+ def new(self) -> Iterable[T]:
59
+ return self.additions
60
+
61
+ def updates(self) -> Iterable[T]:
62
+ return self.changes
63
+
64
+
65
+ class SourceFailing:
66
+ @staticmethod
67
+ def on_everything(using: Source | None = None) -> Source:
68
+ return SourceFailing.on_absent(
69
+ using=SourceFailing.on_new(
70
+ using=SourceFailing.on_update(
71
+ using=using or EmptySource(),
72
+ ),
73
+ ),
74
+ )
75
+
76
+ @staticmethod
77
+ def on_absent(using: Source | None = None) -> Source:
78
+ return SourceFailing.OnAbsent(inner=using or EmptySource())
79
+
80
+ @dataclass(frozen=True, kw_only=True)
81
+ class OnAbsent(SourceDecorator):
82
+ def absent(self) -> Iterable[T]: # pragma: no cover
83
+ raise RuntimeError("Should not request absent!")
84
+
85
+ @staticmethod
86
+ def on_new(using: Source | None = None) -> Source:
87
+ return SourceFailing.OnNew(inner=using or EmptySource())
88
+
89
+ @dataclass(frozen=True, kw_only=True)
90
+ class OnNew(SourceDecorator):
91
+ def new(self) -> Iterable[T]: # pragma: no cover
92
+ raise RuntimeError("Should not request new!")
93
+
94
+ @staticmethod
95
+ def on_update(using: Source | None = None) -> Source:
96
+ return SourceFailing.OnUpdate(inner=using or EmptySource())
97
+
98
+ @dataclass(frozen=True, kw_only=True)
99
+ class OnUpdate(SourceDecorator):
100
+ def updates(self) -> Iterable[T]: # pragma: no cover
101
+ raise RuntimeError("Should not request updates!")
102
+
103
+
104
+ @dataclass(frozen=True, kw_only=True)
105
+ class SourceDiscriminator(Generic[T]):
106
+ current: Iterable[T]
107
+ latest: Iterable[T]
108
+
109
+ key_fn: KeyFn = AttributeKey("id")
110
+
111
+ def absent(self) -> Iterable[T]:
112
+ index = {self.key_fn(item) for item in self.latest}
113
+
114
+ return [item for item in self.current if self.key_fn(item) not in index]
115
+
116
+ def new(self) -> Iterable[T]:
117
+ index = {self.key_fn(item) for item in self.current}
118
+
119
+ return [item for item in self.latest if self.key_fn(item) not in index]
120
+
121
+ def updates(self) -> Iterable[T]:
122
+ return set(self.latest).difference(self.current)
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable, Collection, Iterable
4
+ from dataclasses import dataclass
5
+ from typing import Any, Self
6
+
7
+ from .observer import DefaultLog, ObservableSync
8
+ from .source import Source
9
+ from .target import Target
10
+
11
+
12
+ @dataclass(frozen=True, kw_only=True)
13
+ class Sync(ObservableSync):
14
+ source: Source
15
+ target: Target
16
+
17
+ dry_run: bool = False
18
+
19
+ def with_log(self, using: Callable[[str], None]) -> Self:
20
+ return self.attach(DefaultLog(echo=using))
21
+
22
+ def run(self, prune: bool = True, load: bool = True, update: bool = True) -> None:
23
+ if prune:
24
+ self.prune()
25
+
26
+ if load:
27
+ self.load()
28
+
29
+ if update:
30
+ self.update()
31
+
32
+ def prune(self) -> None:
33
+ (
34
+ SyncProbe(source=set(self.source.absent()))
35
+ .disable(when=self.dry_run)
36
+ .notify(using=self.before_prune)
37
+ .send(using=self.target.prune)
38
+ .notify(using=self.after_prune)
39
+ )
40
+
41
+ def load(self) -> None:
42
+ (
43
+ SyncProbe(source=set(self.source.new()))
44
+ .disable(when=self.dry_run)
45
+ .notify(using=self.before_load)
46
+ .send(using=self.target.load)
47
+ .notify(using=self.after_load)
48
+ )
49
+
50
+ def update(self) -> None:
51
+ (
52
+ SyncProbe(source=set(self.source.updates()))
53
+ .disable(when=self.dry_run)
54
+ .notify(using=self.before_update)
55
+ .send(using=self.target.renew)
56
+ .notify(using=self.after_update)
57
+ )
58
+
59
+
60
+ @dataclass(frozen=True, kw_only=True)
61
+ class SyncProbe:
62
+ source: Collection[Any]
63
+
64
+ is_enabled: bool = True
65
+
66
+ def disable(self, when: bool) -> SyncProbe:
67
+ return SyncProbe(source=self.source, is_enabled=not when)
68
+
69
+ def notify(self, using: Callable[[int], None]) -> SyncProbe:
70
+ using(len(self.source))
71
+
72
+ return self
73
+
74
+ def send(self, using: Callable[[Iterable[Any]], None]) -> SyncProbe:
75
+ if self.is_enabled and len(self.source) > 0:
76
+ using(self.source)
77
+
78
+ return self
@@ -0,0 +1,82 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable
4
+ from dataclasses import dataclass, field
5
+ from typing import Protocol, TypeVar
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ class Target(Protocol): # pragma: no cover
11
+ def prune(self, source: Iterable[T]) -> None:
12
+ pass
13
+
14
+ def load(self, source: Iterable[T]) -> None:
15
+ pass
16
+
17
+ def renew(self, source: Iterable[T]) -> None:
18
+ pass
19
+
20
+
21
+ class NoTarget: # pragma: no cover
22
+ def prune(self, source: Iterable[T]) -> None:
23
+ pass
24
+
25
+ def load(self, source: Iterable[T]) -> None:
26
+ pass
27
+
28
+ def renew(self, source: Iterable[T]) -> None:
29
+ pass
30
+
31
+
32
+ @dataclass(frozen=True, kw_only=True)
33
+ class TargetDecorator:
34
+ inner: Target = field(default_factory=NoTarget)
35
+
36
+ def prune(self, source: Iterable[T]) -> None:
37
+ self.inner.prune(source)
38
+
39
+ def load(self, source: Iterable[T]) -> None:
40
+ self.inner.load(source)
41
+
42
+ def renew(self, source: Iterable[T]) -> None:
43
+ self.inner.renew(source)
44
+
45
+
46
+ class TargetFailing:
47
+ @staticmethod
48
+ def on_everything(using: Target | None = None) -> Target:
49
+ return TargetFailing.on_prune(
50
+ using=TargetFailing.on_load(
51
+ using=TargetFailing.on_update(
52
+ using=using or NoTarget(),
53
+ ),
54
+ ),
55
+ )
56
+
57
+ @staticmethod
58
+ def on_prune(using: Target | None = None) -> Target:
59
+ return TargetFailing.OnPrune(inner=using or NoTarget())
60
+
61
+ @dataclass(frozen=True, kw_only=True)
62
+ class OnPrune(TargetDecorator):
63
+ def prune(self, source: Iterable[T]) -> None: # pragma: no cover
64
+ raise RuntimeError(source)
65
+
66
+ @staticmethod
67
+ def on_load(using: Target | None = None) -> Target:
68
+ return TargetFailing.OnLoad(inner=using or NoTarget())
69
+
70
+ @dataclass(frozen=True, kw_only=True)
71
+ class OnLoad(TargetDecorator):
72
+ def load(self, source: Iterable[T]) -> None: # pragma: no cover
73
+ raise RuntimeError(source)
74
+
75
+ @staticmethod
76
+ def on_update(using: Target | None = None) -> Target:
77
+ return TargetFailing.OnUpdate(inner=using or NoTarget())
78
+
79
+ @dataclass(frozen=True, kw_only=True)
80
+ class OnUpdate(TargetDecorator):
81
+ def renew(self, source: Iterable[T]) -> None: # pragma: no cover
82
+ raise RuntimeError(source)
@@ -1,38 +1,33 @@
1
1
  [project]
2
2
  name = "apexdevkit"
3
- version = "1.30.4"
3
+ version = "1.32.1"
4
4
  description = "Apex Development Tools for python."
5
5
  readme = "README.md"
6
6
  authors = [
7
7
  { name = "Apex Dev", email = "dev@apex.ge" }
8
8
  ]
9
9
  dynamic = ["dependencies"]
10
- requires-python = ">=3.11"
10
+ requires-python = ">=3.11,<4"
11
11
 
12
12
  [tool.poetry.dependencies]
13
- httpx = "*"
14
13
  fastapi = "*"
15
- uvicorn = "*"
16
- sentry-sdk = { extras = ["fastapi"], version = "*" }
14
+ httpx = "*"
17
15
  python-dotenv = "*"
18
16
  pymssql = "2.*"
19
- typer = "*"
20
- tomlkit = "*"
17
+ pydantic = "*"
18
+ sentry-sdk = { extras = ["fastapi"], version = "*" }
19
+ uvicorn = "*"
21
20
 
22
21
  [tool.poetry.group.dev.dependencies]
23
- approvaltests = "*"
22
+ apexcodexpy = "0.6.5"
24
23
  pytest = "*"
25
24
  pytest-approvaltests = "*"
26
25
  pytest-cov = "*"
27
- pytest-env = "^1.6.0"
26
+ pytest-env = "*"
28
27
  pytest-recording = "*"
29
28
  coverage = "*"
30
29
  faker = "*"
31
30
 
32
-
33
- [tool.poetry.group.lint.dependencies]
34
- apexcodexpy = "0.4.1"
35
-
36
31
  [tool.mypy]
37
32
  ignore_missing_imports = true
38
33
  strict = true
@@ -43,6 +38,11 @@ exclude = [
43
38
  show_error_codes = true
44
39
  pretty = true
45
40
 
41
+ [tool.deptry]
42
+ extend_exclude = [
43
+ "apexdevkit/testing",
44
+ ]
45
+
46
46
  [tool.ruff.lint]
47
47
  select = [
48
48
  "A",
File without changes
File without changes