fast-clean 0.4.0__py3-none-any.whl

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. fast_clean/__init__.py +3 -0
  2. fast_clean/broker.py +123 -0
  3. fast_clean/container.py +235 -0
  4. fast_clean/contrib/__init__.py +3 -0
  5. fast_clean/contrib/healthcheck/__init__.py +3 -0
  6. fast_clean/contrib/healthcheck/router.py +17 -0
  7. fast_clean/db.py +179 -0
  8. fast_clean/depends.py +255 -0
  9. fast_clean/enums.py +39 -0
  10. fast_clean/exceptions.py +281 -0
  11. fast_clean/loggers.py +26 -0
  12. fast_clean/middleware.py +20 -0
  13. fast_clean/models.py +33 -0
  14. fast_clean/py.typed +0 -0
  15. fast_clean/redis.py +23 -0
  16. fast_clean/repositories/__init__.py +30 -0
  17. fast_clean/repositories/cache/__init__.py +83 -0
  18. fast_clean/repositories/cache/in_memory.py +62 -0
  19. fast_clean/repositories/cache/redis.py +58 -0
  20. fast_clean/repositories/crud/__init__.py +149 -0
  21. fast_clean/repositories/crud/db.py +559 -0
  22. fast_clean/repositories/crud/in_memory.py +369 -0
  23. fast_clean/repositories/crud/type_vars.py +35 -0
  24. fast_clean/repositories/settings/__init__.py +52 -0
  25. fast_clean/repositories/settings/enums.py +16 -0
  26. fast_clean/repositories/settings/env.py +55 -0
  27. fast_clean/repositories/settings/exceptions.py +13 -0
  28. fast_clean/repositories/settings/type_vars.py +9 -0
  29. fast_clean/repositories/storage/__init__.py +114 -0
  30. fast_clean/repositories/storage/enums.py +20 -0
  31. fast_clean/repositories/storage/local.py +118 -0
  32. fast_clean/repositories/storage/reader.py +122 -0
  33. fast_clean/repositories/storage/s3.py +118 -0
  34. fast_clean/repositories/storage/schemas.py +31 -0
  35. fast_clean/schemas/__init__.py +25 -0
  36. fast_clean/schemas/exceptions.py +32 -0
  37. fast_clean/schemas/pagination.py +65 -0
  38. fast_clean/schemas/repository.py +43 -0
  39. fast_clean/schemas/request_response.py +36 -0
  40. fast_clean/schemas/status_response.py +13 -0
  41. fast_clean/services/__init__.py +16 -0
  42. fast_clean/services/cryptography/__init__.py +57 -0
  43. fast_clean/services/cryptography/aes.py +120 -0
  44. fast_clean/services/cryptography/enums.py +20 -0
  45. fast_clean/services/lock.py +57 -0
  46. fast_clean/services/seed.py +91 -0
  47. fast_clean/services/transaction.py +40 -0
  48. fast_clean/settings.py +189 -0
  49. fast_clean/tools/__init__.py +6 -0
  50. fast_clean/tools/cryptography.py +56 -0
  51. fast_clean/tools/load_seed.py +31 -0
  52. fast_clean/use_cases.py +38 -0
  53. fast_clean/utils/__init__.py +15 -0
  54. fast_clean/utils/process.py +31 -0
  55. fast_clean/utils/pydantic.py +23 -0
  56. fast_clean/utils/ssl_context.py +31 -0
  57. fast_clean/utils/string.py +28 -0
  58. fast_clean/utils/thread.py +21 -0
  59. fast_clean/utils/time.py +14 -0
  60. fast_clean/utils/type_converters.py +18 -0
  61. fast_clean/utils/typer.py +23 -0
  62. fast_clean-0.4.0.dist-info/METADATA +38 -0
  63. fast_clean-0.4.0.dist-info/RECORD +65 -0
  64. fast_clean-0.4.0.dist-info/WHEEL +5 -0
  65. fast_clean-0.4.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,30 @@
1
+ """
2
+ Пакет, содержащий репозитории.
3
+ """
4
+
5
+ from .cache import CacheManager as CacheManager
6
+ from .cache import CacheRepositoryProtocol as CacheRepositoryProtocol
7
+ from .cache import InMemoryCacheRepository as InMemoryCacheRepository
8
+ from .cache import RedisCacheRepository as RedisCacheRepository
9
+ from .crud import CrudRepositoryOldProtocol as CrudRepositoryOldProtocol
10
+ from .crud import CrudRepositoryProtocol as CrudRepositoryProtocol
11
+ from .crud import DbCrudRepository as DbCrudRepository
12
+ from .crud import DbCrudRepositoryOld as DbCrudRepositoryOld
13
+ from .settings import EnvSettingsRepository as EnvSettingsRepository
14
+ from .settings import SettingsRepositoryError as SettingsRepositoryError
15
+ from .settings import SettingsRepositoryFactoryImpl as SettingsRepositoryFactoryImpl
16
+ from .settings import SettingsRepositoryFactoryProtocol as SettingsRepositoryFactoryProtocol
17
+ from .settings import SettingsRepositoryProtocol as SettingsRepositoryProtocol
18
+ from .settings import SettingsSourceEnum as SettingsSourceEnum
19
+ from .storage import LocalStorageParamsSchema as LocalStorageParamsSchema
20
+ from .storage import LocalStorageRepository as LocalStorageRepository
21
+ from .storage import S3StorageParamsSchema as S3StorageParamsSchema
22
+ from .storage import S3StorageRepository as S3StorageRepository
23
+ from .storage import StorageRepositoryFactoryImpl as StorageRepositoryFactoryImpl
24
+ from .storage import (
25
+ StorageRepositoryFactoryProtocol as StorageRepositoryFactoryProtocol,
26
+ )
27
+ from .storage import StorageRepositoryProtocol as StorageRepositoryProtocol
28
+ from .storage import StorageTypeEnum as StorageTypeEnum
29
+ from .storage import StreamReaderProtocol as StreamReaderProtocol
30
+ from .storage import StreamReadProtocol as StreamReadProtocol
@@ -0,0 +1,83 @@
1
+ """
2
+ Пакет, содержащий репозиторий кеша.
3
+
4
+ Представлено две реализации:
5
+ - InMemory
6
+ - Redis
7
+ """
8
+
9
+ from typing import ClassVar, Protocol, Self, Tuple, cast
10
+
11
+ from fastapi_cache import FastAPICache
12
+
13
+ from fast_clean.settings import CoreCacheSettingsSchema
14
+ from redis import asyncio as aioredis
15
+
16
+ from .in_memory import InMemoryCacheRepository as InMemoryCacheRepository
17
+ from .redis import RedisCacheRepository as RedisCacheRepository
18
+
19
+
20
+ class CacheRepositoryProtocol(Protocol):
21
+ """
22
+ Протокол репозитория кеша.
23
+ """
24
+
25
+ async def get(self: Self, key: str) -> str | None:
26
+ """
27
+ Получаем значение.
28
+ """
29
+ ...
30
+
31
+ async def set(self: Self, key: str, value: str, expire: int | None = None, nx: bool = False) -> None:
32
+ """
33
+ Устанавливаем значение.
34
+ """
35
+ ...
36
+
37
+ async def get_with_ttl(self: Self, key: str) -> Tuple[int, str | None]:
38
+ """
39
+ Получаем значение со сроком жизни.
40
+ """
41
+ ...
42
+
43
+ async def incr(self: Self, key: str, amount: int = 1) -> int:
44
+ """
45
+ Инкрементируем значения.
46
+ """
47
+ ...
48
+
49
+ async def decr(self: Self, key: str, amount: int = 1) -> int:
50
+ """
51
+ Декрементируем значения.
52
+ """
53
+ ...
54
+
55
+ async def clear(self: Self, namespace: str | None = None, key: str | None = None) -> int:
56
+ """
57
+ Удаляем значение.
58
+ """
59
+ ...
60
+
61
+
62
+ class CacheManager:
63
+ """
64
+ Менеджер для реализации кеширования.
65
+ """
66
+
67
+ cache: ClassVar[CacheRepositoryProtocol | None] = None
68
+
69
+ @classmethod
70
+ def init(cls, cache_settings: CoreCacheSettingsSchema, redis: aioredis.Redis | None) -> None:
71
+ """
72
+ Инициализируем кеш.
73
+ """
74
+ if cls.cache is None:
75
+ cache_backend: InMemoryCacheRepository | RedisCacheRepository
76
+ match cache_settings.provider:
77
+ case 'in_memory':
78
+ cache_backend = InMemoryCacheRepository()
79
+ case 'redis':
80
+ assert redis is not None
81
+ cache_backend = RedisCacheRepository(redis)
82
+ FastAPICache.init(cache_backend, prefix=cache_settings.prefix)
83
+ cls.cache = cast(CacheRepositoryProtocol, cache_backend)
@@ -0,0 +1,62 @@
1
+ """
2
+ Модуль, содержащий репозиторий кеша в памяти.
3
+ """
4
+
5
+ from typing import Self
6
+
7
+ from fastapi_cache.backends.inmemory import InMemoryBackend, Value
8
+ from overrides import override
9
+
10
+
11
+ class InMemoryCacheRepository(InMemoryBackend):
12
+ """
13
+ Репозиторий кеша в памяти.
14
+ """
15
+
16
+ @override(check_signature=False)
17
+ def _get(self, key: str) -> Value | None:
18
+ """
19
+ Получаем внутреннее значение.
20
+
21
+ Родительский метод работает неправильно, т.к. не рассчитан на правильную логику метода `set`.
22
+ """
23
+ v = self._store.get(key)
24
+ if v:
25
+ if v.ttl_ts == -1 or v.ttl_ts >= self._now:
26
+ return v
27
+ else:
28
+ del self._store[key]
29
+ return None
30
+
31
+ @override(check_signature=False)
32
+ async def set(self: Self, key: str, value: str, expire: int | None = None, nx: bool = False) -> None:
33
+ """
34
+ Устанавливаем значение.
35
+
36
+ Родительский метод работает неправильно, т.к. при отсутствии `expire` должно устанавливаться `-1`.
37
+ Старая логика приводит к тому, что метод работает не так, как `RedisBackend`.
38
+ """
39
+ async with self._lock:
40
+ ttl_ts = self._now + expire if expire is not None else -1
41
+ existing_value = self._get(key)
42
+ if not nx or existing_value is None:
43
+ self._store[key] = Value(value, ttl_ts) # type: ignore
44
+
45
+ async def incr(self: Self, key: str, amount: int = 1) -> int:
46
+ """
47
+ Инкремент значения.
48
+ """
49
+ v = self._get(key)
50
+ if v is None:
51
+ n_value = amount
52
+ await self.set(key, str(amount))
53
+ return n_value
54
+ n_value = int(v.data) + amount
55
+ await self.set(key, str(n_value))
56
+ return n_value
57
+
58
+ async def decr(self: Self, key: str, amount: int = 1) -> int:
59
+ """
60
+ Декремент значения.
61
+ """
62
+ return await self.incr(key, -amount)
@@ -0,0 +1,58 @@
1
+ """
2
+ Модуль, содержащий репозиторий кеша с помощью Redis.
3
+ """
4
+
5
+ from typing import Self
6
+
7
+ from fastapi_cache.backends.redis import RedisBackend
8
+ from overrides import override
9
+
10
+ from redis.asyncio.client import Redis
11
+
12
+
13
+ class RedisCacheRepository(RedisBackend):
14
+ """
15
+ Репозиторий кеша с помощью Redis.
16
+ """
17
+
18
+ def __init__(self, redis: Redis):
19
+ super().__init__(redis)
20
+ self.redis: Redis
21
+
22
+ @override(check_signature=False)
23
+ async def set(self: Self, key: str, value: str, expire: int | None = None, nx: bool = False) -> None:
24
+ """
25
+ Устанавливаем значение.
26
+ """
27
+ await self.redis.set(key, value, ex=expire, nx=nx)
28
+
29
+ async def incr(self: Self, key: str, amount: int = 1) -> int:
30
+ """
31
+ Инкремент значения.
32
+ """
33
+ return await self.redis.incr(key, amount)
34
+
35
+ async def decr(self: Self, key: str, amount: int = 1) -> int:
36
+ """
37
+ Декремент значения.
38
+ """
39
+ return await self.redis.decr(key, amount)
40
+
41
+ async def clear(self, namespace: str | None = None, key: str | None = None) -> int:
42
+ """
43
+ Удаляем значение.
44
+
45
+ Родительский метод работает не правильно и не подсчитывает количество удаленных записей.
46
+ https://github.com/long2ice/fastapi-cache/issues/241
47
+ """
48
+ if namespace:
49
+ cursor = 0
50
+ removed = 0
51
+ while True:
52
+ cursor, keys = await self.redis.scan(cursor, match=f'{namespace}:*', count=500)
53
+ removed += await self.redis.delete(*keys)
54
+ if cursor == 0:
55
+ return removed
56
+ elif key:
57
+ return await self.redis.delete(key)
58
+ return 0
@@ -0,0 +1,149 @@
1
+ """
2
+ Пакет, содержащий репозиторий для выполнения CRUD операций над моделями.
3
+
4
+ Представлено две реализации:
5
+ - InMemory
6
+ - Db
7
+ """
8
+
9
+ import uuid
10
+ from collections.abc import Iterable, Sequence
11
+ from typing import Any, Protocol, Self
12
+
13
+ from fast_clean.schemas import PaginationResultSchema, PaginationSchema
14
+
15
+ from .db import DbCrudRepository as DbCrudRepository
16
+ from .db import DbCrudRepositoryOld as DbCrudRepositoryOld
17
+ from .in_memory import InMemoryCrudRepository as InMemoryCrudRepository
18
+ from .in_memory import InMemoryCrudRepositoryOld as InMemoryCrudRepositoryOld
19
+ from .type_vars import (
20
+ CreateSchemaBaseType,
21
+ CreateSchemaOldType,
22
+ CreateSchemaType,
23
+ IdTypeContravariant,
24
+ ReadSchemaBaseType,
25
+ UpdateSchemaBaseType,
26
+ UpdateSchemaOldType,
27
+ UpdateSchemaType,
28
+ )
29
+
30
+
31
+ class CrudRepositoryBaseProtocol(
32
+ Protocol[
33
+ ReadSchemaBaseType,
34
+ CreateSchemaBaseType,
35
+ UpdateSchemaBaseType,
36
+ IdTypeContravariant,
37
+ ]
38
+ ):
39
+ """
40
+ Протокол базового репозитория для выполнения CRUD операций над моделями.
41
+ """
42
+
43
+ async def get(self: Self, id: IdTypeContravariant) -> ReadSchemaBaseType:
44
+ """
45
+ Получаем модель по идентификатору.
46
+ """
47
+ ...
48
+
49
+ async def get_or_none(self: Self, id: IdTypeContravariant) -> ReadSchemaBaseType | None:
50
+ """
51
+ Получаем модель или None по идентификатору.
52
+ """
53
+ ...
54
+
55
+ async def get_by_ids(
56
+ self: Self, ids: Sequence[IdTypeContravariant], *, exact: bool = False
57
+ ) -> list[ReadSchemaBaseType]:
58
+ """
59
+ Получаем список моделей по идентификаторам.
60
+ """
61
+ ...
62
+
63
+ async def get_all(self: Self) -> list[ReadSchemaBaseType]:
64
+ """
65
+ Получаем все модели.
66
+ """
67
+ ...
68
+
69
+ async def paginate(
70
+ self: Self,
71
+ pagination: PaginationSchema,
72
+ user: Any,
73
+ policies: list[str],
74
+ *,
75
+ search: str | None = None,
76
+ search_by: Iterable[str] | None = None,
77
+ sorting: Iterable[str] | None = None,
78
+ ) -> PaginationResultSchema[ReadSchemaBaseType]:
79
+ """
80
+ Получаем список моделей с пагинацией, поиском и сортировкой.
81
+ """
82
+ ...
83
+
84
+ async def create(self: Self, create_object: CreateSchemaBaseType) -> ReadSchemaBaseType:
85
+ """
86
+ Создаем модель.
87
+ """
88
+ ...
89
+
90
+ async def bulk_create(self: Self, create_objects: list[CreateSchemaBaseType]) -> list[ReadSchemaBaseType]:
91
+ """
92
+ Создаем несколько моделей.
93
+ """
94
+ ...
95
+
96
+ async def update(self: Self, update_object: UpdateSchemaBaseType) -> ReadSchemaBaseType:
97
+ """
98
+ Обновляем модель.
99
+ """
100
+ ...
101
+
102
+ async def bulk_update(self: Self, update_objects: list[UpdateSchemaBaseType]) -> None:
103
+ """
104
+ Обновляем несколько моделей.
105
+ """
106
+ ...
107
+
108
+ async def upsert(self: Self, create_object: CreateSchemaBaseType) -> ReadSchemaBaseType:
109
+ """
110
+ Создаем или обновляем модель.
111
+ """
112
+ ...
113
+
114
+ async def delete(self: Self, ids: Sequence[IdTypeContravariant]) -> None:
115
+ """
116
+ Удаляем модели.
117
+ """
118
+ ...
119
+
120
+
121
+ class CrudRepositoryOldProtocol(
122
+ CrudRepositoryBaseProtocol[
123
+ ReadSchemaBaseType,
124
+ CreateSchemaOldType,
125
+ UpdateSchemaOldType,
126
+ int,
127
+ ],
128
+ Protocol[
129
+ ReadSchemaBaseType,
130
+ CreateSchemaOldType,
131
+ UpdateSchemaOldType,
132
+ ],
133
+ ):
134
+ """
135
+ Протокол репозитория для выполнения CRUD операций над моделями старого типа.
136
+ """
137
+
138
+ ...
139
+
140
+
141
+ class CrudRepositoryProtocol(
142
+ CrudRepositoryBaseProtocol[ReadSchemaBaseType, CreateSchemaType, UpdateSchemaType, uuid.UUID],
143
+ Protocol[ReadSchemaBaseType, CreateSchemaType, UpdateSchemaType],
144
+ ):
145
+ """
146
+ Протокол репозитория для выполнения CRUD операций над моделями нового типа.
147
+ """
148
+
149
+ ...